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 ClutterActorBox content_box;
709 ClutterContentGravity content_gravity;
710 ClutterScalingFilter min_filter;
711 ClutterScalingFilter mag_filter;
713 /* used when painting, to update the paint volume */
714 ClutterEffect *current_effect;
716 /* This is used to store an effect which needs to be redrawn. A
717 redraw can be queued to start from a particular effect. This is
718 used by parametrised effects that can cache an image of the
719 actor. If a parameter of the effect changes then it only needs to
720 redraw the cached image, not the actual actor. The pointer is
721 only valid if is_dirty == TRUE. If the pointer is NULL then the
722 whole actor is dirty. */
723 ClutterEffect *effect_to_redraw;
725 /* This is used when painting effects to implement the
726 clutter_actor_continue_paint() function. It points to the node in
727 the list of effects that is next in the chain */
728 const GList *next_effect_to_paint;
730 ClutterPaintVolume paint_volume;
732 /* NB: This volume isn't relative to this actor, it is in eye
733 * coordinates so that it can remain valid after the actor changes.
735 ClutterPaintVolume last_paint_volume;
737 ClutterStageQueueRedrawEntry *queue_redraw_entry;
739 ClutterColor bg_color;
743 /* fixed position and sizes */
744 guint position_set : 1;
745 guint min_width_set : 1;
746 guint min_height_set : 1;
747 guint natural_width_set : 1;
748 guint natural_height_set : 1;
749 /* cached request is invalid (implies allocation is too) */
750 guint needs_width_request : 1;
751 /* cached request is invalid (implies allocation is too) */
752 guint needs_height_request : 1;
753 /* cached allocation is invalid (request has changed, probably) */
754 guint needs_allocation : 1;
755 guint show_on_set_parent : 1;
757 guint clip_to_allocation : 1;
758 guint enable_model_view_transform : 1;
759 guint enable_paint_unmapped : 1;
760 guint has_pointer : 1;
761 guint propagated_one_redraw : 1;
762 guint paint_volume_valid : 1;
763 guint last_paint_volume_valid : 1;
764 guint in_clone_paint : 1;
765 guint transform_valid : 1;
766 /* This is TRUE if anything has queued a redraw since we were last
767 painted. In this case effect_to_redraw will point to an effect
768 the redraw was queued from or it will be NULL if the redraw was
769 queued without an effect. */
771 guint bg_color_set : 1;
772 guint content_box_valid : 1;
781 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
782 * when set they force a size request, when gotten they
783 * get the allocation if the allocation is valid, and the
794 /* Then the rest of these size-related properties are the "actual"
795 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
800 PROP_FIXED_POSITION_SET,
809 PROP_NATURAL_WIDTH_SET,
812 PROP_NATURAL_HEIGHT_SET,
816 /* Allocation properties are read-only */
823 PROP_CLIP_TO_ALLOCATION,
827 PROP_OFFSCREEN_REDIRECT,
840 PROP_ROTATION_ANGLE_X,
841 PROP_ROTATION_ANGLE_Y,
842 PROP_ROTATION_ANGLE_Z,
843 PROP_ROTATION_CENTER_X,
844 PROP_ROTATION_CENTER_Y,
845 PROP_ROTATION_CENTER_Z,
846 /* This property only makes sense for the z rotation because the
847 others would depend on the actor having a size along the
849 PROP_ROTATION_CENTER_Z_GRAVITY,
855 PROP_SHOW_ON_SET_PARENT,
873 PROP_BACKGROUND_COLOR,
874 PROP_BACKGROUND_COLOR_SET,
880 PROP_CONTENT_GRAVITY,
882 PROP_MINIFICATION_FILTER,
883 PROP_MAGNIFICATION_FILTER,
888 static GParamSpec *obj_props[PROP_LAST];
907 BUTTON_RELEASE_EVENT,
915 TRANSITIONS_COMPLETED,
920 static guint actor_signals[LAST_SIGNAL] = { 0, };
922 static void clutter_container_iface_init (ClutterContainerIface *iface);
923 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
924 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
925 static void atk_implementor_iface_init (AtkImplementorIface *iface);
927 /* These setters are all static for now, maybe they should be in the
928 * public API, but they are perhaps obscure enough to leave only as
931 static void clutter_actor_set_min_width (ClutterActor *self,
933 static void clutter_actor_set_min_height (ClutterActor *self,
935 static void clutter_actor_set_natural_width (ClutterActor *self,
936 gfloat natural_width);
937 static void clutter_actor_set_natural_height (ClutterActor *self,
938 gfloat natural_height);
939 static void clutter_actor_set_min_width_set (ClutterActor *self,
940 gboolean use_min_width);
941 static void clutter_actor_set_min_height_set (ClutterActor *self,
942 gboolean use_min_height);
943 static void clutter_actor_set_natural_width_set (ClutterActor *self,
944 gboolean use_natural_width);
945 static void clutter_actor_set_natural_height_set (ClutterActor *self,
946 gboolean use_natural_height);
947 static void clutter_actor_update_map_state (ClutterActor *self,
948 MapStateChange change);
949 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
951 /* Helper routines for managing anchor coords */
952 static void clutter_anchor_coord_get_units (ClutterActor *self,
953 const AnchorCoord *coord,
957 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
962 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
963 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
964 ClutterGravity gravity);
966 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
968 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
970 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
971 ClutterActor *ancestor,
974 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
976 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
978 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
979 const ClutterColor *color);
981 static void on_layout_manager_changed (ClutterLayoutManager *manager,
984 /* Helper macro which translates by the anchor coord, applies the
985 given transformation and then translates back */
986 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
987 gfloat _tx, _ty, _tz; \
988 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
989 cogl_matrix_translate ((m), _tx, _ty, _tz); \
991 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
993 static GQuark quark_shader_data = 0;
994 static GQuark quark_actor_layout_info = 0;
995 static GQuark quark_actor_transform_info = 0;
996 static GQuark quark_actor_animation_info = 0;
998 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1000 G_TYPE_INITIALLY_UNOWNED,
1001 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1002 clutter_container_iface_init)
1003 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1004 clutter_scriptable_iface_init)
1005 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1006 clutter_animatable_iface_init)
1007 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1008 atk_implementor_iface_init));
1011 * clutter_actor_get_debug_name:
1012 * @actor: a #ClutterActor
1014 * Retrieves a printable name of @actor for debugging messages
1016 * Return value: a string with a printable name
1019 _clutter_actor_get_debug_name (ClutterActor *actor)
1021 return actor->priv->name != NULL ? actor->priv->name
1022 : G_OBJECT_TYPE_NAME (actor);
1025 #ifdef CLUTTER_ENABLE_DEBUG
1026 /* XXX - this is for debugging only, remove once working (or leave
1027 * in only in some debug mode). Should leave it for a little while
1028 * until we're confident in the new map/realize/visible handling.
1031 clutter_actor_verify_map_state (ClutterActor *self)
1033 ClutterActorPrivate *priv = self->priv;
1035 if (CLUTTER_ACTOR_IS_REALIZED (self))
1037 /* all bets are off during reparent when we're potentially realized,
1038 * but should not be according to invariants
1040 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1042 if (priv->parent == NULL)
1044 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1048 g_warning ("Realized non-toplevel actor '%s' should "
1050 _clutter_actor_get_debug_name (self));
1052 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1054 g_warning ("Realized actor %s has an unrealized parent %s",
1055 _clutter_actor_get_debug_name (self),
1056 _clutter_actor_get_debug_name (priv->parent));
1061 if (CLUTTER_ACTOR_IS_MAPPED (self))
1063 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1064 g_warning ("Actor '%s' is mapped but not realized",
1065 _clutter_actor_get_debug_name (self));
1067 /* remaining bets are off during reparent when we're potentially
1068 * mapped, but should not be according to invariants
1070 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1072 if (priv->parent == NULL)
1074 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1076 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1077 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1079 g_warning ("Toplevel actor '%s' is mapped "
1081 _clutter_actor_get_debug_name (self));
1086 g_warning ("Mapped actor '%s' should have a parent",
1087 _clutter_actor_get_debug_name (self));
1092 ClutterActor *iter = self;
1094 /* check for the enable_paint_unmapped flag on the actor
1095 * and parents; if the flag is enabled at any point of this
1096 * branch of the scene graph then all the later checks
1099 while (iter != NULL)
1101 if (iter->priv->enable_paint_unmapped)
1104 iter = iter->priv->parent;
1107 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1109 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1111 _clutter_actor_get_debug_name (self),
1112 _clutter_actor_get_debug_name (priv->parent));
1115 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1117 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1119 _clutter_actor_get_debug_name (self),
1120 _clutter_actor_get_debug_name (priv->parent));
1123 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1125 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1126 g_warning ("Actor '%s' is mapped but its non-toplevel "
1127 "parent '%s' is not mapped",
1128 _clutter_actor_get_debug_name (self),
1129 _clutter_actor_get_debug_name (priv->parent));
1136 #endif /* CLUTTER_ENABLE_DEBUG */
1139 clutter_actor_set_mapped (ClutterActor *self,
1142 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1147 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1148 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1152 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1153 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1157 /* this function updates the mapped and realized states according to
1158 * invariants, in the appropriate order.
1161 clutter_actor_update_map_state (ClutterActor *self,
1162 MapStateChange change)
1164 gboolean was_mapped;
1166 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1168 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1170 /* the mapped flag on top-level actors must be set by the
1171 * per-backend implementation because it might be asynchronous.
1173 * That is, the MAPPED flag on toplevels currently tracks the X
1174 * server mapped-ness of the window, while the expected behavior
1175 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1176 * This creates some weird complexity by breaking the invariant
1177 * that if we're visible and all ancestors shown then we are
1178 * also mapped - instead, we are mapped if all ancestors
1179 * _possibly excepting_ the stage are mapped. The stage
1180 * will map/unmap for example when it is minimized or
1181 * moved to another workspace.
1183 * So, the only invariant on the stage is that if visible it
1184 * should be realized, and that it has to be visible to be
1187 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1188 clutter_actor_realize (self);
1192 case MAP_STATE_CHECK:
1195 case MAP_STATE_MAKE_MAPPED:
1196 g_assert (!was_mapped);
1197 clutter_actor_set_mapped (self, TRUE);
1200 case MAP_STATE_MAKE_UNMAPPED:
1201 g_assert (was_mapped);
1202 clutter_actor_set_mapped (self, FALSE);
1205 case MAP_STATE_MAKE_UNREALIZED:
1206 /* we only use MAKE_UNREALIZED in unparent,
1207 * and unparenting a stage isn't possible.
1208 * If someone wants to just unrealize a stage
1209 * then clutter_actor_unrealize() doesn't
1210 * go through this codepath.
1212 g_warning ("Trying to force unrealize stage is not allowed");
1216 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1217 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1218 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1220 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1221 "it is somehow still mapped",
1222 _clutter_actor_get_debug_name (self));
1227 ClutterActorPrivate *priv = self->priv;
1228 ClutterActor *parent = priv->parent;
1229 gboolean should_be_mapped;
1230 gboolean may_be_realized;
1231 gboolean must_be_realized;
1233 should_be_mapped = FALSE;
1234 may_be_realized = TRUE;
1235 must_be_realized = FALSE;
1237 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1239 may_be_realized = FALSE;
1243 /* Maintain invariant that if parent is mapped, and we are
1244 * visible, then we are mapped ... unless parent is a
1245 * stage, in which case we map regardless of parent's map
1246 * state but do require stage to be visible and realized.
1248 * If parent is realized, that does not force us to be
1249 * realized; but if parent is unrealized, that does force
1250 * us to be unrealized.
1252 * The reason we don't force children to realize with
1253 * parents is _clutter_actor_rerealize(); if we require that
1254 * a realized parent means children are realized, then to
1255 * unrealize an actor we would have to unrealize its
1256 * parents, which would end up meaning unrealizing and
1257 * hiding the entire stage. So we allow unrealizing a
1258 * child (as long as that child is not mapped) while that
1259 * child still has a realized parent.
1261 * Also, if we unrealize from leaf nodes to root, and
1262 * realize from root to leaf, the invariants are never
1263 * violated if we allow children to be unrealized
1264 * while parents are realized.
1266 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1267 * to force us to unmap, even though parent is still
1268 * mapped. This is because we're unmapping from leaf nodes
1271 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1272 change != MAP_STATE_MAKE_UNMAPPED)
1274 gboolean parent_is_visible_realized_toplevel;
1276 parent_is_visible_realized_toplevel =
1277 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1278 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1279 CLUTTER_ACTOR_IS_REALIZED (parent));
1281 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1282 parent_is_visible_realized_toplevel)
1284 must_be_realized = TRUE;
1285 should_be_mapped = TRUE;
1289 /* if the actor has been set to be painted even if unmapped
1290 * then we should map it and check for realization as well;
1291 * this is an override for the branch of the scene graph
1292 * which begins with this node
1294 if (priv->enable_paint_unmapped)
1296 if (priv->parent == NULL)
1297 g_warning ("Attempting to map an unparented actor '%s'",
1298 _clutter_actor_get_debug_name (self));
1300 should_be_mapped = TRUE;
1301 must_be_realized = TRUE;
1304 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1305 may_be_realized = FALSE;
1308 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1311 g_warning ("Attempting to map a child that does not "
1312 "meet the necessary invariants: the actor '%s' "
1314 _clutter_actor_get_debug_name (self));
1316 g_warning ("Attempting to map a child that does not "
1317 "meet the necessary invariants: the actor '%s' "
1318 "is parented to an unmapped actor '%s'",
1319 _clutter_actor_get_debug_name (self),
1320 _clutter_actor_get_debug_name (priv->parent));
1323 /* If in reparent, we temporarily suspend unmap and unrealize.
1325 * We want to go in the order "realize, map" and "unmap, unrealize"
1329 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1330 clutter_actor_set_mapped (self, FALSE);
1333 if (must_be_realized)
1334 clutter_actor_realize (self);
1336 /* if we must be realized then we may be, presumably */
1337 g_assert (!(must_be_realized && !may_be_realized));
1340 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1341 clutter_actor_unrealize_not_hiding (self);
1344 if (should_be_mapped)
1346 if (!must_be_realized)
1347 g_warning ("Somehow we think actor '%s' should be mapped but "
1348 "not realized, which isn't allowed",
1349 _clutter_actor_get_debug_name (self));
1351 /* realization is allowed to fail (though I don't know what
1352 * an app is supposed to do about that - shouldn't it just
1353 * be a g_error? anyway, we have to avoid mapping if this
1356 if (CLUTTER_ACTOR_IS_REALIZED (self))
1357 clutter_actor_set_mapped (self, TRUE);
1361 #ifdef CLUTTER_ENABLE_DEBUG
1362 /* check all invariants were kept */
1363 clutter_actor_verify_map_state (self);
1368 clutter_actor_real_map (ClutterActor *self)
1370 ClutterActorPrivate *priv = self->priv;
1371 ClutterActor *stage, *iter;
1373 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1375 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1376 _clutter_actor_get_debug_name (self));
1378 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1380 stage = _clutter_actor_get_stage_internal (self);
1381 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1383 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1385 _clutter_actor_get_debug_name (self));
1387 /* notify on parent mapped before potentially mapping
1388 * children, so apps see a top-down notification.
1390 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1392 for (iter = self->priv->first_child;
1394 iter = iter->priv->next_sibling)
1396 clutter_actor_map (iter);
1401 * clutter_actor_map:
1402 * @self: A #ClutterActor
1404 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1405 * and realizes its children if they are visible. Does nothing if the
1406 * actor is not visible.
1408 * Calling this function is strongly disencouraged: the default
1409 * implementation of #ClutterActorClass.map() will map all the children
1410 * of an actor when mapping its parent.
1412 * When overriding map, it is mandatory to chain up to the parent
1418 clutter_actor_map (ClutterActor *self)
1420 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1422 if (CLUTTER_ACTOR_IS_MAPPED (self))
1425 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1428 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1432 clutter_actor_real_unmap (ClutterActor *self)
1434 ClutterActorPrivate *priv = self->priv;
1437 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1439 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1440 _clutter_actor_get_debug_name (self));
1442 for (iter = self->priv->first_child;
1444 iter = iter->priv->next_sibling)
1446 clutter_actor_unmap (iter);
1449 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1451 /* clear the contents of the last paint volume, so that hiding + moving +
1452 * showing will not result in the wrong area being repainted
1454 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1455 priv->last_paint_volume_valid = TRUE;
1457 /* notify on parent mapped after potentially unmapping
1458 * children, so apps see a bottom-up notification.
1460 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1462 /* relinquish keyboard focus if we were unmapped while owning it */
1463 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1465 ClutterStage *stage;
1467 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1470 _clutter_stage_release_pick_id (stage, priv->pick_id);
1474 if (stage != NULL &&
1475 clutter_stage_get_key_focus (stage) == self)
1477 clutter_stage_set_key_focus (stage, NULL);
1483 * clutter_actor_unmap:
1484 * @self: A #ClutterActor
1486 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1487 * unmaps its children if they were mapped.
1489 * Calling this function is not encouraged: the default #ClutterActor
1490 * implementation of #ClutterActorClass.unmap() will also unmap any
1491 * eventual children by default when their parent is unmapped.
1493 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1494 * chain up to the parent implementation.
1496 * <note>It is important to note that the implementation of the
1497 * #ClutterActorClass.unmap() virtual function may be called after
1498 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1499 * implementation, but it is guaranteed to be called before the
1500 * #GObjectClass.finalize() implementation.</note>
1505 clutter_actor_unmap (ClutterActor *self)
1507 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1509 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1512 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1516 clutter_actor_real_show (ClutterActor *self)
1518 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1520 ClutterActorPrivate *priv = self->priv;
1522 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1524 /* we notify on the "visible" flag in the clutter_actor_show()
1525 * wrapper so the entire show signal emission completes first
1528 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1530 /* we queue a relayout unless the actor is inside a
1531 * container that explicitly told us not to
1533 if (priv->parent != NULL &&
1534 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1536 /* While an actor is hidden the parent may not have
1537 * allocated/requested so we need to start from scratch
1538 * and avoid the short-circuiting in
1539 * clutter_actor_queue_relayout().
1541 priv->needs_width_request = FALSE;
1542 priv->needs_height_request = FALSE;
1543 priv->needs_allocation = FALSE;
1544 clutter_actor_queue_relayout (self);
1550 set_show_on_set_parent (ClutterActor *self,
1553 ClutterActorPrivate *priv = self->priv;
1555 set_show = !!set_show;
1557 if (priv->show_on_set_parent == set_show)
1560 if (priv->parent == NULL)
1562 priv->show_on_set_parent = set_show;
1563 g_object_notify_by_pspec (G_OBJECT (self),
1564 obj_props[PROP_SHOW_ON_SET_PARENT]);
1569 * clutter_actor_show:
1570 * @self: A #ClutterActor
1572 * Flags an actor to be displayed. An actor that isn't shown will not
1573 * be rendered on the stage.
1575 * Actors are visible by default.
1577 * If this function is called on an actor without a parent, the
1578 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1582 clutter_actor_show (ClutterActor *self)
1584 ClutterActorPrivate *priv;
1586 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1588 /* simple optimization */
1589 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1591 /* we still need to set the :show-on-set-parent property, in
1592 * case show() is called on an unparented actor
1594 set_show_on_set_parent (self, TRUE);
1598 #ifdef CLUTTER_ENABLE_DEBUG
1599 clutter_actor_verify_map_state (self);
1604 g_object_freeze_notify (G_OBJECT (self));
1606 set_show_on_set_parent (self, TRUE);
1608 g_signal_emit (self, actor_signals[SHOW], 0);
1609 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1611 if (priv->parent != NULL)
1612 clutter_actor_queue_redraw (priv->parent);
1614 g_object_thaw_notify (G_OBJECT (self));
1618 * clutter_actor_show_all:
1619 * @self: a #ClutterActor
1621 * Calls clutter_actor_show() on all children of an actor (if any).
1625 * Deprecated: 1.10: Actors are visible by default
1628 clutter_actor_show_all (ClutterActor *self)
1630 ClutterActorClass *klass;
1632 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1634 klass = CLUTTER_ACTOR_GET_CLASS (self);
1635 if (klass->show_all)
1636 klass->show_all (self);
1640 clutter_actor_real_hide (ClutterActor *self)
1642 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1644 ClutterActorPrivate *priv = self->priv;
1646 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1648 /* we notify on the "visible" flag in the clutter_actor_hide()
1649 * wrapper so the entire hide signal emission completes first
1652 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1654 /* we queue a relayout unless the actor is inside a
1655 * container that explicitly told us not to
1657 if (priv->parent != NULL &&
1658 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1659 clutter_actor_queue_relayout (priv->parent);
1664 * clutter_actor_hide:
1665 * @self: A #ClutterActor
1667 * Flags an actor to be hidden. A hidden actor will not be
1668 * rendered on the stage.
1670 * Actors are visible by default.
1672 * If this function is called on an actor without a parent, the
1673 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1677 clutter_actor_hide (ClutterActor *self)
1679 ClutterActorPrivate *priv;
1681 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1683 /* simple optimization */
1684 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1686 /* we still need to set the :show-on-set-parent property, in
1687 * case hide() is called on an unparented actor
1689 set_show_on_set_parent (self, FALSE);
1693 #ifdef CLUTTER_ENABLE_DEBUG
1694 clutter_actor_verify_map_state (self);
1699 g_object_freeze_notify (G_OBJECT (self));
1701 set_show_on_set_parent (self, FALSE);
1703 g_signal_emit (self, actor_signals[HIDE], 0);
1704 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1706 if (priv->parent != NULL)
1707 clutter_actor_queue_redraw (priv->parent);
1709 g_object_thaw_notify (G_OBJECT (self));
1713 * clutter_actor_hide_all:
1714 * @self: a #ClutterActor
1716 * Calls clutter_actor_hide() on all child actors (if any).
1720 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1721 * prevent its children from being painted as well.
1724 clutter_actor_hide_all (ClutterActor *self)
1726 ClutterActorClass *klass;
1728 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1730 klass = CLUTTER_ACTOR_GET_CLASS (self);
1731 if (klass->hide_all)
1732 klass->hide_all (self);
1736 * clutter_actor_realize:
1737 * @self: A #ClutterActor
1739 * Realization informs the actor that it is attached to a stage. It
1740 * can use this to allocate resources if it wanted to delay allocation
1741 * until it would be rendered. However it is perfectly acceptable for
1742 * an actor to create resources before being realized because Clutter
1743 * only ever has a single rendering context so that actor is free to
1744 * be moved from one stage to another.
1746 * This function does nothing if the actor is already realized.
1748 * Because a realized actor must have realized parent actors, calling
1749 * clutter_actor_realize() will also realize all parents of the actor.
1751 * This function does not realize child actors, except in the special
1752 * case that realizing the stage, when the stage is visible, will
1753 * suddenly map (and thus realize) the children of the stage.
1756 clutter_actor_realize (ClutterActor *self)
1758 ClutterActorPrivate *priv;
1760 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1764 #ifdef CLUTTER_ENABLE_DEBUG
1765 clutter_actor_verify_map_state (self);
1768 if (CLUTTER_ACTOR_IS_REALIZED (self))
1771 /* To be realized, our parent actors must be realized first.
1772 * This will only succeed if we're inside a toplevel.
1774 if (priv->parent != NULL)
1775 clutter_actor_realize (priv->parent);
1777 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1779 /* toplevels can be realized at any time */
1783 /* "Fail" the realization if parent is missing or unrealized;
1784 * this should really be a g_warning() not some kind of runtime
1785 * failure; how can an app possibly recover? Instead it's a bug
1786 * in the app and the app should get an explanatory warning so
1787 * someone can fix it. But for now it's too hard to fix this
1788 * because e.g. ClutterTexture needs reworking.
1790 if (priv->parent == NULL ||
1791 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1795 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1797 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1798 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1800 g_signal_emit (self, actor_signals[REALIZE], 0);
1802 /* Stage actor is allowed to unset the realized flag again in its
1803 * default signal handler, though that is a pathological situation.
1806 /* If realization "failed" we'll have to update child state. */
1807 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1811 clutter_actor_real_unrealize (ClutterActor *self)
1813 /* we must be unmapped (implying our children are also unmapped) */
1814 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1818 * clutter_actor_unrealize:
1819 * @self: A #ClutterActor
1821 * Unrealization informs the actor that it may be being destroyed or
1822 * moved to another stage. The actor may want to destroy any
1823 * underlying graphics resources at this point. However it is
1824 * perfectly acceptable for it to retain the resources until the actor
1825 * is destroyed because Clutter only ever uses a single rendering
1826 * context and all of the graphics resources are valid on any stage.
1828 * Because mapped actors must be realized, actors may not be
1829 * unrealized if they are mapped. This function hides the actor to be
1830 * sure it isn't mapped, an application-visible side effect that you
1831 * may not be expecting.
1833 * This function should not be called by application code.
1836 clutter_actor_unrealize (ClutterActor *self)
1838 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1839 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1841 /* This function should not really be in the public API, because
1842 * there isn't a good reason to call it. ClutterActor will already
1843 * unrealize things for you when it's important to do so.
1845 * If you were using clutter_actor_unrealize() in a dispose
1846 * implementation, then don't, just chain up to ClutterActor's
1849 * If you were using clutter_actor_unrealize() to implement
1850 * unrealizing children of your container, then don't, ClutterActor
1851 * will already take care of that.
1853 * If you were using clutter_actor_unrealize() to re-realize to
1854 * create your resources in a different way, then use
1855 * _clutter_actor_rerealize() (inside Clutter) or just call your
1856 * code that recreates your resources directly (outside Clutter).
1859 #ifdef CLUTTER_ENABLE_DEBUG
1860 clutter_actor_verify_map_state (self);
1863 clutter_actor_hide (self);
1865 clutter_actor_unrealize_not_hiding (self);
1868 static ClutterActorTraverseVisitFlags
1869 unrealize_actor_before_children_cb (ClutterActor *self,
1873 /* If an actor is already unrealized we know its children have also
1874 * already been unrealized... */
1875 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1876 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1878 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1880 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1883 static ClutterActorTraverseVisitFlags
1884 unrealize_actor_after_children_cb (ClutterActor *self,
1888 /* We want to unset the realized flag only _after_
1889 * child actors are unrealized, to maintain invariants.
1891 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1892 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1893 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1897 * clutter_actor_unrealize_not_hiding:
1898 * @self: A #ClutterActor
1900 * Unrealization informs the actor that it may be being destroyed or
1901 * moved to another stage. The actor may want to destroy any
1902 * underlying graphics resources at this point. However it is
1903 * perfectly acceptable for it to retain the resources until the actor
1904 * is destroyed because Clutter only ever uses a single rendering
1905 * context and all of the graphics resources are valid on any stage.
1907 * Because mapped actors must be realized, actors may not be
1908 * unrealized if they are mapped. You must hide the actor or one of
1909 * its parents before attempting to unrealize.
1911 * This function is separate from clutter_actor_unrealize() because it
1912 * does not automatically hide the actor.
1913 * Actors need not be hidden to be unrealized, they just need to
1914 * be unmapped. In fact we don't want to mess up the application's
1915 * setting of the "visible" flag, so hiding is very undesirable.
1917 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1918 * backward compatibility.
1921 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1923 _clutter_actor_traverse (self,
1924 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1925 unrealize_actor_before_children_cb,
1926 unrealize_actor_after_children_cb,
1931 * _clutter_actor_rerealize:
1932 * @self: A #ClutterActor
1933 * @callback: Function to call while unrealized
1934 * @data: data for callback
1936 * If an actor is already unrealized, this just calls the callback.
1938 * If it is realized, it unrealizes temporarily, calls the callback,
1939 * and then re-realizes the actor.
1941 * As a side effect, leaves all children of the actor unrealized if
1942 * the actor was realized but not showing. This is because when we
1943 * unrealize the actor temporarily we must unrealize its children
1944 * (e.g. children of a stage can't be realized if stage window is
1945 * gone). And we aren't clever enough to save the realization state of
1946 * all children. In most cases this should not matter, because
1947 * the children will automatically realize when they next become mapped.
1950 _clutter_actor_rerealize (ClutterActor *self,
1951 ClutterCallback callback,
1954 gboolean was_mapped;
1955 gboolean was_showing;
1956 gboolean was_realized;
1958 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1960 #ifdef CLUTTER_ENABLE_DEBUG
1961 clutter_actor_verify_map_state (self);
1964 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1965 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1966 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1968 /* Must be unmapped to unrealize. Note we only have to hide this
1969 * actor if it was mapped (if all parents were showing). If actor
1970 * is merely visible (but not mapped), then that's fine, we can
1974 clutter_actor_hide (self);
1976 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1978 /* unrealize self and all children */
1979 clutter_actor_unrealize_not_hiding (self);
1981 if (callback != NULL)
1983 (* callback) (self, data);
1987 clutter_actor_show (self); /* will realize only if mapping implies it */
1988 else if (was_realized)
1989 clutter_actor_realize (self); /* realize self and all parents */
1993 clutter_actor_real_pick (ClutterActor *self,
1994 const ClutterColor *color)
1996 /* the default implementation is just to paint a rectangle
1997 * with the same size of the actor using the passed color
1999 if (clutter_actor_should_pick_paint (self))
2001 ClutterActorBox box = { 0, };
2002 float width, height;
2004 clutter_actor_get_allocation_box (self, &box);
2006 width = box.x2 - box.x1;
2007 height = box.y2 - box.y1;
2009 cogl_set_source_color4ub (color->red,
2014 cogl_rectangle (0, 0, width, height);
2017 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2018 * with existing container classes that override the pick() virtual
2019 * and chain up to the default implementation - otherwise we'll end up
2020 * painting our children twice.
2022 * this has to go away for 2.0; hopefully along the pick() itself.
2024 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2028 for (iter = self->priv->first_child;
2030 iter = iter->priv->next_sibling)
2031 clutter_actor_paint (iter);
2036 * clutter_actor_should_pick_paint:
2037 * @self: A #ClutterActor
2039 * Should be called inside the implementation of the
2040 * #ClutterActor::pick virtual function in order to check whether
2041 * the actor should paint itself in pick mode or not.
2043 * This function should never be called directly by applications.
2045 * Return value: %TRUE if the actor should paint its silhouette,
2049 clutter_actor_should_pick_paint (ClutterActor *self)
2051 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2053 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2054 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2055 CLUTTER_ACTOR_IS_REACTIVE (self)))
2062 clutter_actor_real_get_preferred_width (ClutterActor *self,
2064 gfloat *min_width_p,
2065 gfloat *natural_width_p)
2067 ClutterActorPrivate *priv = self->priv;
2069 if (priv->n_children != 0 &&
2070 priv->layout_manager != NULL)
2072 ClutterContainer *container = CLUTTER_CONTAINER (self);
2074 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2075 "for the preferred width",
2076 G_OBJECT_TYPE_NAME (priv->layout_manager),
2077 priv->layout_manager);
2079 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2088 /* Default implementation is always 0x0, usually an actor
2089 * using this default is relying on someone to set the
2092 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2097 if (natural_width_p)
2098 *natural_width_p = 0;
2102 clutter_actor_real_get_preferred_height (ClutterActor *self,
2104 gfloat *min_height_p,
2105 gfloat *natural_height_p)
2107 ClutterActorPrivate *priv = self->priv;
2109 if (priv->n_children != 0 &&
2110 priv->layout_manager != NULL)
2112 ClutterContainer *container = CLUTTER_CONTAINER (self);
2114 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2115 "for the preferred height",
2116 G_OBJECT_TYPE_NAME (priv->layout_manager),
2117 priv->layout_manager);
2119 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2127 /* Default implementation is always 0x0, usually an actor
2128 * using this default is relying on someone to set the
2131 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2136 if (natural_height_p)
2137 *natural_height_p = 0;
2141 clutter_actor_store_old_geometry (ClutterActor *self,
2142 ClutterActorBox *box)
2144 *box = self->priv->allocation;
2148 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2149 const ClutterActorBox *old)
2151 ClutterActorPrivate *priv = self->priv;
2152 GObject *obj = G_OBJECT (self);
2154 g_object_freeze_notify (obj);
2156 /* to avoid excessive requisition or allocation cycles we
2157 * use the cached values.
2159 * - if we don't have an allocation we assume that we need
2161 * - if we don't have a width or a height request we notify
2163 * - if we have a valid allocation then we check the old
2164 * bounding box with the current allocation and we notify
2167 if (priv->needs_allocation)
2169 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2170 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2171 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2172 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2173 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2174 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2176 else if (priv->needs_width_request || priv->needs_height_request)
2178 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2179 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2180 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2185 gfloat width, height;
2187 x = priv->allocation.x1;
2188 y = priv->allocation.y1;
2189 width = priv->allocation.x2 - priv->allocation.x1;
2190 height = priv->allocation.y2 - priv->allocation.y1;
2194 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2195 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2200 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2201 g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2204 if (width != (old->x2 - old->x1))
2206 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2207 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2210 if (height != (old->y2 - old->y1))
2212 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2213 g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2217 g_object_thaw_notify (obj);
2221 * clutter_actor_set_allocation_internal:
2222 * @self: a #ClutterActor
2223 * @box: a #ClutterActorBox
2224 * @flags: allocation flags
2226 * Stores the allocation of @self.
2228 * This function only performs basic storage and property notification.
2230 * This function should be called by clutter_actor_set_allocation()
2231 * and by the default implementation of #ClutterActorClass.allocate().
2233 * Return value: %TRUE if the allocation of the #ClutterActor has been
2234 * changed, and %FALSE otherwise
2236 static inline gboolean
2237 clutter_actor_set_allocation_internal (ClutterActor *self,
2238 const ClutterActorBox *box,
2239 ClutterAllocationFlags flags)
2241 ClutterActorPrivate *priv = self->priv;
2243 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2244 gboolean flags_changed;
2246 ClutterActorBox old_alloc = { 0, };
2248 obj = G_OBJECT (self);
2250 g_object_freeze_notify (obj);
2252 clutter_actor_store_old_geometry (self, &old_alloc);
2254 x1_changed = priv->allocation.x1 != box->x1;
2255 y1_changed = priv->allocation.y1 != box->y1;
2256 x2_changed = priv->allocation.x2 != box->x2;
2257 y2_changed = priv->allocation.y2 != box->y2;
2259 flags_changed = priv->allocation_flags != flags;
2261 priv->allocation = *box;
2262 priv->allocation_flags = flags;
2264 /* allocation is authoritative */
2265 priv->needs_width_request = FALSE;
2266 priv->needs_height_request = FALSE;
2267 priv->needs_allocation = FALSE;
2269 if (x1_changed || y1_changed ||
2270 x2_changed || y2_changed ||
2273 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2274 _clutter_actor_get_debug_name (self));
2276 priv->transform_valid = FALSE;
2278 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2280 /* if the allocation changes, so does the content box */
2281 if (priv->content != NULL)
2283 priv->content_box_valid = FALSE;
2284 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2292 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2294 g_object_thaw_notify (obj);
2299 static void clutter_actor_real_allocate (ClutterActor *self,
2300 const ClutterActorBox *box,
2301 ClutterAllocationFlags flags);
2304 clutter_actor_maybe_layout_children (ClutterActor *self,
2305 const ClutterActorBox *allocation,
2306 ClutterAllocationFlags flags)
2308 ClutterActorPrivate *priv = self->priv;
2310 /* this is going to be a bit hard to follow, so let's put an explanation
2313 * we want ClutterActor to have a default layout manager if the actor was
2314 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2316 * we also want any subclass of ClutterActor that does not override the
2317 * ::allocate() virtual function to delegate to a layout manager.
2319 * finally, we want to allow people subclassing ClutterActor and overriding
2320 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2322 * on the other hand, we want existing actor subclasses overriding the
2323 * ::allocate() virtual function and chaining up to the parent's
2324 * implementation to continue working without allocating their children
2325 * twice, or without entering an allocation loop.
2327 * for the first two points, we check if the class of the actor is
2328 * overridding the ::allocate() virtual function; if it isn't, then we
2329 * follow through with checking whether we have children and a layout
2330 * manager, and eventually calling clutter_layout_manager_allocate().
2332 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2333 * allocation flags that we got passed, and if it is present, we continue
2334 * with the check above.
2336 * if neither of these two checks yields a positive result, we just
2337 * assume that the ::allocate() virtual function that resulted in this
2338 * function being called will also allocate the children of the actor.
2341 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2344 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2350 if (priv->n_children != 0 &&
2351 priv->layout_manager != NULL)
2353 ClutterContainer *container = CLUTTER_CONTAINER (self);
2354 ClutterAllocationFlags children_flags;
2355 ClutterActorBox children_box;
2357 /* normalize the box passed to the layout manager */
2358 children_box.x1 = children_box.y1 = 0.f;
2359 children_box.x2 = (allocation->x2 - allocation->x1);
2360 children_box.y2 = (allocation->y2 - allocation->y1);
2362 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2363 * the actor's children, since it refers only to the current
2364 * actor's allocation.
2366 children_flags = flags;
2367 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2369 CLUTTER_NOTE (LAYOUT,
2370 "Allocating %d children of %s "
2371 "at { %.2f, %.2f - %.2f x %.2f } "
2374 _clutter_actor_get_debug_name (self),
2377 (allocation->x2 - allocation->x1),
2378 (allocation->y2 - allocation->y1),
2379 G_OBJECT_TYPE_NAME (priv->layout_manager));
2381 clutter_layout_manager_allocate (priv->layout_manager,
2389 clutter_actor_real_allocate (ClutterActor *self,
2390 const ClutterActorBox *box,
2391 ClutterAllocationFlags flags)
2393 ClutterActorPrivate *priv = self->priv;
2396 g_object_freeze_notify (G_OBJECT (self));
2398 changed = clutter_actor_set_allocation_internal (self, box, flags);
2400 /* we allocate our children before we notify changes in our geometry,
2401 * so that people connecting to properties will be able to get valid
2402 * data out of the sub-tree of the scene graph that has this actor at
2405 clutter_actor_maybe_layout_children (self, box, flags);
2409 ClutterActorBox signal_box = priv->allocation;
2410 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2412 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2417 g_object_thaw_notify (G_OBJECT (self));
2421 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2422 ClutterActor *origin)
2424 /* no point in queuing a redraw on a destroyed actor */
2425 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2428 /* NB: We can't bail out early here if the actor is hidden in case
2429 * the actor bas been cloned. In this case the clone will need to
2430 * receive the signal so it can queue its own redraw.
2433 /* calls klass->queue_redraw in default handler */
2434 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2438 clutter_actor_real_queue_redraw (ClutterActor *self,
2439 ClutterActor *origin)
2441 ClutterActor *parent;
2443 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2444 _clutter_actor_get_debug_name (self),
2445 origin != NULL ? _clutter_actor_get_debug_name (origin)
2448 /* no point in queuing a redraw on a destroyed actor */
2449 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2452 /* If the queue redraw is coming from a child then the actor has
2453 become dirty and any queued effect is no longer valid */
2456 self->priv->is_dirty = TRUE;
2457 self->priv->effect_to_redraw = NULL;
2460 /* If the actor isn't visible, we still had to emit the signal
2461 * to allow for a ClutterClone, but the appearance of the parent
2462 * won't change so we don't have to propagate up the hierarchy.
2464 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2467 /* Although we could determine here that a full stage redraw
2468 * has already been queued and immediately bail out, we actually
2469 * guarantee that we will propagate a queue-redraw signal to our
2470 * parent at least once so that it's possible to implement a
2471 * container that tracks which of its children have queued a
2474 if (self->priv->propagated_one_redraw)
2476 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2477 if (stage != NULL &&
2478 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2482 self->priv->propagated_one_redraw = TRUE;
2484 /* notify parents, if they are all visible eventually we'll
2485 * queue redraw on the stage, which queues the redraw idle.
2487 parent = clutter_actor_get_parent (self);
2490 /* this will go up recursively */
2491 _clutter_actor_signal_queue_redraw (parent, origin);
2496 clutter_actor_real_queue_relayout (ClutterActor *self)
2498 ClutterActorPrivate *priv = self->priv;
2500 /* no point in queueing a redraw on a destroyed actor */
2501 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2504 priv->needs_width_request = TRUE;
2505 priv->needs_height_request = TRUE;
2506 priv->needs_allocation = TRUE;
2508 /* reset the cached size requests */
2509 memset (priv->width_requests, 0,
2510 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2511 memset (priv->height_requests, 0,
2512 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2514 /* We need to go all the way up the hierarchy */
2515 if (priv->parent != NULL)
2516 _clutter_actor_queue_only_relayout (priv->parent);
2520 * clutter_actor_apply_relative_transform_to_point:
2521 * @self: A #ClutterActor
2522 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2523 * default #ClutterStage
2524 * @point: A point as #ClutterVertex
2525 * @vertex: (out caller-allocates): The translated #ClutterVertex
2527 * Transforms @point in coordinates relative to the actor into
2528 * ancestor-relative coordinates using the relevant transform
2529 * stack (i.e. scale, rotation, etc).
2531 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2532 * this case, the coordinates returned will be the coordinates on
2533 * the stage before the projection is applied. This is different from
2534 * the behaviour of clutter_actor_apply_transform_to_point().
2539 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2540 ClutterActor *ancestor,
2541 const ClutterVertex *point,
2542 ClutterVertex *vertex)
2547 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2548 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2549 g_return_if_fail (point != NULL);
2550 g_return_if_fail (vertex != NULL);
2555 if (ancestor == NULL)
2556 ancestor = _clutter_actor_get_stage_internal (self);
2558 if (ancestor == NULL)
2564 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2565 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2569 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2570 const ClutterVertex *vertices_in,
2571 ClutterVertex *vertices_out,
2574 ClutterActor *stage;
2575 CoglMatrix modelview;
2576 CoglMatrix projection;
2579 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2581 stage = _clutter_actor_get_stage_internal (self);
2583 /* We really can't do anything meaningful in this case so don't try
2584 * to do any transform */
2588 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2589 * that gets us to stage coordinates, we want to go all the way to eye
2591 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2593 /* Fetch the projection and viewport */
2594 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2595 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2601 _clutter_util_fully_transform_vertices (&modelview,
2612 * clutter_actor_apply_transform_to_point:
2613 * @self: A #ClutterActor
2614 * @point: A point as #ClutterVertex
2615 * @vertex: (out caller-allocates): The translated #ClutterVertex
2617 * Transforms @point in coordinates relative to the actor
2618 * into screen-relative coordinates with the current actor
2619 * transformation (i.e. scale, rotation, etc)
2624 clutter_actor_apply_transform_to_point (ClutterActor *self,
2625 const ClutterVertex *point,
2626 ClutterVertex *vertex)
2628 g_return_if_fail (point != NULL);
2629 g_return_if_fail (vertex != NULL);
2630 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2634 * _clutter_actor_get_relative_transformation_matrix:
2635 * @self: The actor whose coordinate space you want to transform from.
2636 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2637 * or %NULL if you want to transform all the way to eye coordinates.
2638 * @matrix: A #CoglMatrix to store the transformation
2640 * This gets a transformation @matrix that will transform coordinates from the
2641 * coordinate space of @self into the coordinate space of @ancestor.
2643 * For example if you need a matrix that can transform the local actor
2644 * coordinates of @self into stage coordinates you would pass the actor's stage
2645 * pointer as the @ancestor.
2647 * If you pass %NULL then the transformation will take you all the way through
2648 * to eye coordinates. This can be useful if you want to extract the entire
2649 * modelview transform that Clutter applies before applying the projection
2650 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2651 * using cogl_set_modelview_matrix() for example then you would want a matrix
2652 * that transforms into eye coordinates.
2654 * <note><para>This function explicitly initializes the given @matrix. If you just
2655 * want clutter to multiply a relative transformation with an existing matrix
2656 * you can use clutter_actor_apply_relative_transformation_matrix()
2657 * instead.</para></note>
2660 /* XXX: We should consider caching the stage relative modelview along with
2661 * the actor itself */
2663 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2664 ClutterActor *ancestor,
2667 cogl_matrix_init_identity (matrix);
2669 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2672 /* Project the given @box into stage window coordinates, writing the
2673 * transformed vertices to @verts[]. */
2675 _clutter_actor_transform_and_project_box (ClutterActor *self,
2676 const ClutterActorBox *box,
2677 ClutterVertex verts[])
2679 ClutterVertex box_vertices[4];
2681 box_vertices[0].x = box->x1;
2682 box_vertices[0].y = box->y1;
2683 box_vertices[0].z = 0;
2684 box_vertices[1].x = box->x2;
2685 box_vertices[1].y = box->y1;
2686 box_vertices[1].z = 0;
2687 box_vertices[2].x = box->x1;
2688 box_vertices[2].y = box->y2;
2689 box_vertices[2].z = 0;
2690 box_vertices[3].x = box->x2;
2691 box_vertices[3].y = box->y2;
2692 box_vertices[3].z = 0;
2695 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2699 * clutter_actor_get_allocation_vertices:
2700 * @self: A #ClutterActor
2701 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2702 * against, or %NULL to use the #ClutterStage
2703 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2704 * location for an array of 4 #ClutterVertex in which to store the result
2706 * Calculates the transformed coordinates of the four corners of the
2707 * actor in the plane of @ancestor. The returned vertices relate to
2708 * the #ClutterActorBox coordinates as follows:
2710 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2711 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2712 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2713 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2716 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2717 * this case, the coordinates returned will be the coordinates on
2718 * the stage before the projection is applied. This is different from
2719 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2724 clutter_actor_get_allocation_vertices (ClutterActor *self,
2725 ClutterActor *ancestor,
2726 ClutterVertex verts[])
2728 ClutterActorPrivate *priv;
2729 ClutterActorBox box;
2730 ClutterVertex vertices[4];
2731 CoglMatrix modelview;
2733 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2734 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2736 if (ancestor == NULL)
2737 ancestor = _clutter_actor_get_stage_internal (self);
2739 /* Fallback to a NOP transform if the actor isn't parented under a
2741 if (ancestor == NULL)
2746 /* if the actor needs to be allocated we force a relayout, so that
2747 * we will have valid values to use in the transformations */
2748 if (priv->needs_allocation)
2750 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2752 _clutter_stage_maybe_relayout (stage);
2755 box.x1 = box.y1 = 0;
2756 /* The result isn't really meaningful in this case but at
2757 * least try to do something *vaguely* reasonable... */
2758 clutter_actor_get_size (self, &box.x2, &box.y2);
2762 clutter_actor_get_allocation_box (self, &box);
2764 vertices[0].x = box.x1;
2765 vertices[0].y = box.y1;
2767 vertices[1].x = box.x2;
2768 vertices[1].y = box.y1;
2770 vertices[2].x = box.x1;
2771 vertices[2].y = box.y2;
2773 vertices[3].x = box.x2;
2774 vertices[3].y = box.y2;
2777 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2780 cogl_matrix_transform_points (&modelview,
2782 sizeof (ClutterVertex),
2784 sizeof (ClutterVertex),
2790 * clutter_actor_get_abs_allocation_vertices:
2791 * @self: A #ClutterActor
2792 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2793 * of 4 #ClutterVertex where to store the result.
2795 * Calculates the transformed screen coordinates of the four corners of
2796 * the actor; the returned vertices relate to the #ClutterActorBox
2797 * coordinates as follows:
2799 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2800 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2801 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2802 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2808 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2809 ClutterVertex verts[])
2811 ClutterActorPrivate *priv;
2812 ClutterActorBox actor_space_allocation;
2814 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2818 /* if the actor needs to be allocated we force a relayout, so that
2819 * the actor allocation box will be valid for
2820 * _clutter_actor_transform_and_project_box()
2822 if (priv->needs_allocation)
2824 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2825 /* There's nothing meaningful we can do now */
2829 _clutter_stage_maybe_relayout (stage);
2832 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2833 * own coordinate space... */
2834 actor_space_allocation.x1 = 0;
2835 actor_space_allocation.y1 = 0;
2836 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2837 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2838 _clutter_actor_transform_and_project_box (self,
2839 &actor_space_allocation,
2844 clutter_actor_real_apply_transform (ClutterActor *self,
2847 ClutterActorPrivate *priv = self->priv;
2849 if (!priv->transform_valid)
2851 CoglMatrix *transform = &priv->transform;
2852 const ClutterTransformInfo *info;
2854 info = _clutter_actor_get_transform_info_or_defaults (self);
2856 cogl_matrix_init_identity (transform);
2858 cogl_matrix_translate (transform,
2859 priv->allocation.x1,
2860 priv->allocation.y1,
2864 cogl_matrix_translate (transform, 0, 0, info->depth);
2867 * because the rotation involves translations, we must scale
2868 * before applying the rotations (if we apply the scale after
2869 * the rotations, the translations included in the rotation are
2870 * not scaled and so the entire object will move on the screen
2871 * as a result of rotating it).
2873 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2875 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2876 &info->scale_center,
2877 cogl_matrix_scale (transform,
2884 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2886 cogl_matrix_rotate (transform,
2891 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2893 cogl_matrix_rotate (transform,
2898 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2900 cogl_matrix_rotate (transform,
2904 if (!clutter_anchor_coord_is_zero (&info->anchor))
2908 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2909 cogl_matrix_translate (transform, -x, -y, -z);
2912 priv->transform_valid = TRUE;
2915 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2918 /* Applies the transforms associated with this actor to the given
2921 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2924 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2928 * clutter_actor_apply_relative_transformation_matrix:
2929 * @self: The actor whose coordinate space you want to transform from.
2930 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2931 * or %NULL if you want to transform all the way to eye coordinates.
2932 * @matrix: A #CoglMatrix to apply the transformation too.
2934 * This multiplies a transform with @matrix that will transform coordinates
2935 * from the coordinate space of @self into the coordinate space of @ancestor.
2937 * For example if you need a matrix that can transform the local actor
2938 * coordinates of @self into stage coordinates you would pass the actor's stage
2939 * pointer as the @ancestor.
2941 * If you pass %NULL then the transformation will take you all the way through
2942 * to eye coordinates. This can be useful if you want to extract the entire
2943 * modelview transform that Clutter applies before applying the projection
2944 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2945 * using cogl_set_modelview_matrix() for example then you would want a matrix
2946 * that transforms into eye coordinates.
2948 * <note>This function doesn't initialize the given @matrix, it simply
2949 * multiplies the requested transformation matrix with the existing contents of
2950 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2951 * before calling this function, or you can use
2952 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2955 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2956 ClutterActor *ancestor,
2959 ClutterActor *parent;
2961 /* Note we terminate before ever calling stage->apply_transform()
2962 * since that would conceptually be relative to the underlying
2963 * window OpenGL coordinates so we'd need a special @ancestor
2964 * value to represent the fake parent of the stage. */
2965 if (self == ancestor)
2968 parent = clutter_actor_get_parent (self);
2971 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2974 _clutter_actor_apply_modelview_transform (self, matrix);
2978 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2979 ClutterPaintVolume *pv,
2981 const CoglColor *color)
2983 static CoglPipeline *outline = NULL;
2984 CoglPrimitive *prim;
2985 ClutterVertex line_ends[12 * 2];
2988 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2989 /* XXX: at some point we'll query this from the stage but we can't
2990 * do that until the osx backend uses Cogl natively. */
2991 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2993 if (outline == NULL)
2994 outline = cogl_pipeline_new (ctx);
2996 _clutter_paint_volume_complete (pv);
2998 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3001 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3002 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3003 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3004 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3009 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3010 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3011 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3012 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3014 /* Lines connecting front face to back face */
3015 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3016 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3017 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3018 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3021 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3023 (CoglVertexP3 *)line_ends);
3025 cogl_pipeline_set_color (outline, color);
3026 cogl_framebuffer_draw_primitive (fb, outline, prim);
3027 cogl_object_unref (prim);
3031 PangoLayout *layout;
3032 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3033 pango_layout_set_text (layout, label, -1);
3034 cogl_pango_render_layout (layout,
3039 g_object_unref (layout);
3044 _clutter_actor_draw_paint_volume (ClutterActor *self)
3046 ClutterPaintVolume *pv;
3049 pv = _clutter_actor_get_paint_volume_mutable (self);
3052 gfloat width, height;
3053 ClutterPaintVolume fake_pv;
3055 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3056 _clutter_paint_volume_init_static (&fake_pv, stage);
3058 clutter_actor_get_size (self, &width, &height);
3059 clutter_paint_volume_set_width (&fake_pv, width);
3060 clutter_paint_volume_set_height (&fake_pv, height);
3062 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3063 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3064 _clutter_actor_get_debug_name (self),
3067 clutter_paint_volume_free (&fake_pv);
3071 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3072 _clutter_actor_draw_paint_volume_full (self, pv,
3073 _clutter_actor_get_debug_name (self),
3079 _clutter_actor_paint_cull_result (ClutterActor *self,
3081 ClutterCullResult result)
3083 ClutterPaintVolume *pv;
3088 if (result == CLUTTER_CULL_RESULT_IN)
3089 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3090 else if (result == CLUTTER_CULL_RESULT_OUT)
3091 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3093 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3096 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3098 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3099 _clutter_actor_draw_paint_volume_full (self, pv,
3100 _clutter_actor_get_debug_name (self),
3104 PangoLayout *layout;
3106 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3107 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3108 cogl_set_source_color (&color);
3110 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3111 pango_layout_set_text (layout, label, -1);
3112 cogl_pango_render_layout (layout,
3118 g_object_unref (layout);
3122 static int clone_paint_level = 0;
3125 _clutter_actor_push_clone_paint (void)
3127 clone_paint_level++;
3131 _clutter_actor_pop_clone_paint (void)
3133 clone_paint_level--;
3137 in_clone_paint (void)
3139 return clone_paint_level > 0;
3142 /* Returns TRUE if the actor can be ignored */
3143 /* FIXME: we should return a ClutterCullResult, and
3144 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3145 * means there's no point in trying to cull descendants of the current
3148 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3150 ClutterActorPrivate *priv = self->priv;
3151 ClutterActor *stage;
3152 const ClutterPlane *stage_clip;
3154 if (!priv->last_paint_volume_valid)
3156 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3157 "->last_paint_volume_valid == FALSE",
3158 _clutter_actor_get_debug_name (self));
3162 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3165 stage = _clutter_actor_get_stage_internal (self);
3166 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3167 if (G_UNLIKELY (!stage_clip))
3169 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3170 "No stage clip set",
3171 _clutter_actor_get_debug_name (self));
3175 if (cogl_get_draw_framebuffer () !=
3176 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3178 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3179 "Current framebuffer doesn't correspond to stage",
3180 _clutter_actor_get_debug_name (self));
3185 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3190 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3192 ClutterActorPrivate *priv = self->priv;
3193 const ClutterPaintVolume *pv;
3195 if (priv->last_paint_volume_valid)
3197 clutter_paint_volume_free (&priv->last_paint_volume);
3198 priv->last_paint_volume_valid = FALSE;
3201 pv = clutter_actor_get_paint_volume (self);
3204 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3205 "Actor failed to report a paint volume",
3206 _clutter_actor_get_debug_name (self));
3210 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3212 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3213 NULL); /* eye coordinates */
3215 priv->last_paint_volume_valid = TRUE;
3218 static inline gboolean
3219 actor_has_shader_data (ClutterActor *self)
3221 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3225 _clutter_actor_get_pick_id (ClutterActor *self)
3227 if (self->priv->pick_id < 0)
3230 return self->priv->pick_id;
3233 /* This is the same as clutter_actor_add_effect except that it doesn't
3234 queue a redraw and it doesn't notify on the effect property */
3236 _clutter_actor_add_effect_internal (ClutterActor *self,
3237 ClutterEffect *effect)
3239 ClutterActorPrivate *priv = self->priv;
3241 if (priv->effects == NULL)
3243 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3244 priv->effects->actor = self;
3247 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3250 /* This is the same as clutter_actor_remove_effect except that it doesn't
3251 queue a redraw and it doesn't notify on the effect property */
3253 _clutter_actor_remove_effect_internal (ClutterActor *self,
3254 ClutterEffect *effect)
3256 ClutterActorPrivate *priv = self->priv;
3258 if (priv->effects == NULL)
3261 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3263 if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3264 g_clear_object (&priv->effects);
3268 needs_flatten_effect (ClutterActor *self)
3270 ClutterActorPrivate *priv = self->priv;
3272 if (G_UNLIKELY (clutter_paint_debug_flags &
3273 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3276 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3278 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3280 if (clutter_actor_get_paint_opacity (self) < 255 &&
3281 clutter_actor_has_overlaps (self))
3289 add_or_remove_flatten_effect (ClutterActor *self)
3291 ClutterActorPrivate *priv = self->priv;
3293 /* Add or remove the flatten effect depending on the
3294 offscreen-redirect property. */
3295 if (needs_flatten_effect (self))
3297 if (priv->flatten_effect == NULL)
3299 ClutterActorMeta *actor_meta;
3302 priv->flatten_effect = _clutter_flatten_effect_new ();
3303 /* Keep a reference to the effect so that we can queue
3305 g_object_ref_sink (priv->flatten_effect);
3307 /* Set the priority of the effect to high so that it will
3308 always be applied to the actor first. It uses an internal
3309 priority so that it won't be visible to applications */
3310 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3311 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3312 _clutter_actor_meta_set_priority (actor_meta, priority);
3314 /* This will add the effect without queueing a redraw */
3315 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3320 if (priv->flatten_effect != NULL)
3322 /* Destroy the effect so that it will lose its fbo cache of
3324 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3325 g_clear_object (&priv->flatten_effect);
3331 clutter_actor_real_paint (ClutterActor *actor)
3333 ClutterActorPrivate *priv = actor->priv;
3336 for (iter = priv->first_child;
3338 iter = iter->priv->next_sibling)
3340 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3341 _clutter_actor_get_debug_name (iter),
3342 _clutter_actor_get_debug_name (actor),
3343 iter->priv->allocation.x1,
3344 iter->priv->allocation.y1,
3345 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3346 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3348 clutter_actor_paint (iter);
3353 clutter_actor_paint_node (ClutterActor *actor,
3354 ClutterPaintNode *root)
3356 ClutterActorPrivate *priv = actor->priv;
3361 if (priv->bg_color_set &&
3362 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3364 ClutterPaintNode *node;
3365 ClutterColor bg_color;
3366 ClutterActorBox box;
3370 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3371 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3373 bg_color = priv->bg_color;
3374 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3375 * priv->bg_color.alpha
3378 node = clutter_color_node_new (&bg_color);
3379 clutter_paint_node_set_name (node, "backgroundColor");
3380 clutter_paint_node_add_rectangle (node, &box);
3381 clutter_paint_node_add_child (root, node);
3382 clutter_paint_node_unref (node);
3385 if (priv->content != NULL)
3386 _clutter_content_paint_content (priv->content, actor, root);
3388 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3389 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3391 if (clutter_paint_node_get_n_children (root) == 0)
3394 #ifdef CLUTTER_ENABLE_DEBUG
3395 if (CLUTTER_HAS_DEBUG (PAINT))
3397 /* dump the tree only if we have one */
3398 _clutter_paint_node_dump_tree (root);
3400 #endif /* CLUTTER_ENABLE_DEBUG */
3402 _clutter_paint_node_paint (root);
3405 /* XXX: Uncomment this when we disable emitting the paint signal */
3406 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3413 * clutter_actor_paint:
3414 * @self: A #ClutterActor
3416 * Renders the actor to display.
3418 * This function should not be called directly by applications.
3419 * Call clutter_actor_queue_redraw() to queue paints, instead.
3421 * This function is context-aware, and will either cause a
3422 * regular paint or a pick paint.
3424 * This function will emit the #ClutterActor::paint signal or
3425 * the #ClutterActor::pick signal, depending on the context.
3427 * This function does not paint the actor if the actor is set to 0,
3428 * unless it is performing a pick paint.
3431 clutter_actor_paint (ClutterActor *self)
3433 ClutterActorPrivate *priv;
3434 ClutterPickMode pick_mode;
3435 gboolean clip_set = FALSE;
3436 gboolean shader_applied = FALSE;
3438 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3439 "Actor real-paint counter",
3440 "Increments each time any actor is painted",
3441 0 /* no application private data */);
3442 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3443 "Actor pick-paint counter",
3444 "Increments each time any actor is painted "
3446 0 /* no application private data */);
3448 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3450 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3455 pick_mode = _clutter_context_get_pick_mode ();
3457 if (pick_mode == CLUTTER_PICK_NONE)
3458 priv->propagated_one_redraw = FALSE;
3460 /* It's an important optimization that we consider painting of
3461 * actors with 0 opacity to be a NOP... */
3462 if (pick_mode == CLUTTER_PICK_NONE &&
3463 /* ignore top-levels, since they might be transparent */
3464 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3465 /* Use the override opacity if its been set */
3466 ((priv->opacity_override >= 0) ?
3467 priv->opacity_override : priv->opacity) == 0)
3470 /* if we aren't paintable (not in a toplevel with all
3471 * parents paintable) then do nothing.
3473 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3476 /* mark that we are in the paint process */
3477 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3481 if (priv->enable_model_view_transform)
3485 /* XXX: It could be better to cache the modelview with the actor
3486 * instead of progressively building up the transformations on
3487 * the matrix stack every time we paint. */
3488 cogl_get_modelview_matrix (&matrix);
3489 _clutter_actor_apply_modelview_transform (self, &matrix);
3491 #ifdef CLUTTER_ENABLE_DEBUG
3492 /* Catch when out-of-band transforms have been made by actors not as part
3493 * of an apply_transform vfunc... */
3494 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3496 CoglMatrix expected_matrix;
3498 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3501 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3503 GString *buf = g_string_sized_new (1024);
3504 ClutterActor *parent;
3507 while (parent != NULL)
3509 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3511 if (parent->priv->parent != NULL)
3512 g_string_append (buf, "->");
3514 parent = parent->priv->parent;
3517 g_warning ("Unexpected transform found when painting actor "
3518 "\"%s\". This will be caused by one of the actor's "
3519 "ancestors (%s) using the Cogl API directly to transform "
3520 "children instead of using ::apply_transform().",
3521 _clutter_actor_get_debug_name (self),
3524 g_string_free (buf, TRUE);
3527 #endif /* CLUTTER_ENABLE_DEBUG */
3529 cogl_set_modelview_matrix (&matrix);
3534 cogl_clip_push_rectangle (priv->clip.x,
3536 priv->clip.x + priv->clip.width,
3537 priv->clip.y + priv->clip.height);
3540 else if (priv->clip_to_allocation)
3542 gfloat width, height;
3544 width = priv->allocation.x2 - priv->allocation.x1;
3545 height = priv->allocation.y2 - priv->allocation.y1;
3547 cogl_clip_push_rectangle (0, 0, width, height);
3551 if (pick_mode == CLUTTER_PICK_NONE)
3553 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3555 /* We check whether we need to add the flatten effect before
3556 each paint so that we can avoid having a mechanism for
3557 applications to notify when the value of the
3558 has_overlaps virtual changes. */
3559 add_or_remove_flatten_effect (self);
3562 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3564 /* We save the current paint volume so that the next time the
3565 * actor queues a redraw we can constrain the redraw to just
3566 * cover the union of the new bounding box and the old.
3568 * We also fetch the current paint volume to perform culling so
3569 * we can avoid painting actors outside the current clip region.
3571 * If we are painting inside a clone, we should neither update
3572 * the paint volume or use it to cull painting, since the paint
3573 * box represents the location of the source actor on the
3576 * XXX: We are starting to do a lot of vertex transforms on
3577 * the CPU in a typical paint, so at some point we should
3578 * audit these and consider caching some things.
3580 * NB: We don't perform culling while picking at this point because
3581 * clutter-stage.c doesn't setup the clipping planes appropriately.
3583 * NB: We don't want to update the last-paint-volume during picking
3584 * because the last-paint-volume is used to determine the old screen
3585 * space location of an actor that has moved so we can know the
3586 * minimal region to redraw to clear an old view of the actor. If we
3587 * update this during picking then by the time we come around to
3588 * paint then the last-paint-volume would likely represent the new
3589 * actor position not the old.
3591 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3594 /* annoyingly gcc warns if uninitialized even though
3595 * the initialization is redundant :-( */
3596 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3598 if (G_LIKELY ((clutter_paint_debug_flags &
3599 (CLUTTER_DEBUG_DISABLE_CULLING |
3600 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3601 (CLUTTER_DEBUG_DISABLE_CULLING |
3602 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3603 _clutter_actor_update_last_paint_volume (self);
3605 success = cull_actor (self, &result);
3607 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3608 _clutter_actor_paint_cull_result (self, success, result);
3609 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3613 if (priv->effects == NULL)
3615 if (pick_mode == CLUTTER_PICK_NONE &&
3616 actor_has_shader_data (self))
3618 _clutter_actor_shader_pre_paint (self, FALSE);
3619 shader_applied = TRUE;
3622 priv->next_effect_to_paint = NULL;
3625 priv->next_effect_to_paint =
3626 _clutter_meta_group_peek_metas (priv->effects);
3628 clutter_actor_continue_paint (self);
3631 _clutter_actor_shader_post_paint (self);
3633 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3634 pick_mode == CLUTTER_PICK_NONE))
3635 _clutter_actor_draw_paint_volume (self);
3638 /* If we make it here then the actor has run through a complete
3639 paint run including all the effects so it's no longer dirty */
3640 if (pick_mode == CLUTTER_PICK_NONE)
3641 priv->is_dirty = FALSE;
3648 /* paint sequence complete */
3649 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3653 * clutter_actor_continue_paint:
3654 * @self: A #ClutterActor
3656 * Run the next stage of the paint sequence. This function should only
3657 * be called within the implementation of the ‘run’ virtual of a
3658 * #ClutterEffect. It will cause the run method of the next effect to
3659 * be applied, or it will paint the actual actor if the current effect
3660 * is the last effect in the chain.
3665 clutter_actor_continue_paint (ClutterActor *self)
3667 ClutterActorPrivate *priv;
3669 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3670 /* This should only be called from with in the ‘run’ implementation
3671 of a ClutterEffect */
3672 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3676 /* Skip any effects that are disabled */
3677 while (priv->next_effect_to_paint &&
3678 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3679 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3681 /* If this has come from the last effect then we'll just paint the
3683 if (priv->next_effect_to_paint == NULL)
3685 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3687 ClutterPaintNode *dummy;
3689 /* XXX - this will go away in 2.0, when we can get rid of this
3690 * stuff and switch to a pure retained render tree of PaintNodes
3691 * for the entire frame, starting from the Stage; the paint()
3692 * virtual function can then be called directly.
3694 dummy = _clutter_dummy_node_new (self);
3695 clutter_paint_node_set_name (dummy, "Root");
3697 /* XXX - for 1.12, we use the return value of paint_node() to
3698 * decide whether we should emit the ::paint signal.
3700 clutter_actor_paint_node (self, dummy);
3701 clutter_paint_node_unref (dummy);
3703 g_signal_emit (self, actor_signals[PAINT], 0);
3707 ClutterColor col = { 0, };
3709 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3711 /* Actor will then paint silhouette of itself in supplied
3712 * color. See clutter_stage_get_actor_at_pos() for where
3713 * picking is enabled.
3715 g_signal_emit (self, actor_signals[PICK], 0, &col);
3720 ClutterEffect *old_current_effect;
3721 ClutterEffectPaintFlags run_flags = 0;
3723 /* Cache the current effect so that we can put it back before
3725 old_current_effect = priv->current_effect;
3727 priv->current_effect = priv->next_effect_to_paint->data;
3728 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3730 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3734 /* If there's an effect queued with this redraw then all
3735 effects up to that one will be considered dirty. It
3736 is expected the queued effect will paint the cached
3737 image and not call clutter_actor_continue_paint again
3738 (although it should work ok if it does) */
3739 if (priv->effect_to_redraw == NULL ||
3740 priv->current_effect != priv->effect_to_redraw)
3741 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3744 _clutter_effect_paint (priv->current_effect, run_flags);
3748 /* We can't determine when an actor has been modified since
3749 its last pick so lets just assume it has always been
3751 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3753 _clutter_effect_pick (priv->current_effect, run_flags);
3756 priv->current_effect = old_current_effect;
3760 static ClutterActorTraverseVisitFlags
3761 invalidate_queue_redraw_entry (ClutterActor *self,
3765 ClutterActorPrivate *priv = self->priv;
3767 if (priv->queue_redraw_entry != NULL)
3769 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3770 priv->queue_redraw_entry = NULL;
3773 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3777 remove_child (ClutterActor *self,
3778 ClutterActor *child)
3780 ClutterActor *prev_sibling, *next_sibling;
3782 prev_sibling = child->priv->prev_sibling;
3783 next_sibling = child->priv->next_sibling;
3785 if (prev_sibling != NULL)
3786 prev_sibling->priv->next_sibling = next_sibling;
3788 if (next_sibling != NULL)
3789 next_sibling->priv->prev_sibling = prev_sibling;
3791 if (self->priv->first_child == child)
3792 self->priv->first_child = next_sibling;
3794 if (self->priv->last_child == child)
3795 self->priv->last_child = prev_sibling;
3797 child->priv->parent = NULL;
3798 child->priv->prev_sibling = NULL;
3799 child->priv->next_sibling = NULL;
3803 REMOVE_CHILD_DESTROY_META = 1 << 0,
3804 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3805 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3806 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3807 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3808 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3810 /* default flags for public API */
3811 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3812 REMOVE_CHILD_EMIT_PARENT_SET |
3813 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3814 REMOVE_CHILD_CHECK_STATE |
3815 REMOVE_CHILD_FLUSH_QUEUE |
3816 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3818 /* flags for legacy/deprecated API */
3819 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3820 REMOVE_CHILD_FLUSH_QUEUE |
3821 REMOVE_CHILD_EMIT_PARENT_SET |
3822 REMOVE_CHILD_NOTIFY_FIRST_LAST
3823 } ClutterActorRemoveChildFlags;
3826 * clutter_actor_remove_child_internal:
3827 * @self: a #ClutterActor
3828 * @child: the child of @self that has to be removed
3829 * @flags: control the removal operations
3831 * Removes @child from the list of children of @self.
3834 clutter_actor_remove_child_internal (ClutterActor *self,
3835 ClutterActor *child,
3836 ClutterActorRemoveChildFlags flags)
3838 ClutterActor *old_first, *old_last;
3839 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3840 gboolean flush_queue;
3841 gboolean notify_first_last;
3842 gboolean was_mapped;
3844 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3845 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3846 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3847 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3848 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3849 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3851 g_object_freeze_notify (G_OBJECT (self));
3854 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3858 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3860 /* we need to unrealize *before* we set parent_actor to NULL,
3861 * because in an unrealize method actors are dissociating from the
3862 * stage, which means they need to be able to
3863 * clutter_actor_get_stage().
3865 * yhis should unmap and unrealize, unless we're reparenting.
3867 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3874 /* We take this opportunity to invalidate any queue redraw entry
3875 * associated with the actor and descendants since we won't be able to
3876 * determine the appropriate stage after this.
3878 * we do this after we updated the mapped state because actors might
3879 * end up queueing redraws inside their mapped/unmapped virtual
3880 * functions, and if we invalidate the redraw entry we could end up
3881 * with an inconsistent state and weird memory corruption. see
3884 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3885 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3887 _clutter_actor_traverse (child,
3889 invalidate_queue_redraw_entry,
3894 old_first = self->priv->first_child;
3895 old_last = self->priv->last_child;
3897 remove_child (self, child);
3899 self->priv->n_children -= 1;
3901 self->priv->age += 1;
3903 /* clutter_actor_reparent() will emit ::parent-set for us */
3904 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3905 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3907 /* if the child was mapped then we need to relayout ourselves to account
3908 * for the removed child
3911 clutter_actor_queue_relayout (self);
3913 /* we need to emit the signal before dropping the reference */
3914 if (emit_actor_removed)
3915 g_signal_emit_by_name (self, "actor-removed", child);
3917 if (notify_first_last)
3919 if (old_first != self->priv->first_child)
3920 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3922 if (old_last != self->priv->last_child)
3923 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3926 g_object_thaw_notify (G_OBJECT (self));
3928 /* remove the reference we acquired in clutter_actor_add_child() */
3929 g_object_unref (child);
3932 static const ClutterTransformInfo default_transform_info = {
3933 0.0, { 0, }, /* rotation-x */
3934 0.0, { 0, }, /* rotation-y */
3935 0.0, { 0, }, /* rotation-z */
3937 1.0, 1.0, { 0, }, /* scale */
3939 { 0, }, /* anchor */
3945 * _clutter_actor_get_transform_info_or_defaults:
3946 * @self: a #ClutterActor
3948 * Retrieves the ClutterTransformInfo structure associated to an actor.
3950 * If the actor does not have a ClutterTransformInfo structure associated
3951 * to it, then the default structure will be returned.
3953 * This function should only be used for getters.
3955 * Return value: a const pointer to the ClutterTransformInfo structure
3957 const ClutterTransformInfo *
3958 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3960 ClutterTransformInfo *info;
3962 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3966 return &default_transform_info;
3970 clutter_transform_info_free (gpointer data)
3973 g_slice_free (ClutterTransformInfo, data);
3977 * _clutter_actor_get_transform_info:
3978 * @self: a #ClutterActor
3980 * Retrieves a pointer to the ClutterTransformInfo structure.
3982 * If the actor does not have a ClutterTransformInfo associated to it, one
3983 * will be created and initialized to the default values.
3985 * This function should be used for setters.
3987 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3990 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3993 ClutterTransformInfo *
3994 _clutter_actor_get_transform_info (ClutterActor *self)
3996 ClutterTransformInfo *info;
3998 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4001 info = g_slice_new (ClutterTransformInfo);
4003 *info = default_transform_info;
4005 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4007 clutter_transform_info_free);
4014 * clutter_actor_set_rotation_angle_internal:
4015 * @self: a #ClutterActor
4016 * @axis: the axis of the angle to change
4017 * @angle: the angle of rotation
4019 * Sets the rotation angle on the given axis without affecting the
4020 * rotation center point.
4023 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4024 ClutterRotateAxis axis,
4027 GObject *obj = G_OBJECT (self);
4028 ClutterTransformInfo *info;
4030 info = _clutter_actor_get_transform_info (self);
4032 g_object_freeze_notify (obj);
4036 case CLUTTER_X_AXIS:
4037 info->rx_angle = angle;
4038 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4041 case CLUTTER_Y_AXIS:
4042 info->ry_angle = angle;
4043 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4046 case CLUTTER_Z_AXIS:
4047 info->rz_angle = angle;
4048 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4052 self->priv->transform_valid = FALSE;
4054 g_object_thaw_notify (obj);
4056 clutter_actor_queue_redraw (self);
4060 clutter_actor_set_rotation_angle (ClutterActor *self,
4061 ClutterRotateAxis axis,
4064 const ClutterTransformInfo *info;
4065 const double *cur_angle_p = NULL;
4066 GParamSpec *pspec = NULL;
4068 info = _clutter_actor_get_transform_info_or_defaults (self);
4072 case CLUTTER_X_AXIS:
4073 cur_angle_p = &info->rx_angle;
4074 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4077 case CLUTTER_Y_AXIS:
4078 cur_angle_p = &info->ry_angle;
4079 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4082 case CLUTTER_Z_AXIS:
4083 cur_angle_p = &info->rz_angle;
4084 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4088 g_assert (pspec != NULL);
4089 g_assert (cur_angle_p != NULL);
4091 if (_clutter_actor_get_transition (self, pspec) == NULL)
4092 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4094 _clutter_actor_update_transition (self, pspec, angle);
4096 clutter_actor_queue_redraw (self);
4100 * clutter_actor_set_rotation_center_internal:
4101 * @self: a #ClutterActor
4102 * @axis: the axis of the center to change
4103 * @center: the coordinates of the rotation center
4105 * Sets the rotation center on the given axis without affecting the
4109 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4110 ClutterRotateAxis axis,
4111 const ClutterVertex *center)
4113 GObject *obj = G_OBJECT (self);
4114 ClutterTransformInfo *info;
4115 ClutterVertex v = { 0, 0, 0 };
4117 info = _clutter_actor_get_transform_info (self);
4122 g_object_freeze_notify (obj);
4126 case CLUTTER_X_AXIS:
4127 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4128 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4131 case CLUTTER_Y_AXIS:
4132 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4133 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4136 case CLUTTER_Z_AXIS:
4137 /* if the previously set rotation center was fractional, then
4138 * setting explicit coordinates will have to notify the
4139 * :rotation-center-z-gravity property as well
4141 if (info->rz_center.is_fractional)
4142 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4144 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4145 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4149 self->priv->transform_valid = FALSE;
4151 g_object_thaw_notify (obj);
4153 clutter_actor_queue_redraw (self);
4157 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4161 GObject *obj = G_OBJECT (self);
4162 ClutterTransformInfo *info;
4164 info = _clutter_actor_get_transform_info (self);
4166 if (pspec == obj_props[PROP_SCALE_X])
4167 info->scale_x = factor;
4169 info->scale_y = factor;
4171 self->priv->transform_valid = FALSE;
4172 clutter_actor_queue_redraw (self);
4173 g_object_notify_by_pspec (obj, pspec);
4177 clutter_actor_set_scale_factor (ClutterActor *self,
4178 ClutterRotateAxis axis,
4181 const ClutterTransformInfo *info;
4182 const double *scale_p = NULL;
4183 GParamSpec *pspec = NULL;
4185 info = _clutter_actor_get_transform_info_or_defaults (self);
4189 case CLUTTER_X_AXIS:
4190 pspec = obj_props[PROP_SCALE_X];
4191 scale_p = &info->scale_x;
4194 case CLUTTER_Y_AXIS:
4195 pspec = obj_props[PROP_SCALE_Y];
4196 scale_p = &info->scale_y;
4199 case CLUTTER_Z_AXIS:
4203 g_assert (pspec != NULL);
4204 g_assert (scale_p != NULL);
4206 if (_clutter_actor_get_transition (self, pspec) == NULL)
4207 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4209 _clutter_actor_update_transition (self, pspec, factor);
4211 clutter_actor_queue_redraw (self);
4215 clutter_actor_set_scale_center (ClutterActor *self,
4216 ClutterRotateAxis axis,
4219 GObject *obj = G_OBJECT (self);
4220 ClutterTransformInfo *info;
4221 gfloat center_x, center_y;
4223 info = _clutter_actor_get_transform_info (self);
4225 g_object_freeze_notify (obj);
4227 /* get the current scale center coordinates */
4228 clutter_anchor_coord_get_units (self, &info->scale_center,
4233 /* we need to notify this too, because setting explicit coordinates will
4234 * change the gravity as a side effect
4236 if (info->scale_center.is_fractional)
4237 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4241 case CLUTTER_X_AXIS:
4242 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4243 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4246 case CLUTTER_Y_AXIS:
4247 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4248 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4252 g_assert_not_reached ();
4255 self->priv->transform_valid = FALSE;
4257 clutter_actor_queue_redraw (self);
4259 g_object_thaw_notify (obj);
4263 clutter_actor_set_scale_gravity (ClutterActor *self,
4264 ClutterGravity gravity)
4266 ClutterTransformInfo *info;
4269 info = _clutter_actor_get_transform_info (self);
4270 obj = G_OBJECT (self);
4272 if (gravity == CLUTTER_GRAVITY_NONE)
4273 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4275 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4277 self->priv->transform_valid = FALSE;
4279 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4280 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4281 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4283 clutter_actor_queue_redraw (self);
4287 clutter_actor_set_anchor_coord (ClutterActor *self,
4288 ClutterRotateAxis axis,
4291 GObject *obj = G_OBJECT (self);
4292 ClutterTransformInfo *info;
4293 gfloat anchor_x, anchor_y;
4295 info = _clutter_actor_get_transform_info (self);
4297 g_object_freeze_notify (obj);
4299 clutter_anchor_coord_get_units (self, &info->anchor,
4304 if (info->anchor.is_fractional)
4305 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4309 case CLUTTER_X_AXIS:
4310 clutter_anchor_coord_set_units (&info->anchor,
4314 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4317 case CLUTTER_Y_AXIS:
4318 clutter_anchor_coord_set_units (&info->anchor,
4322 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4326 g_assert_not_reached ();
4329 self->priv->transform_valid = FALSE;
4331 clutter_actor_queue_redraw (self);
4333 g_object_thaw_notify (obj);
4337 clutter_actor_set_property (GObject *object,
4339 const GValue *value,
4342 ClutterActor *actor = CLUTTER_ACTOR (object);
4343 ClutterActorPrivate *priv = actor->priv;
4348 clutter_actor_set_x (actor, g_value_get_float (value));
4352 clutter_actor_set_y (actor, g_value_get_float (value));
4357 const ClutterPoint *pos = g_value_get_boxed (value);
4360 clutter_actor_set_position (actor, pos->x, pos->y);
4362 clutter_actor_set_fixed_position_set (actor, FALSE);
4367 clutter_actor_set_width (actor, g_value_get_float (value));
4371 clutter_actor_set_height (actor, g_value_get_float (value));
4376 const ClutterSize *size = g_value_get_boxed (value);
4379 clutter_actor_set_size (actor, size->width, size->height);
4381 clutter_actor_set_size (actor, -1, -1);
4386 clutter_actor_set_x (actor, g_value_get_float (value));
4390 clutter_actor_set_y (actor, g_value_get_float (value));
4393 case PROP_FIXED_POSITION_SET:
4394 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4397 case PROP_MIN_WIDTH:
4398 clutter_actor_set_min_width (actor, g_value_get_float (value));
4401 case PROP_MIN_HEIGHT:
4402 clutter_actor_set_min_height (actor, g_value_get_float (value));
4405 case PROP_NATURAL_WIDTH:
4406 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4409 case PROP_NATURAL_HEIGHT:
4410 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4413 case PROP_MIN_WIDTH_SET:
4414 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4417 case PROP_MIN_HEIGHT_SET:
4418 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4421 case PROP_NATURAL_WIDTH_SET:
4422 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4425 case PROP_NATURAL_HEIGHT_SET:
4426 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4429 case PROP_REQUEST_MODE:
4430 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4434 clutter_actor_set_depth (actor, g_value_get_float (value));
4438 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4441 case PROP_OFFSCREEN_REDIRECT:
4442 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4446 clutter_actor_set_name (actor, g_value_get_string (value));
4450 if (g_value_get_boolean (value) == TRUE)
4451 clutter_actor_show (actor);
4453 clutter_actor_hide (actor);
4457 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4458 g_value_get_double (value));
4462 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4463 g_value_get_double (value));
4466 case PROP_SCALE_CENTER_X:
4467 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4468 g_value_get_float (value));
4471 case PROP_SCALE_CENTER_Y:
4472 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4473 g_value_get_float (value));
4476 case PROP_SCALE_GRAVITY:
4477 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4482 const ClutterGeometry *geom = g_value_get_boxed (value);
4484 clutter_actor_set_clip (actor,
4486 geom->width, geom->height);
4490 case PROP_CLIP_TO_ALLOCATION:
4491 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4495 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4498 case PROP_ROTATION_ANGLE_X:
4499 clutter_actor_set_rotation_angle (actor,
4501 g_value_get_double (value));
4504 case PROP_ROTATION_ANGLE_Y:
4505 clutter_actor_set_rotation_angle (actor,
4507 g_value_get_double (value));
4510 case PROP_ROTATION_ANGLE_Z:
4511 clutter_actor_set_rotation_angle (actor,
4513 g_value_get_double (value));
4516 case PROP_ROTATION_CENTER_X:
4517 clutter_actor_set_rotation_center_internal (actor,
4519 g_value_get_boxed (value));
4522 case PROP_ROTATION_CENTER_Y:
4523 clutter_actor_set_rotation_center_internal (actor,
4525 g_value_get_boxed (value));
4528 case PROP_ROTATION_CENTER_Z:
4529 clutter_actor_set_rotation_center_internal (actor,
4531 g_value_get_boxed (value));
4534 case PROP_ROTATION_CENTER_Z_GRAVITY:
4536 const ClutterTransformInfo *info;
4538 info = _clutter_actor_get_transform_info_or_defaults (actor);
4539 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4540 g_value_get_enum (value));
4545 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4546 g_value_get_float (value));
4550 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4551 g_value_get_float (value));
4554 case PROP_ANCHOR_GRAVITY:
4555 clutter_actor_set_anchor_point_from_gravity (actor,
4556 g_value_get_enum (value));
4559 case PROP_SHOW_ON_SET_PARENT:
4560 priv->show_on_set_parent = g_value_get_boolean (value);
4563 case PROP_TEXT_DIRECTION:
4564 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4568 clutter_actor_add_action (actor, g_value_get_object (value));
4571 case PROP_CONSTRAINTS:
4572 clutter_actor_add_constraint (actor, g_value_get_object (value));
4576 clutter_actor_add_effect (actor, g_value_get_object (value));
4579 case PROP_LAYOUT_MANAGER:
4580 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4584 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4588 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4591 case PROP_MARGIN_TOP:
4592 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4595 case PROP_MARGIN_BOTTOM:
4596 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4599 case PROP_MARGIN_LEFT:
4600 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4603 case PROP_MARGIN_RIGHT:
4604 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4607 case PROP_BACKGROUND_COLOR:
4608 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4612 clutter_actor_set_content (actor, g_value_get_object (value));
4615 case PROP_CONTENT_GRAVITY:
4616 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4619 case PROP_MINIFICATION_FILTER:
4620 clutter_actor_set_content_scaling_filters (actor,
4621 g_value_get_enum (value),
4622 actor->priv->mag_filter);
4625 case PROP_MAGNIFICATION_FILTER:
4626 clutter_actor_set_content_scaling_filters (actor,
4627 actor->priv->min_filter,
4628 g_value_get_enum (value));
4632 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4638 clutter_actor_get_property (GObject *object,
4643 ClutterActor *actor = CLUTTER_ACTOR (object);
4644 ClutterActorPrivate *priv = actor->priv;
4649 g_value_set_float (value, clutter_actor_get_x (actor));
4653 g_value_set_float (value, clutter_actor_get_y (actor));
4658 ClutterPoint position;
4660 clutter_point_init (&position,
4661 clutter_actor_get_x (actor),
4662 clutter_actor_get_y (actor));
4663 g_value_set_boxed (value, &position);
4668 g_value_set_float (value, clutter_actor_get_width (actor));
4672 g_value_set_float (value, clutter_actor_get_height (actor));
4679 clutter_size_init (&size,
4680 clutter_actor_get_width (actor),
4681 clutter_actor_get_height (actor));
4682 g_value_set_boxed (value, &size);
4688 const ClutterLayoutInfo *info;
4690 info = _clutter_actor_get_layout_info_or_defaults (actor);
4691 g_value_set_float (value, info->fixed_pos.x);
4697 const ClutterLayoutInfo *info;
4699 info = _clutter_actor_get_layout_info_or_defaults (actor);
4700 g_value_set_float (value, info->fixed_pos.y);
4704 case PROP_FIXED_POSITION_SET:
4705 g_value_set_boolean (value, priv->position_set);
4708 case PROP_MIN_WIDTH:
4710 const ClutterLayoutInfo *info;
4712 info = _clutter_actor_get_layout_info_or_defaults (actor);
4713 g_value_set_float (value, info->minimum.width);
4717 case PROP_MIN_HEIGHT:
4719 const ClutterLayoutInfo *info;
4721 info = _clutter_actor_get_layout_info_or_defaults (actor);
4722 g_value_set_float (value, info->minimum.height);
4726 case PROP_NATURAL_WIDTH:
4728 const ClutterLayoutInfo *info;
4730 info = _clutter_actor_get_layout_info_or_defaults (actor);
4731 g_value_set_float (value, info->natural.width);
4735 case PROP_NATURAL_HEIGHT:
4737 const ClutterLayoutInfo *info;
4739 info = _clutter_actor_get_layout_info_or_defaults (actor);
4740 g_value_set_float (value, info->natural.height);
4744 case PROP_MIN_WIDTH_SET:
4745 g_value_set_boolean (value, priv->min_width_set);
4748 case PROP_MIN_HEIGHT_SET:
4749 g_value_set_boolean (value, priv->min_height_set);
4752 case PROP_NATURAL_WIDTH_SET:
4753 g_value_set_boolean (value, priv->natural_width_set);
4756 case PROP_NATURAL_HEIGHT_SET:
4757 g_value_set_boolean (value, priv->natural_height_set);
4760 case PROP_REQUEST_MODE:
4761 g_value_set_enum (value, priv->request_mode);
4764 case PROP_ALLOCATION:
4765 g_value_set_boxed (value, &priv->allocation);
4769 g_value_set_float (value, clutter_actor_get_depth (actor));
4773 g_value_set_uint (value, priv->opacity);
4776 case PROP_OFFSCREEN_REDIRECT:
4777 g_value_set_enum (value, priv->offscreen_redirect);
4781 g_value_set_string (value, priv->name);
4785 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4789 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4793 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4797 g_value_set_boolean (value, priv->has_clip);
4802 ClutterGeometry clip;
4804 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4805 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4806 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4807 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4809 g_value_set_boxed (value, &clip);
4813 case PROP_CLIP_TO_ALLOCATION:
4814 g_value_set_boolean (value, priv->clip_to_allocation);
4819 const ClutterTransformInfo *info;
4821 info = _clutter_actor_get_transform_info_or_defaults (actor);
4822 g_value_set_double (value, info->scale_x);
4828 const ClutterTransformInfo *info;
4830 info = _clutter_actor_get_transform_info_or_defaults (actor);
4831 g_value_set_double (value, info->scale_y);
4835 case PROP_SCALE_CENTER_X:
4839 clutter_actor_get_scale_center (actor, ¢er, NULL);
4841 g_value_set_float (value, center);
4845 case PROP_SCALE_CENTER_Y:
4849 clutter_actor_get_scale_center (actor, NULL, ¢er);
4851 g_value_set_float (value, center);
4855 case PROP_SCALE_GRAVITY:
4856 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4860 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4863 case PROP_ROTATION_ANGLE_X:
4865 const ClutterTransformInfo *info;
4867 info = _clutter_actor_get_transform_info_or_defaults (actor);
4868 g_value_set_double (value, info->rx_angle);
4872 case PROP_ROTATION_ANGLE_Y:
4874 const ClutterTransformInfo *info;
4876 info = _clutter_actor_get_transform_info_or_defaults (actor);
4877 g_value_set_double (value, info->ry_angle);
4881 case PROP_ROTATION_ANGLE_Z:
4883 const ClutterTransformInfo *info;
4885 info = _clutter_actor_get_transform_info_or_defaults (actor);
4886 g_value_set_double (value, info->rz_angle);
4890 case PROP_ROTATION_CENTER_X:
4892 ClutterVertex center;
4894 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4899 g_value_set_boxed (value, ¢er);
4903 case PROP_ROTATION_CENTER_Y:
4905 ClutterVertex center;
4907 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4912 g_value_set_boxed (value, ¢er);
4916 case PROP_ROTATION_CENTER_Z:
4918 ClutterVertex center;
4920 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4925 g_value_set_boxed (value, ¢er);
4929 case PROP_ROTATION_CENTER_Z_GRAVITY:
4930 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4935 const ClutterTransformInfo *info;
4938 info = _clutter_actor_get_transform_info_or_defaults (actor);
4939 clutter_anchor_coord_get_units (actor, &info->anchor,
4943 g_value_set_float (value, anchor_x);
4949 const ClutterTransformInfo *info;
4952 info = _clutter_actor_get_transform_info_or_defaults (actor);
4953 clutter_anchor_coord_get_units (actor, &info->anchor,
4957 g_value_set_float (value, anchor_y);
4961 case PROP_ANCHOR_GRAVITY:
4962 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4965 case PROP_SHOW_ON_SET_PARENT:
4966 g_value_set_boolean (value, priv->show_on_set_parent);
4969 case PROP_TEXT_DIRECTION:
4970 g_value_set_enum (value, priv->text_direction);
4973 case PROP_HAS_POINTER:
4974 g_value_set_boolean (value, priv->has_pointer);
4977 case PROP_LAYOUT_MANAGER:
4978 g_value_set_object (value, priv->layout_manager);
4983 const ClutterLayoutInfo *info;
4985 info = _clutter_actor_get_layout_info_or_defaults (actor);
4986 g_value_set_enum (value, info->x_align);
4992 const ClutterLayoutInfo *info;
4994 info = _clutter_actor_get_layout_info_or_defaults (actor);
4995 g_value_set_enum (value, info->y_align);
4999 case PROP_MARGIN_TOP:
5001 const ClutterLayoutInfo *info;
5003 info = _clutter_actor_get_layout_info_or_defaults (actor);
5004 g_value_set_float (value, info->margin.top);
5008 case PROP_MARGIN_BOTTOM:
5010 const ClutterLayoutInfo *info;
5012 info = _clutter_actor_get_layout_info_or_defaults (actor);
5013 g_value_set_float (value, info->margin.bottom);
5017 case PROP_MARGIN_LEFT:
5019 const ClutterLayoutInfo *info;
5021 info = _clutter_actor_get_layout_info_or_defaults (actor);
5022 g_value_set_float (value, info->margin.left);
5026 case PROP_MARGIN_RIGHT:
5028 const ClutterLayoutInfo *info;
5030 info = _clutter_actor_get_layout_info_or_defaults (actor);
5031 g_value_set_float (value, info->margin.right);
5035 case PROP_BACKGROUND_COLOR_SET:
5036 g_value_set_boolean (value, priv->bg_color_set);
5039 case PROP_BACKGROUND_COLOR:
5040 g_value_set_boxed (value, &priv->bg_color);
5043 case PROP_FIRST_CHILD:
5044 g_value_set_object (value, priv->first_child);
5047 case PROP_LAST_CHILD:
5048 g_value_set_object (value, priv->last_child);
5052 g_value_set_object (value, priv->content);
5055 case PROP_CONTENT_GRAVITY:
5056 g_value_set_enum (value, priv->content_gravity);
5059 case PROP_CONTENT_BOX:
5061 ClutterActorBox box = { 0, };
5063 clutter_actor_get_content_box (actor, &box);
5064 g_value_set_boxed (value, &box);
5068 case PROP_MINIFICATION_FILTER:
5069 g_value_set_enum (value, priv->min_filter);
5072 case PROP_MAGNIFICATION_FILTER:
5073 g_value_set_enum (value, priv->mag_filter);
5077 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5083 clutter_actor_dispose (GObject *object)
5085 ClutterActor *self = CLUTTER_ACTOR (object);
5086 ClutterActorPrivate *priv = self->priv;
5088 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5090 g_type_name (G_OBJECT_TYPE (self)),
5093 g_signal_emit (self, actor_signals[DESTROY], 0);
5095 /* avoid recursing when called from clutter_actor_destroy() */
5096 if (priv->parent != NULL)
5098 ClutterActor *parent = priv->parent;
5100 /* go through the Container implementation unless this
5101 * is an internal child and has been marked as such.
5103 * removing the actor from its parent will reset the
5104 * realized and mapped states.
5106 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5107 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5109 clutter_actor_remove_child_internal (parent, self,
5110 REMOVE_CHILD_LEGACY_FLAGS);
5113 /* parent must be gone at this point */
5114 g_assert (priv->parent == NULL);
5116 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5118 /* can't be mapped or realized with no parent */
5119 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5120 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5123 g_clear_object (&priv->pango_context);
5124 g_clear_object (&priv->actions);
5125 g_clear_object (&priv->constraints);
5126 g_clear_object (&priv->effects);
5127 g_clear_object (&priv->flatten_effect);
5129 if (priv->layout_manager != NULL)
5131 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5132 g_clear_object (&priv->layout_manager);
5135 if (priv->content != NULL)
5137 _clutter_content_detached (priv->content, self);
5138 g_clear_object (&priv->content);
5141 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5145 clutter_actor_finalize (GObject *object)
5147 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5149 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5150 priv->name != NULL ? priv->name : "<none>",
5152 g_type_name (G_OBJECT_TYPE (object)));
5154 _clutter_context_release_id (priv->id);
5156 g_free (priv->name);
5158 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5163 * clutter_actor_get_accessible:
5164 * @self: a #ClutterActor
5166 * Returns the accessible object that describes the actor to an
5167 * assistive technology.
5169 * If no class-specific #AtkObject implementation is available for the
5170 * actor instance in question, it will inherit an #AtkObject
5171 * implementation from the first ancestor class for which such an
5172 * implementation is defined.
5174 * The documentation of the <ulink
5175 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5176 * library contains more information about accessible objects and
5179 * Returns: (transfer none): the #AtkObject associated with @actor
5182 clutter_actor_get_accessible (ClutterActor *self)
5184 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5186 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5190 clutter_actor_real_get_accessible (ClutterActor *actor)
5192 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5196 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5198 AtkObject *accessible;
5200 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5201 if (accessible != NULL)
5202 g_object_ref (accessible);
5208 atk_implementor_iface_init (AtkImplementorIface *iface)
5210 iface->ref_accessible = _clutter_actor_ref_accessible;
5214 clutter_actor_update_default_paint_volume (ClutterActor *self,
5215 ClutterPaintVolume *volume)
5217 ClutterActorPrivate *priv = self->priv;
5218 gboolean res = TRUE;
5220 /* we start from the allocation */
5221 clutter_paint_volume_set_width (volume,
5222 priv->allocation.x2 - priv->allocation.x1);
5223 clutter_paint_volume_set_height (volume,
5224 priv->allocation.y2 - priv->allocation.y1);
5226 /* if the actor has a clip set then we have a pretty definite
5227 * size for the paint volume: the actor cannot possibly paint
5228 * outside the clip region.
5230 if (priv->clip_to_allocation)
5232 /* the allocation has already been set, so we just flip the
5239 ClutterActor *child;
5241 if (priv->has_clip &&
5242 priv->clip.width >= 0 &&
5243 priv->clip.height >= 0)
5245 ClutterVertex origin;
5247 origin.x = priv->clip.x;
5248 origin.y = priv->clip.y;
5251 clutter_paint_volume_set_origin (volume, &origin);
5252 clutter_paint_volume_set_width (volume, priv->clip.width);
5253 clutter_paint_volume_set_height (volume, priv->clip.height);
5258 /* if we don't have children we just bail out here... */
5259 if (priv->n_children == 0)
5262 /* ...but if we have children then we ask for their paint volume in
5263 * our coordinates. if any of our children replies that it doesn't
5264 * have a paint volume, we bail out
5266 for (child = priv->first_child;
5268 child = child->priv->next_sibling)
5270 const ClutterPaintVolume *child_volume;
5272 if (!CLUTTER_ACTOR_IS_MAPPED (child))
5275 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5276 if (child_volume == NULL)
5282 clutter_paint_volume_union (volume, child_volume);
5292 clutter_actor_real_get_paint_volume (ClutterActor *self,
5293 ClutterPaintVolume *volume)
5295 ClutterActorClass *klass;
5298 klass = CLUTTER_ACTOR_GET_CLASS (self);
5300 /* XXX - this thoroughly sucks, but we don't want to penalize users
5301 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5302 * redraw. This should go away in 2.0.
5304 if (klass->paint == clutter_actor_real_paint &&
5305 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5311 /* this is the default return value: we cannot know if a class
5312 * is going to paint outside its allocation, so we take the
5313 * conservative approach.
5318 /* update_default_paint_volume() should only fail if one of the children
5319 * reported an invalid, or no, paint volume
5321 if (!clutter_actor_update_default_paint_volume (self, volume))
5328 * clutter_actor_get_default_paint_volume:
5329 * @self: a #ClutterActor
5331 * Retrieves the default paint volume for @self.
5333 * This function provides the same #ClutterPaintVolume that would be
5334 * computed by the default implementation inside #ClutterActor of the
5335 * #ClutterActorClass.get_paint_volume() virtual function.
5337 * This function should only be used by #ClutterActor subclasses that
5338 * cannot chain up to the parent implementation when computing their
5341 * Return value: (transfer none): a pointer to the default
5342 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5343 * the actor could not compute a valid paint volume. The returned value
5344 * is not guaranteed to be stable across multiple frames, so if you
5345 * want to retain it, you will need to copy it using
5346 * clutter_paint_volume_copy().
5350 const ClutterPaintVolume *
5351 clutter_actor_get_default_paint_volume (ClutterActor *self)
5353 ClutterPaintVolume volume;
5354 ClutterPaintVolume *res;
5356 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5359 _clutter_paint_volume_init_static (&volume, self);
5360 if (clutter_actor_update_default_paint_volume (self, &volume))
5362 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5366 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5367 _clutter_paint_volume_copy_static (&volume, res);
5371 clutter_paint_volume_free (&volume);
5377 clutter_actor_real_has_overlaps (ClutterActor *self)
5379 /* By default we'll assume that all actors need an offscreen redirect to get
5380 * the correct opacity. Actors such as ClutterTexture that would never need
5381 * an offscreen redirect can override this to return FALSE. */
5386 clutter_actor_real_destroy (ClutterActor *actor)
5388 ClutterActorIter iter;
5390 g_object_freeze_notify (G_OBJECT (actor));
5392 clutter_actor_iter_init (&iter, actor);
5393 while (clutter_actor_iter_next (&iter, NULL))
5394 clutter_actor_iter_destroy (&iter);
5396 g_object_thaw_notify (G_OBJECT (actor));
5400 clutter_actor_constructor (GType gtype,
5402 GObjectConstructParam *props)
5404 GObjectClass *gobject_class;
5408 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5409 retval = gobject_class->constructor (gtype, n_props, props);
5410 self = CLUTTER_ACTOR (retval);
5412 if (self->priv->layout_manager == NULL)
5414 ClutterLayoutManager *default_layout;
5416 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5418 default_layout = clutter_fixed_layout_new ();
5419 clutter_actor_set_layout_manager (self, default_layout);
5426 clutter_actor_class_init (ClutterActorClass *klass)
5428 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5430 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5431 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5432 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5433 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5435 object_class->constructor = clutter_actor_constructor;
5436 object_class->set_property = clutter_actor_set_property;
5437 object_class->get_property = clutter_actor_get_property;
5438 object_class->dispose = clutter_actor_dispose;
5439 object_class->finalize = clutter_actor_finalize;
5441 klass->show = clutter_actor_real_show;
5442 klass->show_all = clutter_actor_show;
5443 klass->hide = clutter_actor_real_hide;
5444 klass->hide_all = clutter_actor_hide;
5445 klass->map = clutter_actor_real_map;
5446 klass->unmap = clutter_actor_real_unmap;
5447 klass->unrealize = clutter_actor_real_unrealize;
5448 klass->pick = clutter_actor_real_pick;
5449 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5450 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5451 klass->allocate = clutter_actor_real_allocate;
5452 klass->queue_redraw = clutter_actor_real_queue_redraw;
5453 klass->queue_relayout = clutter_actor_real_queue_relayout;
5454 klass->apply_transform = clutter_actor_real_apply_transform;
5455 klass->get_accessible = clutter_actor_real_get_accessible;
5456 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5457 klass->has_overlaps = clutter_actor_real_has_overlaps;
5458 klass->paint = clutter_actor_real_paint;
5459 klass->destroy = clutter_actor_real_destroy;
5461 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5466 * X coordinate of the actor in pixels. If written, forces a fixed
5467 * position for the actor. If read, returns the fixed position if any,
5468 * otherwise the allocation if available, otherwise 0.
5470 * The #ClutterActor:x property is animatable.
5473 g_param_spec_float ("x",
5475 P_("X coordinate of the actor"),
5476 -G_MAXFLOAT, G_MAXFLOAT,
5479 G_PARAM_STATIC_STRINGS |
5480 CLUTTER_PARAM_ANIMATABLE);
5485 * Y coordinate of the actor in pixels. If written, forces a fixed
5486 * position for the actor. If read, returns the fixed position if
5487 * any, otherwise the allocation if available, otherwise 0.
5489 * The #ClutterActor:y property is animatable.
5492 g_param_spec_float ("y",
5494 P_("Y coordinate of the actor"),
5495 -G_MAXFLOAT, G_MAXFLOAT,
5498 G_PARAM_STATIC_STRINGS |
5499 CLUTTER_PARAM_ANIMATABLE);
5502 * ClutterActor:position:
5504 * The position of the origin of the actor.
5506 * This property is a shorthand for setting and getting the
5507 * #ClutterActor:x and #ClutterActor:y properties at the same
5510 * The #ClutterActor:position property is animatable.
5514 obj_props[PROP_POSITION] =
5515 g_param_spec_boxed ("position",
5517 P_("The position of the origin of the actor"),
5520 G_PARAM_STATIC_STRINGS |
5521 CLUTTER_PARAM_ANIMATABLE);
5524 * ClutterActor:width:
5526 * Width of the actor (in pixels). If written, forces the minimum and
5527 * natural size request of the actor to the given width. If read, returns
5528 * the allocated width if available, otherwise the width request.
5530 * The #ClutterActor:width property is animatable.
5532 obj_props[PROP_WIDTH] =
5533 g_param_spec_float ("width",
5535 P_("Width of the actor"),
5539 G_PARAM_STATIC_STRINGS |
5540 CLUTTER_PARAM_ANIMATABLE);
5543 * ClutterActor:height:
5545 * Height of the actor (in pixels). If written, forces the minimum and
5546 * natural size request of the actor to the given height. If read, returns
5547 * the allocated height if available, otherwise the height request.
5549 * The #ClutterActor:height property is animatable.
5551 obj_props[PROP_HEIGHT] =
5552 g_param_spec_float ("height",
5554 P_("Height of the actor"),
5558 G_PARAM_STATIC_STRINGS |
5559 CLUTTER_PARAM_ANIMATABLE);
5562 * ClutterActor:size:
5564 * The size of the actor.
5566 * This property is a shorthand for setting and getting the
5567 * #ClutterActor:width and #ClutterActor:height at the same time.
5569 * The #ClutterActor:size property is animatable.
5573 obj_props[PROP_SIZE] =
5574 g_param_spec_boxed ("size",
5576 P_("The size of the actor"),
5579 G_PARAM_STATIC_STRINGS |
5580 CLUTTER_PARAM_ANIMATABLE);
5583 * ClutterActor:fixed-x:
5585 * The fixed X position of the actor in pixels.
5587 * Writing this property sets #ClutterActor:fixed-position-set
5588 * property as well, as a side effect
5592 obj_props[PROP_FIXED_X] =
5593 g_param_spec_float ("fixed-x",
5595 P_("Forced X position of the actor"),
5596 -G_MAXFLOAT, G_MAXFLOAT,
5598 CLUTTER_PARAM_READWRITE);
5601 * ClutterActor:fixed-y:
5603 * The fixed Y position of the actor in pixels.
5605 * Writing this property sets the #ClutterActor:fixed-position-set
5606 * property as well, as a side effect
5610 obj_props[PROP_FIXED_Y] =
5611 g_param_spec_float ("fixed-y",
5613 P_("Forced Y position of the actor"),
5614 -G_MAXFLOAT, G_MAXFLOAT,
5616 CLUTTER_PARAM_READWRITE);
5619 * ClutterActor:fixed-position-set:
5621 * This flag controls whether the #ClutterActor:fixed-x and
5622 * #ClutterActor:fixed-y properties are used
5626 obj_props[PROP_FIXED_POSITION_SET] =
5627 g_param_spec_boolean ("fixed-position-set",
5628 P_("Fixed position set"),
5629 P_("Whether to use fixed positioning for the actor"),
5631 CLUTTER_PARAM_READWRITE);
5634 * ClutterActor:min-width:
5636 * A forced minimum width request for the actor, in pixels
5638 * Writing this property sets the #ClutterActor:min-width-set property
5639 * as well, as a side effect.
5641 *This property overrides the usual width request of the actor.
5645 obj_props[PROP_MIN_WIDTH] =
5646 g_param_spec_float ("min-width",
5648 P_("Forced minimum width request for the actor"),
5651 CLUTTER_PARAM_READWRITE);
5654 * ClutterActor:min-height:
5656 * A forced minimum height request for the actor, in pixels
5658 * Writing this property sets the #ClutterActor:min-height-set property
5659 * as well, as a side effect. This property overrides the usual height
5660 * request of the actor.
5664 obj_props[PROP_MIN_HEIGHT] =
5665 g_param_spec_float ("min-height",
5667 P_("Forced minimum height request for the actor"),
5670 CLUTTER_PARAM_READWRITE);
5673 * ClutterActor:natural-width:
5675 * A forced natural width request for the actor, in pixels
5677 * Writing this property sets the #ClutterActor:natural-width-set
5678 * property as well, as a side effect. This property overrides the
5679 * usual width request of the actor
5683 obj_props[PROP_NATURAL_WIDTH] =
5684 g_param_spec_float ("natural-width",
5685 P_("Natural Width"),
5686 P_("Forced natural width request for the actor"),
5689 CLUTTER_PARAM_READWRITE);
5692 * ClutterActor:natural-height:
5694 * A forced natural height request for the actor, in pixels
5696 * Writing this property sets the #ClutterActor:natural-height-set
5697 * property as well, as a side effect. This property overrides the
5698 * usual height request of the actor
5702 obj_props[PROP_NATURAL_HEIGHT] =
5703 g_param_spec_float ("natural-height",
5704 P_("Natural Height"),
5705 P_("Forced natural height request for the actor"),
5708 CLUTTER_PARAM_READWRITE);
5711 * ClutterActor:min-width-set:
5713 * This flag controls whether the #ClutterActor:min-width property
5718 obj_props[PROP_MIN_WIDTH_SET] =
5719 g_param_spec_boolean ("min-width-set",
5720 P_("Minimum width set"),
5721 P_("Whether to use the min-width property"),
5723 CLUTTER_PARAM_READWRITE);
5726 * ClutterActor:min-height-set:
5728 * This flag controls whether the #ClutterActor:min-height property
5733 obj_props[PROP_MIN_HEIGHT_SET] =
5734 g_param_spec_boolean ("min-height-set",
5735 P_("Minimum height set"),
5736 P_("Whether to use the min-height property"),
5738 CLUTTER_PARAM_READWRITE);
5741 * ClutterActor:natural-width-set:
5743 * This flag controls whether the #ClutterActor:natural-width property
5748 obj_props[PROP_NATURAL_WIDTH_SET] =
5749 g_param_spec_boolean ("natural-width-set",
5750 P_("Natural width set"),
5751 P_("Whether to use the natural-width property"),
5753 CLUTTER_PARAM_READWRITE);
5756 * ClutterActor:natural-height-set:
5758 * This flag controls whether the #ClutterActor:natural-height property
5763 obj_props[PROP_NATURAL_HEIGHT_SET] =
5764 g_param_spec_boolean ("natural-height-set",
5765 P_("Natural height set"),
5766 P_("Whether to use the natural-height property"),
5768 CLUTTER_PARAM_READWRITE);
5771 * ClutterActor:allocation:
5773 * The allocation for the actor, in pixels
5775 * This is property is read-only, but you might monitor it to know when an
5776 * actor moves or resizes
5780 obj_props[PROP_ALLOCATION] =
5781 g_param_spec_boxed ("allocation",
5783 P_("The actor's allocation"),
5784 CLUTTER_TYPE_ACTOR_BOX,
5785 CLUTTER_PARAM_READABLE);
5788 * ClutterActor:request-mode:
5790 * Request mode for the #ClutterActor. The request mode determines the
5791 * type of geometry management used by the actor, either height for width
5792 * (the default) or width for height.
5794 * For actors implementing height for width, the parent container should get
5795 * the preferred width first, and then the preferred height for that width.
5797 * For actors implementing width for height, the parent container should get
5798 * the preferred height first, and then the preferred width for that height.
5803 * ClutterRequestMode mode;
5804 * gfloat natural_width, min_width;
5805 * gfloat natural_height, min_height;
5807 * mode = clutter_actor_get_request_mode (child);
5808 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5810 * clutter_actor_get_preferred_width (child, -1,
5812 * &natural_width);
5813 * clutter_actor_get_preferred_height (child, natural_width,
5815 * &natural_height);
5819 * clutter_actor_get_preferred_height (child, -1,
5821 * &natural_height);
5822 * clutter_actor_get_preferred_width (child, natural_height,
5824 * &natural_width);
5828 * will retrieve the minimum and natural width and height depending on the
5829 * preferred request mode of the #ClutterActor "child".
5831 * The clutter_actor_get_preferred_size() function will implement this
5836 obj_props[PROP_REQUEST_MODE] =
5837 g_param_spec_enum ("request-mode",
5839 P_("The actor's request mode"),
5840 CLUTTER_TYPE_REQUEST_MODE,
5841 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5842 CLUTTER_PARAM_READWRITE);
5845 * ClutterActor:depth:
5847 * The position of the actor on the Z axis.
5849 * The #ClutterActor:depth property is relative to the parent's
5852 * The #ClutterActor:depth property is animatable.
5856 obj_props[PROP_DEPTH] =
5857 g_param_spec_float ("depth",
5859 P_("Position on the Z axis"),
5860 -G_MAXFLOAT, G_MAXFLOAT,
5863 G_PARAM_STATIC_STRINGS |
5864 CLUTTER_PARAM_ANIMATABLE);
5867 * ClutterActor:opacity:
5869 * Opacity of an actor, between 0 (fully transparent) and
5870 * 255 (fully opaque)
5872 * The #ClutterActor:opacity property is animatable.
5874 obj_props[PROP_OPACITY] =
5875 g_param_spec_uint ("opacity",
5877 P_("Opacity of an actor"),
5881 G_PARAM_STATIC_STRINGS |
5882 CLUTTER_PARAM_ANIMATABLE);
5885 * ClutterActor:offscreen-redirect:
5887 * Determines the conditions in which the actor will be redirected
5888 * to an offscreen framebuffer while being painted. For example this
5889 * can be used to cache an actor in a framebuffer or for improved
5890 * handling of transparent actors. See
5891 * clutter_actor_set_offscreen_redirect() for details.
5895 obj_props[PROP_OFFSCREEN_REDIRECT] =
5896 g_param_spec_flags ("offscreen-redirect",
5897 P_("Offscreen redirect"),
5898 P_("Flags controlling when to flatten the actor into a single image"),
5899 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5901 CLUTTER_PARAM_READWRITE);
5904 * ClutterActor:visible:
5906 * Whether the actor is set to be visible or not
5908 * See also #ClutterActor:mapped
5910 obj_props[PROP_VISIBLE] =
5911 g_param_spec_boolean ("visible",
5913 P_("Whether the actor is visible or not"),
5915 CLUTTER_PARAM_READWRITE);
5918 * ClutterActor:mapped:
5920 * Whether the actor is mapped (will be painted when the stage
5921 * to which it belongs is mapped)
5925 obj_props[PROP_MAPPED] =
5926 g_param_spec_boolean ("mapped",
5928 P_("Whether the actor will be painted"),
5930 CLUTTER_PARAM_READABLE);
5933 * ClutterActor:realized:
5935 * Whether the actor has been realized
5939 obj_props[PROP_REALIZED] =
5940 g_param_spec_boolean ("realized",
5942 P_("Whether the actor has been realized"),
5944 CLUTTER_PARAM_READABLE);
5947 * ClutterActor:reactive:
5949 * Whether the actor is reactive to events or not
5951 * Only reactive actors will emit event-related signals
5955 obj_props[PROP_REACTIVE] =
5956 g_param_spec_boolean ("reactive",
5958 P_("Whether the actor is reactive to events"),
5960 CLUTTER_PARAM_READWRITE);
5963 * ClutterActor:has-clip:
5965 * Whether the actor has the #ClutterActor:clip property set or not
5967 obj_props[PROP_HAS_CLIP] =
5968 g_param_spec_boolean ("has-clip",
5970 P_("Whether the actor has a clip set"),
5972 CLUTTER_PARAM_READABLE);
5975 * ClutterActor:clip:
5977 * The clip region for the actor, in actor-relative coordinates
5979 * Every part of the actor outside the clip region will not be
5982 obj_props[PROP_CLIP] =
5983 g_param_spec_boxed ("clip",
5985 P_("The clip region for the actor"),
5986 CLUTTER_TYPE_GEOMETRY,
5987 CLUTTER_PARAM_READWRITE);
5990 * ClutterActor:name:
5992 * The name of the actor
5996 obj_props[PROP_NAME] =
5997 g_param_spec_string ("name",
5999 P_("Name of the actor"),
6001 CLUTTER_PARAM_READWRITE);
6004 * ClutterActor:scale-x:
6006 * The horizontal scale of the actor.
6008 * The #ClutterActor:scale-x property is animatable.
6012 obj_props[PROP_SCALE_X] =
6013 g_param_spec_double ("scale-x",
6015 P_("Scale factor on the X axis"),
6019 G_PARAM_STATIC_STRINGS |
6020 CLUTTER_PARAM_ANIMATABLE);
6023 * ClutterActor:scale-y:
6025 * The vertical scale of the actor.
6027 * The #ClutterActor:scale-y property is animatable.
6031 obj_props[PROP_SCALE_Y] =
6032 g_param_spec_double ("scale-y",
6034 P_("Scale factor on the Y axis"),
6038 G_PARAM_STATIC_STRINGS |
6039 CLUTTER_PARAM_ANIMATABLE);
6042 * ClutterActor:scale-center-x:
6044 * The horizontal center point for scaling
6048 obj_props[PROP_SCALE_CENTER_X] =
6049 g_param_spec_float ("scale-center-x",
6050 P_("Scale Center X"),
6051 P_("Horizontal scale center"),
6052 -G_MAXFLOAT, G_MAXFLOAT,
6054 CLUTTER_PARAM_READWRITE);
6057 * ClutterActor:scale-center-y:
6059 * The vertical center point for scaling
6063 obj_props[PROP_SCALE_CENTER_Y] =
6064 g_param_spec_float ("scale-center-y",
6065 P_("Scale Center Y"),
6066 P_("Vertical scale center"),
6067 -G_MAXFLOAT, G_MAXFLOAT,
6069 CLUTTER_PARAM_READWRITE);
6072 * ClutterActor:scale-gravity:
6074 * The center point for scaling expressed as a #ClutterGravity
6078 obj_props[PROP_SCALE_GRAVITY] =
6079 g_param_spec_enum ("scale-gravity",
6080 P_("Scale Gravity"),
6081 P_("The center of scaling"),
6082 CLUTTER_TYPE_GRAVITY,
6083 CLUTTER_GRAVITY_NONE,
6084 CLUTTER_PARAM_READWRITE);
6087 * ClutterActor:rotation-angle-x:
6089 * The rotation angle on the X axis.
6091 * The #ClutterActor:rotation-angle-x property is animatable.
6095 obj_props[PROP_ROTATION_ANGLE_X] =
6096 g_param_spec_double ("rotation-angle-x",
6097 P_("Rotation Angle X"),
6098 P_("The rotation angle on the X axis"),
6099 -G_MAXDOUBLE, G_MAXDOUBLE,
6102 G_PARAM_STATIC_STRINGS |
6103 CLUTTER_PARAM_ANIMATABLE);
6106 * ClutterActor:rotation-angle-y:
6108 * The rotation angle on the Y axis
6110 * The #ClutterActor:rotation-angle-y property is animatable.
6114 obj_props[PROP_ROTATION_ANGLE_Y] =
6115 g_param_spec_double ("rotation-angle-y",
6116 P_("Rotation Angle Y"),
6117 P_("The rotation angle on the Y axis"),
6118 -G_MAXDOUBLE, G_MAXDOUBLE,
6121 G_PARAM_STATIC_STRINGS |
6122 CLUTTER_PARAM_ANIMATABLE);
6125 * ClutterActor:rotation-angle-z:
6127 * The rotation angle on the Z axis
6129 * The #ClutterActor:rotation-angle-z property is animatable.
6133 obj_props[PROP_ROTATION_ANGLE_Z] =
6134 g_param_spec_double ("rotation-angle-z",
6135 P_("Rotation Angle Z"),
6136 P_("The rotation angle on the Z axis"),
6137 -G_MAXDOUBLE, G_MAXDOUBLE,
6140 G_PARAM_STATIC_STRINGS |
6141 CLUTTER_PARAM_ANIMATABLE);
6144 * ClutterActor:rotation-center-x:
6146 * The rotation center on the X axis.
6150 obj_props[PROP_ROTATION_CENTER_X] =
6151 g_param_spec_boxed ("rotation-center-x",
6152 P_("Rotation Center X"),
6153 P_("The rotation center on the X axis"),
6154 CLUTTER_TYPE_VERTEX,
6155 CLUTTER_PARAM_READWRITE);
6158 * ClutterActor:rotation-center-y:
6160 * The rotation center on the Y axis.
6164 obj_props[PROP_ROTATION_CENTER_Y] =
6165 g_param_spec_boxed ("rotation-center-y",
6166 P_("Rotation Center Y"),
6167 P_("The rotation center on the Y axis"),
6168 CLUTTER_TYPE_VERTEX,
6169 CLUTTER_PARAM_READWRITE);
6172 * ClutterActor:rotation-center-z:
6174 * The rotation center on the Z axis.
6178 obj_props[PROP_ROTATION_CENTER_Z] =
6179 g_param_spec_boxed ("rotation-center-z",
6180 P_("Rotation Center Z"),
6181 P_("The rotation center on the Z axis"),
6182 CLUTTER_TYPE_VERTEX,
6183 CLUTTER_PARAM_READWRITE);
6186 * ClutterActor:rotation-center-z-gravity:
6188 * The rotation center on the Z axis expressed as a #ClutterGravity.
6192 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6193 g_param_spec_enum ("rotation-center-z-gravity",
6194 P_("Rotation Center Z Gravity"),
6195 P_("Center point for rotation around the Z axis"),
6196 CLUTTER_TYPE_GRAVITY,
6197 CLUTTER_GRAVITY_NONE,
6198 CLUTTER_PARAM_READWRITE);
6201 * ClutterActor:anchor-x:
6203 * The X coordinate of an actor's anchor point, relative to
6204 * the actor coordinate space, in pixels
6208 obj_props[PROP_ANCHOR_X] =
6209 g_param_spec_float ("anchor-x",
6211 P_("X coordinate of the anchor point"),
6212 -G_MAXFLOAT, G_MAXFLOAT,
6214 CLUTTER_PARAM_READWRITE);
6217 * ClutterActor:anchor-y:
6219 * The Y coordinate of an actor's anchor point, relative to
6220 * the actor coordinate space, in pixels
6224 obj_props[PROP_ANCHOR_Y] =
6225 g_param_spec_float ("anchor-y",
6227 P_("Y coordinate of the anchor point"),
6228 -G_MAXFLOAT, G_MAXFLOAT,
6230 CLUTTER_PARAM_READWRITE);
6233 * ClutterActor:anchor-gravity:
6235 * The anchor point expressed as a #ClutterGravity
6239 obj_props[PROP_ANCHOR_GRAVITY] =
6240 g_param_spec_enum ("anchor-gravity",
6241 P_("Anchor Gravity"),
6242 P_("The anchor point as a ClutterGravity"),
6243 CLUTTER_TYPE_GRAVITY,
6244 CLUTTER_GRAVITY_NONE,
6245 CLUTTER_PARAM_READWRITE);
6248 * ClutterActor:show-on-set-parent:
6250 * If %TRUE, the actor is automatically shown when parented.
6252 * Calling clutter_actor_hide() on an actor which has not been
6253 * parented will set this property to %FALSE as a side effect.
6257 obj_props[PROP_SHOW_ON_SET_PARENT] =
6258 g_param_spec_boolean ("show-on-set-parent",
6259 P_("Show on set parent"),
6260 P_("Whether the actor is shown when parented"),
6262 CLUTTER_PARAM_READWRITE);
6265 * ClutterActor:clip-to-allocation:
6267 * Whether the clip region should track the allocated area
6270 * This property is ignored if a clip area has been explicitly
6271 * set using clutter_actor_set_clip().
6275 obj_props[PROP_CLIP_TO_ALLOCATION] =
6276 g_param_spec_boolean ("clip-to-allocation",
6277 P_("Clip to Allocation"),
6278 P_("Sets the clip region to track the actor's allocation"),
6280 CLUTTER_PARAM_READWRITE);
6283 * ClutterActor:text-direction:
6285 * The direction of the text inside a #ClutterActor.
6289 obj_props[PROP_TEXT_DIRECTION] =
6290 g_param_spec_enum ("text-direction",
6291 P_("Text Direction"),
6292 P_("Direction of the text"),
6293 CLUTTER_TYPE_TEXT_DIRECTION,
6294 CLUTTER_TEXT_DIRECTION_LTR,
6295 CLUTTER_PARAM_READWRITE);
6298 * ClutterActor:has-pointer:
6300 * Whether the actor contains the pointer of a #ClutterInputDevice
6305 obj_props[PROP_HAS_POINTER] =
6306 g_param_spec_boolean ("has-pointer",
6308 P_("Whether the actor contains the pointer of an input device"),
6310 CLUTTER_PARAM_READABLE);
6313 * ClutterActor:actions:
6315 * Adds a #ClutterAction to the actor
6319 obj_props[PROP_ACTIONS] =
6320 g_param_spec_object ("actions",
6322 P_("Adds an action to the actor"),
6323 CLUTTER_TYPE_ACTION,
6324 CLUTTER_PARAM_WRITABLE);
6327 * ClutterActor:constraints:
6329 * Adds a #ClutterConstraint to the actor
6333 obj_props[PROP_CONSTRAINTS] =
6334 g_param_spec_object ("constraints",
6336 P_("Adds a constraint to the actor"),
6337 CLUTTER_TYPE_CONSTRAINT,
6338 CLUTTER_PARAM_WRITABLE);
6341 * ClutterActor:effect:
6343 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6347 obj_props[PROP_EFFECT] =
6348 g_param_spec_object ("effect",
6350 P_("Add an effect to be applied on the actor"),
6351 CLUTTER_TYPE_EFFECT,
6352 CLUTTER_PARAM_WRITABLE);
6355 * ClutterActor:layout-manager:
6357 * A delegate object for controlling the layout of the children of
6362 obj_props[PROP_LAYOUT_MANAGER] =
6363 g_param_spec_object ("layout-manager",
6364 P_("Layout Manager"),
6365 P_("The object controlling the layout of an actor's children"),
6366 CLUTTER_TYPE_LAYOUT_MANAGER,
6367 CLUTTER_PARAM_READWRITE);
6371 * ClutterActor:x-align:
6373 * The alignment of an actor on the X axis, if the actor has been given
6374 * extra space for its allocation.
6378 obj_props[PROP_X_ALIGN] =
6379 g_param_spec_enum ("x-align",
6381 P_("The alignment of the actor on the X axis within its allocation"),
6382 CLUTTER_TYPE_ACTOR_ALIGN,
6383 CLUTTER_ACTOR_ALIGN_FILL,
6384 CLUTTER_PARAM_READWRITE);
6387 * ClutterActor:y-align:
6389 * The alignment of an actor on the Y axis, if the actor has been given
6390 * extra space for its allocation.
6394 obj_props[PROP_Y_ALIGN] =
6395 g_param_spec_enum ("y-align",
6397 P_("The alignment of the actor on the Y axis within its allocation"),
6398 CLUTTER_TYPE_ACTOR_ALIGN,
6399 CLUTTER_ACTOR_ALIGN_FILL,
6400 CLUTTER_PARAM_READWRITE);
6403 * ClutterActor:margin-top:
6405 * The margin (in pixels) from the top of the actor.
6407 * This property adds a margin to the actor's preferred size; the margin
6408 * will be automatically taken into account when allocating the actor.
6412 obj_props[PROP_MARGIN_TOP] =
6413 g_param_spec_float ("margin-top",
6415 P_("Extra space at the top"),
6418 CLUTTER_PARAM_READWRITE);
6421 * ClutterActor:margin-bottom:
6423 * The margin (in pixels) from the bottom of the actor.
6425 * This property adds a margin to the actor's preferred size; the margin
6426 * will be automatically taken into account when allocating the actor.
6430 obj_props[PROP_MARGIN_BOTTOM] =
6431 g_param_spec_float ("margin-bottom",
6432 P_("Margin Bottom"),
6433 P_("Extra space at the bottom"),
6436 CLUTTER_PARAM_READWRITE);
6439 * ClutterActor:margin-left:
6441 * The margin (in pixels) from the left of the actor.
6443 * This property adds a margin to the actor's preferred size; the margin
6444 * will be automatically taken into account when allocating the actor.
6448 obj_props[PROP_MARGIN_LEFT] =
6449 g_param_spec_float ("margin-left",
6451 P_("Extra space at the left"),
6454 CLUTTER_PARAM_READWRITE);
6457 * ClutterActor:margin-right:
6459 * The margin (in pixels) from the right of the actor.
6461 * This property adds a margin to the actor's preferred size; the margin
6462 * will be automatically taken into account when allocating the actor.
6466 obj_props[PROP_MARGIN_RIGHT] =
6467 g_param_spec_float ("margin-right",
6469 P_("Extra space at the right"),
6472 CLUTTER_PARAM_READWRITE);
6475 * ClutterActor:background-color-set:
6477 * Whether the #ClutterActor:background-color property has been set.
6481 obj_props[PROP_BACKGROUND_COLOR_SET] =
6482 g_param_spec_boolean ("background-color-set",
6483 P_("Background Color Set"),
6484 P_("Whether the background color is set"),
6486 CLUTTER_PARAM_READABLE);
6489 * ClutterActor:background-color:
6491 * Paints a solid fill of the actor's allocation using the specified
6494 * The #ClutterActor:background-color property is animatable.
6498 obj_props[PROP_BACKGROUND_COLOR] =
6499 clutter_param_spec_color ("background-color",
6500 P_("Background color"),
6501 P_("The actor's background color"),
6502 CLUTTER_COLOR_Transparent,
6504 G_PARAM_STATIC_STRINGS |
6505 CLUTTER_PARAM_ANIMATABLE);
6508 * ClutterActor:first-child:
6510 * The actor's first child.
6514 obj_props[PROP_FIRST_CHILD] =
6515 g_param_spec_object ("first-child",
6517 P_("The actor's first child"),
6519 CLUTTER_PARAM_READABLE);
6522 * ClutterActor:last-child:
6524 * The actor's last child.
6528 obj_props[PROP_LAST_CHILD] =
6529 g_param_spec_object ("last-child",
6531 P_("The actor's last child"),
6533 CLUTTER_PARAM_READABLE);
6536 * ClutterActor:content:
6538 * The #ClutterContent implementation that controls the content
6543 obj_props[PROP_CONTENT] =
6544 g_param_spec_object ("content",
6546 P_("Delegate object for painting the actor's content"),
6547 CLUTTER_TYPE_CONTENT,
6548 CLUTTER_PARAM_READWRITE);
6551 * ClutterActor:content-gravity:
6553 * The alignment that should be honoured by the #ClutterContent
6554 * set with the #ClutterActor:content property.
6556 * Changing the value of this property will change the bounding box of
6557 * the content; you can use the #ClutterActor:content-box property to
6558 * get the position and size of the content within the actor's
6561 * This property is meaningful only for #ClutterContent implementations
6562 * that have a preferred size, and if the preferred size is smaller than
6563 * the actor's allocation.
6565 * The #ClutterActor:content-gravity property is animatable.
6569 obj_props[PROP_CONTENT_GRAVITY] =
6570 g_param_spec_enum ("content-gravity",
6571 P_("Content Gravity"),
6572 P_("Alignment of the actor's content"),
6573 CLUTTER_TYPE_CONTENT_GRAVITY,
6574 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6575 CLUTTER_PARAM_READWRITE);
6578 * ClutterActor:content-box:
6580 * The bounding box for the #ClutterContent used by the actor.
6582 * The value of this property is controlled by the #ClutterActor:allocation
6583 * and #ClutterActor:content-gravity properties of #ClutterActor.
6585 * The bounding box for the content is guaranteed to never exceed the
6586 * allocation's of the actor.
6590 obj_props[PROP_CONTENT_BOX] =
6591 g_param_spec_boxed ("content-box",
6593 P_("The bounding box of the actor's content"),
6594 CLUTTER_TYPE_ACTOR_BOX,
6596 G_PARAM_STATIC_STRINGS |
6597 CLUTTER_PARAM_ANIMATABLE);
6599 obj_props[PROP_MINIFICATION_FILTER] =
6600 g_param_spec_enum ("minification-filter",
6601 P_("Minification Filter"),
6602 P_("The filter used when reducing the size of the content"),
6603 CLUTTER_TYPE_SCALING_FILTER,
6604 CLUTTER_SCALING_FILTER_LINEAR,
6605 CLUTTER_PARAM_READWRITE);
6607 obj_props[PROP_MAGNIFICATION_FILTER] =
6608 g_param_spec_enum ("magnification-filter",
6609 P_("Magnification Filter"),
6610 P_("The filter used when increasing the size of the content"),
6611 CLUTTER_TYPE_SCALING_FILTER,
6612 CLUTTER_SCALING_FILTER_LINEAR,
6613 CLUTTER_PARAM_READWRITE);
6615 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6618 * ClutterActor::destroy:
6619 * @actor: the #ClutterActor which emitted the signal
6621 * The ::destroy signal notifies that all references held on the
6622 * actor which emitted it should be released.
6624 * The ::destroy signal should be used by all holders of a reference
6627 * This signal might result in the finalization of the #ClutterActor
6628 * if all references are released.
6630 * Composite actors and actors implementing the #ClutterContainer
6631 * interface should override the default implementation of the
6632 * class handler of this signal and call clutter_actor_destroy() on
6633 * their children. When overriding the default class handler, it is
6634 * required to chain up to the parent's implementation.
6638 actor_signals[DESTROY] =
6639 g_signal_new (I_("destroy"),
6640 G_TYPE_FROM_CLASS (object_class),
6641 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6642 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6644 _clutter_marshal_VOID__VOID,
6647 * ClutterActor::show:
6648 * @actor: the object which received the signal
6650 * The ::show signal is emitted when an actor is visible and
6651 * rendered on the stage.
6655 actor_signals[SHOW] =
6656 g_signal_new (I_("show"),
6657 G_TYPE_FROM_CLASS (object_class),
6659 G_STRUCT_OFFSET (ClutterActorClass, show),
6661 _clutter_marshal_VOID__VOID,
6664 * ClutterActor::hide:
6665 * @actor: the object which received the signal
6667 * The ::hide signal is emitted when an actor is no longer rendered
6672 actor_signals[HIDE] =
6673 g_signal_new (I_("hide"),
6674 G_TYPE_FROM_CLASS (object_class),
6676 G_STRUCT_OFFSET (ClutterActorClass, hide),
6678 _clutter_marshal_VOID__VOID,
6681 * ClutterActor::parent-set:
6682 * @actor: the object which received the signal
6683 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6685 * This signal is emitted when the parent of the actor changes.
6689 actor_signals[PARENT_SET] =
6690 g_signal_new (I_("parent-set"),
6691 G_TYPE_FROM_CLASS (object_class),
6693 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6695 _clutter_marshal_VOID__OBJECT,
6697 CLUTTER_TYPE_ACTOR);
6700 * ClutterActor::queue-redraw:
6701 * @actor: the actor we're bubbling the redraw request through
6702 * @origin: the actor which initiated the redraw request
6704 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6705 * is called on @origin.
6707 * The default implementation for #ClutterActor chains up to the
6708 * parent actor and queues a redraw on the parent, thus "bubbling"
6709 * the redraw queue up through the actor graph. The default
6710 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6711 * in a main loop idle handler.
6713 * Note that the @origin actor may be the stage, or a container; it
6714 * does not have to be a leaf node in the actor graph.
6716 * Toolkits embedding a #ClutterStage which require a redraw and
6717 * relayout cycle can stop the emission of this signal using the
6718 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6723 * on_redraw_complete (gpointer data)
6725 * ClutterStage *stage = data;
6727 * /* execute the Clutter drawing pipeline */
6728 * clutter_stage_ensure_redraw (stage);
6732 * on_stage_queue_redraw (ClutterStage *stage)
6734 * /* this prevents the default handler to run */
6735 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6737 * /* queue a redraw with the host toolkit and call
6738 * * a function when the redraw has been completed
6740 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6744 * <note><para>This signal is emitted before the Clutter paint
6745 * pipeline is executed. If you want to know when the pipeline has
6746 * been completed you should connect to the ::paint signal on the
6747 * Stage with g_signal_connect_after().</para></note>
6751 actor_signals[QUEUE_REDRAW] =
6752 g_signal_new (I_("queue-redraw"),
6753 G_TYPE_FROM_CLASS (object_class),
6756 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6758 _clutter_marshal_VOID__OBJECT,
6760 CLUTTER_TYPE_ACTOR);
6763 * ClutterActor::queue-relayout
6764 * @actor: the actor being queued for relayout
6766 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6767 * is called on an actor.
6769 * The default implementation for #ClutterActor chains up to the
6770 * parent actor and queues a relayout on the parent, thus "bubbling"
6771 * the relayout queue up through the actor graph.
6773 * The main purpose of this signal is to allow relayout to be propagated
6774 * properly in the procense of #ClutterClone actors. Applications will
6775 * not normally need to connect to this signal.
6779 actor_signals[QUEUE_RELAYOUT] =
6780 g_signal_new (I_("queue-relayout"),
6781 G_TYPE_FROM_CLASS (object_class),
6784 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6786 _clutter_marshal_VOID__VOID,
6790 * ClutterActor::event:
6791 * @actor: the actor which received the event
6792 * @event: a #ClutterEvent
6794 * The ::event signal is emitted each time an event is received
6795 * by the @actor. This signal will be emitted on every actor,
6796 * following the hierarchy chain, until it reaches the top-level
6797 * container (the #ClutterStage).
6799 * Return value: %TRUE if the event has been handled by the actor,
6800 * or %FALSE to continue the emission.
6804 actor_signals[EVENT] =
6805 g_signal_new (I_("event"),
6806 G_TYPE_FROM_CLASS (object_class),
6808 G_STRUCT_OFFSET (ClutterActorClass, event),
6809 _clutter_boolean_handled_accumulator, NULL,
6810 _clutter_marshal_BOOLEAN__BOXED,
6812 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6814 * ClutterActor::button-press-event:
6815 * @actor: the actor which received the event
6816 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6818 * The ::button-press-event signal is emitted each time a mouse button
6819 * is pressed on @actor.
6821 * Return value: %TRUE if the event has been handled by the actor,
6822 * or %FALSE to continue the emission.
6826 actor_signals[BUTTON_PRESS_EVENT] =
6827 g_signal_new (I_("button-press-event"),
6828 G_TYPE_FROM_CLASS (object_class),
6830 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6831 _clutter_boolean_handled_accumulator, NULL,
6832 _clutter_marshal_BOOLEAN__BOXED,
6834 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6836 * ClutterActor::button-release-event:
6837 * @actor: the actor which received the event
6838 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6840 * The ::button-release-event signal is emitted each time a mouse button
6841 * is released on @actor.
6843 * Return value: %TRUE if the event has been handled by the actor,
6844 * or %FALSE to continue the emission.
6848 actor_signals[BUTTON_RELEASE_EVENT] =
6849 g_signal_new (I_("button-release-event"),
6850 G_TYPE_FROM_CLASS (object_class),
6852 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6853 _clutter_boolean_handled_accumulator, NULL,
6854 _clutter_marshal_BOOLEAN__BOXED,
6856 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6858 * ClutterActor::scroll-event:
6859 * @actor: the actor which received the event
6860 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6862 * The ::scroll-event signal is emitted each time the mouse is
6863 * scrolled on @actor
6865 * Return value: %TRUE if the event has been handled by the actor,
6866 * or %FALSE to continue the emission.
6870 actor_signals[SCROLL_EVENT] =
6871 g_signal_new (I_("scroll-event"),
6872 G_TYPE_FROM_CLASS (object_class),
6874 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6875 _clutter_boolean_handled_accumulator, NULL,
6876 _clutter_marshal_BOOLEAN__BOXED,
6878 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6880 * ClutterActor::key-press-event:
6881 * @actor: the actor which received the event
6882 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6884 * The ::key-press-event signal is emitted each time a keyboard button
6885 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6887 * Return value: %TRUE if the event has been handled by the actor,
6888 * or %FALSE to continue the emission.
6892 actor_signals[KEY_PRESS_EVENT] =
6893 g_signal_new (I_("key-press-event"),
6894 G_TYPE_FROM_CLASS (object_class),
6896 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6897 _clutter_boolean_handled_accumulator, NULL,
6898 _clutter_marshal_BOOLEAN__BOXED,
6900 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6902 * ClutterActor::key-release-event:
6903 * @actor: the actor which received the event
6904 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6906 * The ::key-release-event signal is emitted each time a keyboard button
6907 * is released while @actor has key focus (see
6908 * clutter_stage_set_key_focus()).
6910 * Return value: %TRUE if the event has been handled by the actor,
6911 * or %FALSE to continue the emission.
6915 actor_signals[KEY_RELEASE_EVENT] =
6916 g_signal_new (I_("key-release-event"),
6917 G_TYPE_FROM_CLASS (object_class),
6919 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6920 _clutter_boolean_handled_accumulator, NULL,
6921 _clutter_marshal_BOOLEAN__BOXED,
6923 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6925 * ClutterActor::motion-event:
6926 * @actor: the actor which received the event
6927 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6929 * The ::motion-event signal is emitted each time the mouse pointer is
6930 * moved over @actor.
6932 * Return value: %TRUE if the event has been handled by the actor,
6933 * or %FALSE to continue the emission.
6937 actor_signals[MOTION_EVENT] =
6938 g_signal_new (I_("motion-event"),
6939 G_TYPE_FROM_CLASS (object_class),
6941 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6942 _clutter_boolean_handled_accumulator, NULL,
6943 _clutter_marshal_BOOLEAN__BOXED,
6945 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6948 * ClutterActor::key-focus-in:
6949 * @actor: the actor which now has key focus
6951 * The ::key-focus-in signal is emitted when @actor receives key focus.
6955 actor_signals[KEY_FOCUS_IN] =
6956 g_signal_new (I_("key-focus-in"),
6957 G_TYPE_FROM_CLASS (object_class),
6959 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6961 _clutter_marshal_VOID__VOID,
6965 * ClutterActor::key-focus-out:
6966 * @actor: the actor which now has key focus
6968 * The ::key-focus-out signal is emitted when @actor loses key focus.
6972 actor_signals[KEY_FOCUS_OUT] =
6973 g_signal_new (I_("key-focus-out"),
6974 G_TYPE_FROM_CLASS (object_class),
6976 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6978 _clutter_marshal_VOID__VOID,
6982 * ClutterActor::enter-event:
6983 * @actor: the actor which the pointer has entered.
6984 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6986 * The ::enter-event signal is emitted when the pointer enters the @actor
6988 * Return value: %TRUE if the event has been handled by the actor,
6989 * or %FALSE to continue the emission.
6993 actor_signals[ENTER_EVENT] =
6994 g_signal_new (I_("enter-event"),
6995 G_TYPE_FROM_CLASS (object_class),
6997 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6998 _clutter_boolean_handled_accumulator, NULL,
6999 _clutter_marshal_BOOLEAN__BOXED,
7001 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7004 * ClutterActor::leave-event:
7005 * @actor: the actor which the pointer has left
7006 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7008 * The ::leave-event signal is emitted when the pointer leaves the @actor.
7010 * Return value: %TRUE if the event has been handled by the actor,
7011 * or %FALSE to continue the emission.
7015 actor_signals[LEAVE_EVENT] =
7016 g_signal_new (I_("leave-event"),
7017 G_TYPE_FROM_CLASS (object_class),
7019 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7020 _clutter_boolean_handled_accumulator, NULL,
7021 _clutter_marshal_BOOLEAN__BOXED,
7023 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7026 * ClutterActor::captured-event:
7027 * @actor: the actor which received the signal
7028 * @event: a #ClutterEvent
7030 * The ::captured-event signal is emitted when an event is captured
7031 * by Clutter. This signal will be emitted starting from the top-level
7032 * container (the #ClutterStage) to the actor which received the event
7033 * going down the hierarchy. This signal can be used to intercept every
7034 * event before the specialized events (like
7035 * ClutterActor::button-press-event or ::key-released-event) are
7038 * Return value: %TRUE if the event has been handled by the actor,
7039 * or %FALSE to continue the emission.
7043 actor_signals[CAPTURED_EVENT] =
7044 g_signal_new (I_("captured-event"),
7045 G_TYPE_FROM_CLASS (object_class),
7047 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7048 _clutter_boolean_handled_accumulator, NULL,
7049 _clutter_marshal_BOOLEAN__BOXED,
7051 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7054 * ClutterActor::paint:
7055 * @actor: the #ClutterActor that received the signal
7057 * The ::paint signal is emitted each time an actor is being painted.
7059 * Subclasses of #ClutterActor should override the class signal handler
7060 * and paint themselves in that function.
7062 * It is possible to connect a handler to the ::paint signal in order
7063 * to set up some custom aspect of a paint.
7067 actor_signals[PAINT] =
7068 g_signal_new (I_("paint"),
7069 G_TYPE_FROM_CLASS (object_class),
7072 G_STRUCT_OFFSET (ClutterActorClass, paint),
7074 _clutter_marshal_VOID__VOID,
7077 * ClutterActor::realize:
7078 * @actor: the #ClutterActor that received the signal
7080 * The ::realize signal is emitted each time an actor is being
7085 actor_signals[REALIZE] =
7086 g_signal_new (I_("realize"),
7087 G_TYPE_FROM_CLASS (object_class),
7089 G_STRUCT_OFFSET (ClutterActorClass, realize),
7091 _clutter_marshal_VOID__VOID,
7094 * ClutterActor::unrealize:
7095 * @actor: the #ClutterActor that received the signal
7097 * The ::unrealize signal is emitted each time an actor is being
7102 actor_signals[UNREALIZE] =
7103 g_signal_new (I_("unrealize"),
7104 G_TYPE_FROM_CLASS (object_class),
7106 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7108 _clutter_marshal_VOID__VOID,
7112 * ClutterActor::pick:
7113 * @actor: the #ClutterActor that received the signal
7114 * @color: the #ClutterColor to be used when picking
7116 * The ::pick signal is emitted each time an actor is being painted
7117 * in "pick mode". The pick mode is used to identify the actor during
7118 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7119 * The actor should paint its shape using the passed @pick_color.
7121 * Subclasses of #ClutterActor should override the class signal handler
7122 * and paint themselves in that function.
7124 * It is possible to connect a handler to the ::pick signal in order
7125 * to set up some custom aspect of a paint in pick mode.
7129 actor_signals[PICK] =
7130 g_signal_new (I_("pick"),
7131 G_TYPE_FROM_CLASS (object_class),
7133 G_STRUCT_OFFSET (ClutterActorClass, pick),
7135 _clutter_marshal_VOID__BOXED,
7137 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7140 * ClutterActor::allocation-changed:
7141 * @actor: the #ClutterActor that emitted the signal
7142 * @box: a #ClutterActorBox with the new allocation
7143 * @flags: #ClutterAllocationFlags for the allocation
7145 * The ::allocation-changed signal is emitted when the
7146 * #ClutterActor:allocation property changes. Usually, application
7147 * code should just use the notifications for the :allocation property
7148 * but if you want to track the allocation flags as well, for instance
7149 * to know whether the absolute origin of @actor changed, then you might
7150 * want use this signal instead.
7154 actor_signals[ALLOCATION_CHANGED] =
7155 g_signal_new (I_("allocation-changed"),
7156 G_TYPE_FROM_CLASS (object_class),
7160 _clutter_marshal_VOID__BOXED_FLAGS,
7162 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7163 CLUTTER_TYPE_ALLOCATION_FLAGS);
7166 * ClutterActor::transitions-completed:
7167 * @actor: a #ClutterActor
7169 * The ::transitions-completed signal is emitted once all transitions
7170 * involving @actor are complete.
7174 actor_signals[TRANSITIONS_COMPLETED] =
7175 g_signal_new (I_("transitions-completed"),
7176 G_TYPE_FROM_CLASS (object_class),
7180 _clutter_marshal_VOID__VOID,
7185 clutter_actor_init (ClutterActor *self)
7187 ClutterActorPrivate *priv;
7189 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7191 priv->id = _clutter_context_acquire_id (self);
7194 priv->opacity = 0xff;
7195 priv->show_on_set_parent = TRUE;
7197 priv->needs_width_request = TRUE;
7198 priv->needs_height_request = TRUE;
7199 priv->needs_allocation = TRUE;
7201 priv->cached_width_age = 1;
7202 priv->cached_height_age = 1;
7204 priv->opacity_override = -1;
7205 priv->enable_model_view_transform = TRUE;
7207 /* Initialize an empty paint volume to start with */
7208 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7209 priv->last_paint_volume_valid = TRUE;
7211 priv->transform_valid = FALSE;
7213 /* the default is to stretch the content, to match the
7214 * current behaviour of basically all actors. also, it's
7215 * the easiest thing to compute.
7217 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7218 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7219 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7223 * clutter_actor_new:
7225 * Creates a new #ClutterActor.
7227 * A newly created actor has a floating reference, which will be sunk
7228 * when it is added to another actor.
7230 * Return value: (transfer full): the newly created #ClutterActor
7235 clutter_actor_new (void)
7237 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7241 * clutter_actor_destroy:
7242 * @self: a #ClutterActor
7244 * Destroys an actor. When an actor is destroyed, it will break any
7245 * references it holds to other objects. If the actor is inside a
7246 * container, the actor will be removed.
7248 * When you destroy a container, its children will be destroyed as well.
7250 * Note: you cannot destroy the #ClutterStage returned by
7251 * clutter_stage_get_default().
7254 clutter_actor_destroy (ClutterActor *self)
7256 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7258 g_object_ref (self);
7260 /* avoid recursion while destroying */
7261 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7263 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7265 g_object_run_dispose (G_OBJECT (self));
7267 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7270 g_object_unref (self);
7274 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7275 ClutterPaintVolume *clip)
7277 ClutterActorPrivate *priv = self->priv;
7278 ClutterPaintVolume *pv;
7281 /* Remove queue entry early in the process, otherwise a new
7282 queue_redraw() during signal handling could put back this
7283 object in the stage redraw list (but the entry is freed as
7284 soon as we return from this function, causing a segfault
7287 priv->queue_redraw_entry = NULL;
7289 /* If we've been explicitly passed a clip volume then there's
7290 * nothing more to calculate, but otherwise the only thing we know
7291 * is that the change is constrained to the given actor.
7293 * The idea is that if we know the paint volume for where the actor
7294 * was last drawn (in eye coordinates) and we also have the paint
7295 * volume for where it will be drawn next (in actor coordinates)
7296 * then if we queue a redraw for both these volumes that will cover
7297 * everything that needs to be redrawn to clear the old view and
7298 * show the latest view of the actor.
7300 * Don't clip this redraw if we don't know what position we had for
7301 * the previous redraw since we don't know where to set the clip so
7302 * it will clear the actor as it is currently.
7306 _clutter_actor_set_queue_redraw_clip (self, clip);
7309 else if (G_LIKELY (priv->last_paint_volume_valid))
7311 pv = _clutter_actor_get_paint_volume_mutable (self);
7314 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7316 /* make sure we redraw the actors old position... */
7317 _clutter_actor_set_queue_redraw_clip (stage,
7318 &priv->last_paint_volume);
7319 _clutter_actor_signal_queue_redraw (stage, stage);
7320 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7322 /* XXX: Ideally the redraw signal would take a clip volume
7323 * argument, but that would be an ABI break. Until we can
7324 * break the ABI we pass the argument out-of-band
7327 /* setup the clip for the actors new position... */
7328 _clutter_actor_set_queue_redraw_clip (self, pv);
7337 _clutter_actor_signal_queue_redraw (self, self);
7339 /* Just in case anyone is manually firing redraw signals without
7340 * using the public queue_redraw() API we are careful to ensure that
7341 * our out-of-band clip member is cleared before returning...
7343 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7345 if (G_LIKELY (clipped))
7346 _clutter_actor_set_queue_redraw_clip (self, NULL);
7350 _clutter_actor_get_allocation_clip (ClutterActor *self,
7351 ClutterActorBox *clip)
7353 ClutterActorBox allocation;
7355 /* XXX: we don't care if we get an out of date allocation here
7356 * because clutter_actor_queue_redraw_with_clip knows to ignore
7357 * the clip if the actor's allocation is invalid.
7359 * This is noted because clutter_actor_get_allocation_box does some
7360 * unnecessary work to support buggy code with a comment suggesting
7361 * that it could be changed later which would be good for this use
7364 clutter_actor_get_allocation_box (self, &allocation);
7366 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7367 * actor's own coordinate space but the allocation is in parent
7371 clip->x2 = allocation.x2 - allocation.x1;
7372 clip->y2 = allocation.y2 - allocation.y1;
7376 _clutter_actor_queue_redraw_full (ClutterActor *self,
7377 ClutterRedrawFlags flags,
7378 ClutterPaintVolume *volume,
7379 ClutterEffect *effect)
7381 ClutterActorPrivate *priv = self->priv;
7382 ClutterPaintVolume allocation_pv;
7383 ClutterPaintVolume *pv;
7384 gboolean should_free_pv;
7385 ClutterActor *stage;
7387 /* Here's an outline of the actor queue redraw mechanism:
7389 * The process starts in one of the following two functions which
7390 * are wrappers for this function:
7391 * clutter_actor_queue_redraw
7392 * _clutter_actor_queue_redraw_with_clip
7394 * additionally, an effect can queue a redraw by wrapping this
7395 * function in clutter_effect_queue_rerun
7397 * This functions queues an entry in a list associated with the
7398 * stage which is a list of actors that queued a redraw while
7399 * updating the timelines, performing layouting and processing other
7400 * mainloop sources before the next paint starts.
7402 * We aim to minimize the processing done at this point because
7403 * there is a good chance other events will happen while updating
7404 * the scenegraph that would invalidate any expensive work we might
7405 * otherwise try to do here. For example we don't try and resolve
7406 * the screen space bounding box of an actor at this stage so as to
7407 * minimize how much of the screen redraw because it's possible
7408 * something else will happen which will force a full redraw anyway.
7410 * When all updates are complete and we come to paint the stage then
7411 * we iterate this list and actually emit the "queue-redraw" signals
7412 * for each of the listed actors which will bubble up to the stage
7413 * for each actor and at that point we will transform the actors
7414 * paint volume into screen coordinates to determine the clip region
7415 * for what needs to be redrawn in the next paint.
7417 * Besides minimizing redundant work another reason for this
7418 * deferred design is that it's more likely we will be able to
7419 * determine the paint volume of an actor once we've finished
7420 * updating the scenegraph because its allocation should be up to
7421 * date. NB: If we can't determine an actors paint volume then we
7422 * can't automatically queue a clipped redraw which can make a big
7423 * difference to performance.
7425 * So the control flow goes like this:
7426 * One of clutter_actor_queue_redraw,
7427 * _clutter_actor_queue_redraw_with_clip
7428 * or clutter_effect_queue_rerun
7430 * then control moves to:
7431 * _clutter_stage_queue_actor_redraw
7433 * later during _clutter_stage_do_update, once relayouting is done
7434 * and the scenegraph has been updated we will call:
7435 * _clutter_stage_finish_queue_redraws
7437 * _clutter_stage_finish_queue_redraws will call
7438 * _clutter_actor_finish_queue_redraw for each listed actor.
7439 * Note: actors *are* allowed to queue further redraws during this
7440 * process (considering clone actors or texture_new_from_actor which
7441 * respond to their source queueing a redraw by queuing a redraw
7442 * themselves). We repeat the process until the list is empty.
7444 * This will result in the "queue-redraw" signal being fired for
7445 * each actor which will pass control to the default signal handler:
7446 * clutter_actor_real_queue_redraw
7448 * This will bubble up to the stages handler:
7449 * clutter_stage_real_queue_redraw
7451 * clutter_stage_real_queue_redraw will transform the actors paint
7452 * volume into screen space and add it as a clip region for the next
7456 /* ignore queueing a redraw for actors being destroyed */
7457 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7460 stage = _clutter_actor_get_stage_internal (self);
7462 /* Ignore queueing a redraw for actors not descended from a stage */
7466 /* ignore queueing a redraw on stages that are being destroyed */
7467 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7470 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7472 ClutterActorBox allocation_clip;
7473 ClutterVertex origin;
7475 /* If the actor doesn't have a valid allocation then we will
7476 * queue a full stage redraw. */
7477 if (priv->needs_allocation)
7479 /* NB: NULL denotes an undefined clip which will result in a
7481 _clutter_actor_set_queue_redraw_clip (self, NULL);
7482 _clutter_actor_signal_queue_redraw (self, self);
7486 _clutter_paint_volume_init_static (&allocation_pv, self);
7487 pv = &allocation_pv;
7489 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7491 origin.x = allocation_clip.x1;
7492 origin.y = allocation_clip.y1;
7494 clutter_paint_volume_set_origin (pv, &origin);
7495 clutter_paint_volume_set_width (pv,
7496 allocation_clip.x2 - allocation_clip.x1);
7497 clutter_paint_volume_set_height (pv,
7498 allocation_clip.y2 -
7499 allocation_clip.y1);
7500 should_free_pv = TRUE;
7505 should_free_pv = FALSE;
7508 self->priv->queue_redraw_entry =
7509 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7510 priv->queue_redraw_entry,
7515 clutter_paint_volume_free (pv);
7517 /* If this is the first redraw queued then we can directly use the
7519 if (!priv->is_dirty)
7520 priv->effect_to_redraw = effect;
7521 /* Otherwise we need to merge it with the existing effect parameter */
7522 else if (effect != NULL)
7524 /* If there's already an effect then we need to use whichever is
7525 later in the chain of actors. Otherwise a full redraw has
7526 already been queued on the actor so we need to ignore the
7528 if (priv->effect_to_redraw != NULL)
7530 if (priv->effects == NULL)
7531 g_warning ("Redraw queued with an effect that is "
7532 "not applied to the actor");
7537 for (l = _clutter_meta_group_peek_metas (priv->effects);
7541 if (l->data == priv->effect_to_redraw ||
7543 priv->effect_to_redraw = l->data;
7550 /* If no effect is specified then we need to redraw the whole
7552 priv->effect_to_redraw = NULL;
7555 priv->is_dirty = TRUE;
7559 * clutter_actor_queue_redraw:
7560 * @self: A #ClutterActor
7562 * Queues up a redraw of an actor and any children. The redraw occurs
7563 * once the main loop becomes idle (after the current batch of events
7564 * has been processed, roughly).
7566 * Applications rarely need to call this, as redraws are handled
7567 * automatically by modification functions.
7569 * This function will not do anything if @self is not visible, or
7570 * if the actor is inside an invisible part of the scenegraph.
7572 * Also be aware that painting is a NOP for actors with an opacity of
7575 * When you are implementing a custom actor you must queue a redraw
7576 * whenever some private state changes that will affect painting or
7577 * picking of your actor.
7580 clutter_actor_queue_redraw (ClutterActor *self)
7582 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7584 _clutter_actor_queue_redraw_full (self,
7586 NULL, /* clip volume */
7591 * _clutter_actor_queue_redraw_with_clip:
7592 * @self: A #ClutterActor
7593 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7594 * this queue redraw.
7595 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7596 * redrawn or %NULL if you are just using a @flag to state your
7599 * Queues up a clipped redraw of an actor and any children. The redraw
7600 * occurs once the main loop becomes idle (after the current batch of
7601 * events has been processed, roughly).
7603 * If no flags are given the clip volume is defined by @volume
7604 * specified in actor coordinates and tells Clutter that only content
7605 * within this volume has been changed so Clutter can optionally
7606 * optimize the redraw.
7608 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7609 * should be %NULL and this tells Clutter to use the actor's current
7610 * allocation as a clip box. This flag can only be used for 2D actors,
7611 * because any actor with depth may be projected outside its
7614 * Applications rarely need to call this, as redraws are handled
7615 * automatically by modification functions.
7617 * This function will not do anything if @self is not visible, or if
7618 * the actor is inside an invisible part of the scenegraph.
7620 * Also be aware that painting is a NOP for actors with an opacity of
7623 * When you are implementing a custom actor you must queue a redraw
7624 * whenever some private state changes that will affect painting or
7625 * picking of your actor.
7628 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7629 ClutterRedrawFlags flags,
7630 ClutterPaintVolume *volume)
7632 _clutter_actor_queue_redraw_full (self,
7634 volume, /* clip volume */
7639 _clutter_actor_queue_only_relayout (ClutterActor *self)
7641 ClutterActorPrivate *priv = self->priv;
7643 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7646 if (priv->needs_width_request &&
7647 priv->needs_height_request &&
7648 priv->needs_allocation)
7649 return; /* save some cpu cycles */
7651 #if CLUTTER_ENABLE_DEBUG
7652 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7654 g_warning ("The actor '%s' is currently inside an allocation "
7655 "cycle; calling clutter_actor_queue_relayout() is "
7657 _clutter_actor_get_debug_name (self));
7659 #endif /* CLUTTER_ENABLE_DEBUG */
7661 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7665 * clutter_actor_queue_redraw_with_clip:
7666 * @self: a #ClutterActor
7667 * @clip: (allow-none): a rectangular clip region, or %NULL
7669 * Queues a redraw on @self limited to a specific, actor-relative
7672 * If @clip is %NULL this function is equivalent to
7673 * clutter_actor_queue_redraw().
7678 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7679 const cairo_rectangle_int_t *clip)
7681 ClutterPaintVolume volume;
7682 ClutterVertex origin;
7684 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7688 clutter_actor_queue_redraw (self);
7692 _clutter_paint_volume_init_static (&volume, self);
7698 clutter_paint_volume_set_origin (&volume, &origin);
7699 clutter_paint_volume_set_width (&volume, clip->width);
7700 clutter_paint_volume_set_height (&volume, clip->height);
7702 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7704 clutter_paint_volume_free (&volume);
7708 * clutter_actor_queue_relayout:
7709 * @self: A #ClutterActor
7711 * Indicates that the actor's size request or other layout-affecting
7712 * properties may have changed. This function is used inside #ClutterActor
7713 * subclass implementations, not by applications directly.
7715 * Queueing a new layout automatically queues a redraw as well.
7720 clutter_actor_queue_relayout (ClutterActor *self)
7722 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7724 _clutter_actor_queue_only_relayout (self);
7725 clutter_actor_queue_redraw (self);
7729 * clutter_actor_get_preferred_size:
7730 * @self: a #ClutterActor
7731 * @min_width_p: (out) (allow-none): return location for the minimum
7733 * @min_height_p: (out) (allow-none): return location for the minimum
7735 * @natural_width_p: (out) (allow-none): return location for the natural
7737 * @natural_height_p: (out) (allow-none): return location for the natural
7740 * Computes the preferred minimum and natural size of an actor, taking into
7741 * account the actor's geometry management (either height-for-width
7742 * or width-for-height).
7744 * The width and height used to compute the preferred height and preferred
7745 * width are the actor's natural ones.
7747 * If you need to control the height for the preferred width, or the width for
7748 * the preferred height, you should use clutter_actor_get_preferred_width()
7749 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7750 * geometry management using the #ClutterActor:request-mode property.
7755 clutter_actor_get_preferred_size (ClutterActor *self,
7756 gfloat *min_width_p,
7757 gfloat *min_height_p,
7758 gfloat *natural_width_p,
7759 gfloat *natural_height_p)
7761 ClutterActorPrivate *priv;
7762 gfloat min_width, min_height;
7763 gfloat natural_width, natural_height;
7765 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7769 min_width = min_height = 0;
7770 natural_width = natural_height = 0;
7772 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7774 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7775 clutter_actor_get_preferred_width (self, -1,
7778 clutter_actor_get_preferred_height (self, natural_width,
7784 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7785 clutter_actor_get_preferred_height (self, -1,
7788 clutter_actor_get_preferred_width (self, natural_height,
7794 *min_width_p = min_width;
7797 *min_height_p = min_height;
7799 if (natural_width_p)
7800 *natural_width_p = natural_width;
7802 if (natural_height_p)
7803 *natural_height_p = natural_height;
7808 * @align: a #ClutterActorAlign
7809 * @direction: a #ClutterTextDirection
7811 * Retrieves the correct alignment depending on the text direction
7813 * Return value: the effective alignment
7815 static ClutterActorAlign
7816 effective_align (ClutterActorAlign align,
7817 ClutterTextDirection direction)
7819 ClutterActorAlign res;
7823 case CLUTTER_ACTOR_ALIGN_START:
7824 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7825 ? CLUTTER_ACTOR_ALIGN_END
7826 : CLUTTER_ACTOR_ALIGN_START;
7829 case CLUTTER_ACTOR_ALIGN_END:
7830 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7831 ? CLUTTER_ACTOR_ALIGN_START
7832 : CLUTTER_ACTOR_ALIGN_END;
7844 adjust_for_margin (float margin_start,
7846 float *minimum_size,
7847 float *natural_size,
7848 float *allocated_start,
7849 float *allocated_end)
7851 *minimum_size -= (margin_start + margin_end);
7852 *natural_size -= (margin_start + margin_end);
7853 *allocated_start += margin_start;
7854 *allocated_end -= margin_end;
7858 adjust_for_alignment (ClutterActorAlign alignment,
7860 float *allocated_start,
7861 float *allocated_end)
7863 float allocated_size = *allocated_end - *allocated_start;
7867 case CLUTTER_ACTOR_ALIGN_FILL:
7871 case CLUTTER_ACTOR_ALIGN_START:
7873 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7876 case CLUTTER_ACTOR_ALIGN_END:
7877 if (allocated_size > natural_size)
7879 *allocated_start += (allocated_size - natural_size);
7880 *allocated_end = *allocated_start + natural_size;
7884 case CLUTTER_ACTOR_ALIGN_CENTER:
7885 if (allocated_size > natural_size)
7887 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7888 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7895 * clutter_actor_adjust_width:
7896 * @self: a #ClutterActor
7897 * @minimum_width: (inout): the actor's preferred minimum width, which
7898 * will be adjusted depending on the margin
7899 * @natural_width: (inout): the actor's preferred natural width, which
7900 * will be adjusted depending on the margin
7901 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7902 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7904 * Adjusts the preferred and allocated position and size of an actor,
7905 * depending on the margin and alignment properties.
7908 clutter_actor_adjust_width (ClutterActor *self,
7909 gfloat *minimum_width,
7910 gfloat *natural_width,
7911 gfloat *adjusted_x1,
7912 gfloat *adjusted_x2)
7914 ClutterTextDirection text_dir;
7915 const ClutterLayoutInfo *info;
7917 info = _clutter_actor_get_layout_info_or_defaults (self);
7918 text_dir = clutter_actor_get_text_direction (self);
7920 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7922 /* this will tweak natural_width to remove the margin, so that
7923 * adjust_for_alignment() will use the correct size
7925 adjust_for_margin (info->margin.left, info->margin.right,
7926 minimum_width, natural_width,
7927 adjusted_x1, adjusted_x2);
7929 adjust_for_alignment (effective_align (info->x_align, text_dir),
7931 adjusted_x1, adjusted_x2);
7935 * clutter_actor_adjust_height:
7936 * @self: a #ClutterActor
7937 * @minimum_height: (inout): the actor's preferred minimum height, which
7938 * will be adjusted depending on the margin
7939 * @natural_height: (inout): the actor's preferred natural height, which
7940 * will be adjusted depending on the margin
7941 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7942 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7944 * Adjusts the preferred and allocated position and size of an actor,
7945 * depending on the margin and alignment properties.
7948 clutter_actor_adjust_height (ClutterActor *self,
7949 gfloat *minimum_height,
7950 gfloat *natural_height,
7951 gfloat *adjusted_y1,
7952 gfloat *adjusted_y2)
7954 const ClutterLayoutInfo *info;
7956 info = _clutter_actor_get_layout_info_or_defaults (self);
7958 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7960 /* this will tweak natural_height to remove the margin, so that
7961 * adjust_for_alignment() will use the correct size
7963 adjust_for_margin (info->margin.top, info->margin.bottom,
7964 minimum_height, natural_height,
7968 /* we don't use effective_align() here, because text direction
7969 * only affects the horizontal axis
7971 adjust_for_alignment (info->y_align,
7978 /* looks for a cached size request for this for_size. If not
7979 * found, returns the oldest entry so it can be overwritten */
7981 _clutter_actor_get_cached_size_request (gfloat for_size,
7982 SizeRequest *cached_size_requests,
7983 SizeRequest **result)
7987 *result = &cached_size_requests[0];
7989 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7993 sr = &cached_size_requests[i];
7996 sr->for_size == for_size)
7998 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8002 else if (sr->age < (*result)->age)
8008 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8014 * clutter_actor_get_preferred_width:
8015 * @self: A #ClutterActor
8016 * @for_height: available height when computing the preferred width,
8017 * or a negative value to indicate that no height is defined
8018 * @min_width_p: (out) (allow-none): return location for minimum width,
8020 * @natural_width_p: (out) (allow-none): return location for the natural
8023 * Computes the requested minimum and natural widths for an actor,
8024 * optionally depending on the specified height, or if they are
8025 * already computed, returns the cached values.
8027 * An actor may not get its request - depending on the layout
8028 * manager that's in effect.
8030 * A request should not incorporate the actor's scale or anchor point;
8031 * those transformations do not affect layout, only rendering.
8036 clutter_actor_get_preferred_width (ClutterActor *self,
8038 gfloat *min_width_p,
8039 gfloat *natural_width_p)
8041 float request_min_width, request_natural_width;
8042 SizeRequest *cached_size_request;
8043 const ClutterLayoutInfo *info;
8044 ClutterActorPrivate *priv;
8045 gboolean found_in_cache;
8047 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8051 info = _clutter_actor_get_layout_info_or_defaults (self);
8053 /* we shortcircuit the case of a fixed size set using set_width() */
8054 if (priv->min_width_set && priv->natural_width_set)
8056 if (min_width_p != NULL)
8057 *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8059 if (natural_width_p != NULL)
8060 *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8065 /* the remaining cases are:
8067 * - either min_width or natural_width have been set
8068 * - neither min_width or natural_width have been set
8070 * in both cases, we go through the cache (and through the actor in case
8071 * of cache misses) and determine the authoritative value depending on
8075 if (!priv->needs_width_request)
8078 _clutter_actor_get_cached_size_request (for_height,
8079 priv->width_requests,
8080 &cached_size_request);
8084 /* if the actor needs a width request we use the first slot */
8085 found_in_cache = FALSE;
8086 cached_size_request = &priv->width_requests[0];
8089 if (!found_in_cache)
8091 gfloat minimum_width, natural_width;
8092 ClutterActorClass *klass;
8094 minimum_width = natural_width = 0;
8096 /* adjust for the margin */
8097 if (for_height >= 0)
8099 for_height -= (info->margin.top + info->margin.bottom);
8104 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8106 klass = CLUTTER_ACTOR_GET_CLASS (self);
8107 klass->get_preferred_width (self, for_height,
8111 /* adjust for the margin */
8112 minimum_width += (info->margin.left + info->margin.right);
8113 natural_width += (info->margin.left + info->margin.right);
8115 /* Due to accumulated float errors, it's better not to warn
8116 * on this, but just fix it.
8118 if (natural_width < minimum_width)
8119 natural_width = minimum_width;
8121 cached_size_request->min_size = minimum_width;
8122 cached_size_request->natural_size = natural_width;
8123 cached_size_request->for_size = for_height;
8124 cached_size_request->age = priv->cached_width_age;
8126 priv->cached_width_age += 1;
8127 priv->needs_width_request = FALSE;
8130 if (!priv->min_width_set)
8131 request_min_width = cached_size_request->min_size;
8133 request_min_width = info->minimum.width;
8135 if (!priv->natural_width_set)
8136 request_natural_width = cached_size_request->natural_size;
8138 request_natural_width = info->natural.width;
8141 *min_width_p = request_min_width;
8143 if (natural_width_p)
8144 *natural_width_p = request_natural_width;
8148 * clutter_actor_get_preferred_height:
8149 * @self: A #ClutterActor
8150 * @for_width: available width to assume in computing desired height,
8151 * or a negative value to indicate that no width is defined
8152 * @min_height_p: (out) (allow-none): return location for minimum height,
8154 * @natural_height_p: (out) (allow-none): return location for natural
8157 * Computes the requested minimum and natural heights for an actor,
8158 * or if they are already computed, returns the cached values.
8160 * An actor may not get its request - depending on the layout
8161 * manager that's in effect.
8163 * A request should not incorporate the actor's scale or anchor point;
8164 * those transformations do not affect layout, only rendering.
8169 clutter_actor_get_preferred_height (ClutterActor *self,
8171 gfloat *min_height_p,
8172 gfloat *natural_height_p)
8174 float request_min_height, request_natural_height;
8175 SizeRequest *cached_size_request;
8176 const ClutterLayoutInfo *info;
8177 ClutterActorPrivate *priv;
8178 gboolean found_in_cache;
8180 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8184 info = _clutter_actor_get_layout_info_or_defaults (self);
8186 /* we shortcircuit the case of a fixed size set using set_height() */
8187 if (priv->min_height_set && priv->natural_height_set)
8189 if (min_height_p != NULL)
8190 *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8192 if (natural_height_p != NULL)
8193 *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8198 /* the remaining cases are:
8200 * - either min_height or natural_height have been set
8201 * - neither min_height or natural_height have been set
8203 * in both cases, we go through the cache (and through the actor in case
8204 * of cache misses) and determine the authoritative value depending on
8208 if (!priv->needs_height_request)
8211 _clutter_actor_get_cached_size_request (for_width,
8212 priv->height_requests,
8213 &cached_size_request);
8217 found_in_cache = FALSE;
8218 cached_size_request = &priv->height_requests[0];
8221 if (!found_in_cache)
8223 gfloat minimum_height, natural_height;
8224 ClutterActorClass *klass;
8226 minimum_height = natural_height = 0;
8228 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8230 /* adjust for margin */
8233 for_width -= (info->margin.left + info->margin.right);
8238 klass = CLUTTER_ACTOR_GET_CLASS (self);
8239 klass->get_preferred_height (self, for_width,
8243 /* adjust for margin */
8244 minimum_height += (info->margin.top + info->margin.bottom);
8245 natural_height += (info->margin.top + info->margin.bottom);
8247 /* Due to accumulated float errors, it's better not to warn
8248 * on this, but just fix it.
8250 if (natural_height < minimum_height)
8251 natural_height = minimum_height;
8253 cached_size_request->min_size = minimum_height;
8254 cached_size_request->natural_size = natural_height;
8255 cached_size_request->for_size = for_width;
8256 cached_size_request->age = priv->cached_height_age;
8258 priv->cached_height_age += 1;
8259 priv->needs_height_request = FALSE;
8262 if (!priv->min_height_set)
8263 request_min_height = cached_size_request->min_size;
8265 request_min_height = info->minimum.height;
8267 if (!priv->natural_height_set)
8268 request_natural_height = cached_size_request->natural_size;
8270 request_natural_height = info->natural.height;
8273 *min_height_p = request_min_height;
8275 if (natural_height_p)
8276 *natural_height_p = request_natural_height;
8280 * clutter_actor_get_allocation_box:
8281 * @self: A #ClutterActor
8282 * @box: (out): the function fills this in with the actor's allocation
8284 * Gets the layout box an actor has been assigned. The allocation can
8285 * only be assumed valid inside a paint() method; anywhere else, it
8286 * may be out-of-date.
8288 * An allocation does not incorporate the actor's scale or anchor point;
8289 * those transformations do not affect layout, only rendering.
8291 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8292 * of functions inside the implementation of the get_preferred_width()
8293 * or get_preferred_height() virtual functions.</note>
8298 clutter_actor_get_allocation_box (ClutterActor *self,
8299 ClutterActorBox *box)
8301 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8303 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8304 * which limits calling get_allocation to inside paint() basically; or
8305 * we can 2) force a layout, which could be expensive if someone calls
8306 * get_allocation somewhere silly; or we can 3) just return the latest
8307 * value, allowing it to be out-of-date, and assume people know what
8310 * The least-surprises approach that keeps existing code working is
8311 * likely to be 2). People can end up doing some inefficient things,
8312 * though, and in general code that requires 2) is probably broken.
8315 /* this implements 2) */
8316 if (G_UNLIKELY (self->priv->needs_allocation))
8318 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8320 /* do not queue a relayout on an unparented actor */
8322 _clutter_stage_maybe_relayout (stage);
8325 /* commenting out the code above and just keeping this assigment
8328 *box = self->priv->allocation;
8332 * clutter_actor_get_allocation_geometry:
8333 * @self: A #ClutterActor
8334 * @geom: (out): allocation geometry in pixels
8336 * Gets the layout box an actor has been assigned. The allocation can
8337 * only be assumed valid inside a paint() method; anywhere else, it
8338 * may be out-of-date.
8340 * An allocation does not incorporate the actor's scale or anchor point;
8341 * those transformations do not affect layout, only rendering.
8343 * The returned rectangle is in pixels.
8348 clutter_actor_get_allocation_geometry (ClutterActor *self,
8349 ClutterGeometry *geom)
8351 ClutterActorBox box;
8353 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8354 g_return_if_fail (geom != NULL);
8356 clutter_actor_get_allocation_box (self, &box);
8358 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8359 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8360 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8361 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8365 clutter_actor_update_constraints (ClutterActor *self,
8366 ClutterActorBox *allocation)
8368 ClutterActorPrivate *priv = self->priv;
8369 const GList *constraints, *l;
8371 if (priv->constraints == NULL)
8374 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8375 for (l = constraints; l != NULL; l = l->next)
8377 ClutterConstraint *constraint = l->data;
8378 ClutterActorMeta *meta = l->data;
8380 if (clutter_actor_meta_get_enabled (meta))
8382 _clutter_constraint_update_allocation (constraint,
8386 CLUTTER_NOTE (LAYOUT,
8387 "Allocation of '%s' after constraint '%s': "
8388 "{ %.2f, %.2f, %.2f, %.2f }",
8389 _clutter_actor_get_debug_name (self),
8390 _clutter_actor_meta_get_debug_name (meta),
8400 * clutter_actor_adjust_allocation:
8401 * @self: a #ClutterActor
8402 * @allocation: (inout): the allocation to adjust
8404 * Adjusts the passed allocation box taking into account the actor's
8405 * layout information, like alignment, expansion, and margin.
8408 clutter_actor_adjust_allocation (ClutterActor *self,
8409 ClutterActorBox *allocation)
8411 ClutterActorBox adj_allocation;
8412 float alloc_width, alloc_height;
8413 float min_width, min_height;
8414 float nat_width, nat_height;
8415 ClutterRequestMode req_mode;
8417 adj_allocation = *allocation;
8419 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8421 /* we want to hit the cache, so we use the public API */
8422 req_mode = clutter_actor_get_request_mode (self);
8424 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8426 clutter_actor_get_preferred_width (self, -1,
8429 clutter_actor_get_preferred_height (self, alloc_width,
8433 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8435 clutter_actor_get_preferred_height (self, -1,
8438 clutter_actor_get_preferred_height (self, alloc_height,
8443 #ifdef CLUTTER_ENABLE_DEBUG
8444 /* warn about underallocations */
8445 if (_clutter_diagnostic_enabled () &&
8446 (floorf (min_width - alloc_width) > 0 ||
8447 floorf (min_height - alloc_height) > 0))
8449 ClutterActor *parent = clutter_actor_get_parent (self);
8451 /* the only actors that are allowed to be underallocated are the Stage,
8452 * as it doesn't have an implicit size, and Actors that specifically
8453 * told us that they want to opt-out from layout control mechanisms
8454 * through the NO_LAYOUT escape hatch.
8456 if (parent != NULL &&
8457 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8459 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8460 "of %.2f x %.2f from its parent actor '%s', but its "
8461 "requested minimum size is of %.2f x %.2f",
8462 _clutter_actor_get_debug_name (self),
8463 alloc_width, alloc_height,
8464 _clutter_actor_get_debug_name (parent),
8465 min_width, min_height);
8470 clutter_actor_adjust_width (self,
8474 &adj_allocation.x2);
8476 clutter_actor_adjust_height (self,
8480 &adj_allocation.y2);
8482 /* we maintain the invariant that an allocation cannot be adjusted
8483 * to be outside the parent-given box
8485 if (adj_allocation.x1 < allocation->x1 ||
8486 adj_allocation.y1 < allocation->y1 ||
8487 adj_allocation.x2 > allocation->x2 ||
8488 adj_allocation.y2 > allocation->y2)
8490 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8491 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8492 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8493 _clutter_actor_get_debug_name (self),
8494 adj_allocation.x1, adj_allocation.y1,
8495 adj_allocation.x2 - adj_allocation.x1,
8496 adj_allocation.y2 - adj_allocation.y1,
8497 allocation->x1, allocation->y1,
8498 allocation->x2 - allocation->x1,
8499 allocation->y2 - allocation->y1);
8503 *allocation = adj_allocation;
8507 * clutter_actor_allocate:
8508 * @self: A #ClutterActor
8509 * @box: new allocation of the actor, in parent-relative coordinates
8510 * @flags: flags that control the allocation
8512 * Called by the parent of an actor to assign the actor its size.
8513 * Should never be called by applications (except when implementing
8514 * a container or layout manager).
8516 * Actors can know from their allocation box whether they have moved
8517 * with respect to their parent actor. The @flags parameter describes
8518 * additional information about the allocation, for instance whether
8519 * the parent has moved with respect to the stage, for example because
8520 * a grandparent's origin has moved.
8525 clutter_actor_allocate (ClutterActor *self,
8526 const ClutterActorBox *box,
8527 ClutterAllocationFlags flags)
8529 ClutterActorPrivate *priv;
8530 ClutterActorClass *klass;
8531 ClutterActorBox old_allocation, real_allocation;
8532 gboolean origin_changed, child_moved, size_changed;
8533 gboolean stage_allocation_changed;
8535 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8536 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8538 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8539 "which isn't a descendent of the stage!\n",
8540 self, _clutter_actor_get_debug_name (self));
8546 old_allocation = priv->allocation;
8547 real_allocation = *box;
8549 /* constraints are allowed to modify the allocation only here; we do
8550 * this prior to all the other checks so that we can bail out if the
8551 * allocation did not change
8553 clutter_actor_update_constraints (self, &real_allocation);
8555 /* adjust the allocation depending on the align/margin properties */
8556 clutter_actor_adjust_allocation (self, &real_allocation);
8558 if (real_allocation.x2 < real_allocation.x1 ||
8559 real_allocation.y2 < real_allocation.y1)
8561 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8562 _clutter_actor_get_debug_name (self),
8563 real_allocation.x2 - real_allocation.x1,
8564 real_allocation.y2 - real_allocation.y1);
8567 /* we allow 0-sized actors, but not negative-sized ones */
8568 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8569 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8571 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8573 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8574 real_allocation.y1 != old_allocation.y1);
8576 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8577 real_allocation.y2 != old_allocation.y2);
8579 if (origin_changed || child_moved || size_changed)
8580 stage_allocation_changed = TRUE;
8582 stage_allocation_changed = FALSE;
8584 /* If we get an allocation "out of the blue"
8585 * (we did not queue relayout), then we want to
8586 * ignore it. But if we have needs_allocation set,
8587 * we want to guarantee that allocate() virtual
8588 * method is always called, i.e. that queue_relayout()
8589 * always results in an allocate() invocation on
8592 * The optimization here is to avoid re-allocating
8593 * actors that did not queue relayout and were
8596 if (!priv->needs_allocation && !stage_allocation_changed)
8598 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8602 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8603 * clutter_actor_allocate(), it indicates whether the parent has its
8604 * absolute origin moved; when passed in to ClutterActor::allocate()
8605 * virtual method though, it indicates whether the child has its
8606 * absolute origin moved. So we set it when child_moved is TRUE
8609 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8611 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8613 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8614 _clutter_actor_get_debug_name (self));
8616 klass = CLUTTER_ACTOR_GET_CLASS (self);
8617 klass->allocate (self, &real_allocation, flags);
8619 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8621 if (stage_allocation_changed)
8622 clutter_actor_queue_redraw (self);
8626 * clutter_actor_set_allocation:
8627 * @self: a #ClutterActor
8628 * @box: a #ClutterActorBox
8629 * @flags: allocation flags
8631 * Stores the allocation of @self as defined by @box.
8633 * This function can only be called from within the implementation of
8634 * the #ClutterActorClass.allocate() virtual function.
8636 * The allocation should have been adjusted to take into account constraints,
8637 * alignment, and margin properties. If you are implementing a #ClutterActor
8638 * subclass that provides its own layout management policy for its children
8639 * instead of using a #ClutterLayoutManager delegate, you should not call
8640 * this function on the children of @self; instead, you should call
8641 * clutter_actor_allocate(), which will adjust the allocation box for
8644 * This function should only be used by subclasses of #ClutterActor
8645 * that wish to store their allocation but cannot chain up to the
8646 * parent's implementation; the default implementation of the
8647 * #ClutterActorClass.allocate() virtual function will call this
8650 * It is important to note that, while chaining up was the recommended
8651 * behaviour for #ClutterActor subclasses prior to the introduction of
8652 * this function, it is recommended to call clutter_actor_set_allocation()
8655 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8656 * to handle the allocation of its children, this function will call
8657 * the clutter_layout_manager_allocate() function only if the
8658 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8659 * expected that the subclass will call clutter_layout_manager_allocate()
8660 * by itself. For instance, the following code:
8664 * my_actor_allocate (ClutterActor *actor,
8665 * const ClutterActorBox *allocation,
8666 * ClutterAllocationFlags flags)
8668 * ClutterActorBox new_alloc;
8669 * ClutterAllocationFlags new_flags;
8671 * adjust_allocation (allocation, &new_alloc);
8673 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8675 * /* this will use the layout manager set on the actor */
8676 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8680 * is equivalent to this:
8684 * my_actor_allocate (ClutterActor *actor,
8685 * const ClutterActorBox *allocation,
8686 * ClutterAllocationFlags flags)
8688 * ClutterLayoutManager *layout;
8689 * ClutterActorBox new_alloc;
8691 * adjust_allocation (allocation, &new_alloc);
8693 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8695 * layout = clutter_actor_get_layout_manager (actor);
8696 * clutter_layout_manager_allocate (layout,
8697 * CLUTTER_CONTAINER (actor),
8706 clutter_actor_set_allocation (ClutterActor *self,
8707 const ClutterActorBox *box,
8708 ClutterAllocationFlags flags)
8710 ClutterActorPrivate *priv;
8713 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8714 g_return_if_fail (box != NULL);
8716 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8718 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8719 "can only be called from within the implementation of "
8720 "the ClutterActor::allocate() virtual function.");
8726 g_object_freeze_notify (G_OBJECT (self));
8728 changed = clutter_actor_set_allocation_internal (self, box, flags);
8730 /* we allocate our children before we notify changes in our geometry,
8731 * so that people connecting to properties will be able to get valid
8732 * data out of the sub-tree of the scene graph that has this actor at
8735 clutter_actor_maybe_layout_children (self, box, flags);
8739 ClutterActorBox signal_box = priv->allocation;
8740 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8742 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8747 g_object_thaw_notify (G_OBJECT (self));
8751 * clutter_actor_set_geometry:
8752 * @self: A #ClutterActor
8753 * @geometry: A #ClutterGeometry
8755 * Sets the actor's fixed position and forces its minimum and natural
8756 * size, in pixels. This means the untransformed actor will have the
8757 * given geometry. This is the same as calling clutter_actor_set_position()
8758 * and clutter_actor_set_size().
8760 * Deprecated: 1.10: Use clutter_actor_set_position() and
8761 * clutter_actor_set_size() instead.
8764 clutter_actor_set_geometry (ClutterActor *self,
8765 const ClutterGeometry *geometry)
8767 g_object_freeze_notify (G_OBJECT (self));
8769 clutter_actor_set_position (self, geometry->x, geometry->y);
8770 clutter_actor_set_size (self, geometry->width, geometry->height);
8772 g_object_thaw_notify (G_OBJECT (self));
8776 * clutter_actor_get_geometry:
8777 * @self: A #ClutterActor
8778 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8780 * Gets the size and position of an actor relative to its parent
8781 * actor. This is the same as calling clutter_actor_get_position() and
8782 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8783 * requested size and position if the actor's allocation is invalid.
8785 * Deprecated: 1.10: Use clutter_actor_get_position() and
8786 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8790 clutter_actor_get_geometry (ClutterActor *self,
8791 ClutterGeometry *geometry)
8793 gfloat x, y, width, height;
8795 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8796 g_return_if_fail (geometry != NULL);
8798 clutter_actor_get_position (self, &x, &y);
8799 clutter_actor_get_size (self, &width, &height);
8801 geometry->x = (int) x;
8802 geometry->y = (int) y;
8803 geometry->width = (int) width;
8804 geometry->height = (int) height;
8808 * clutter_actor_set_position:
8809 * @self: A #ClutterActor
8810 * @x: New left position of actor in pixels.
8811 * @y: New top position of actor in pixels.
8813 * Sets the actor's fixed position in pixels relative to any parent
8816 * If a layout manager is in use, this position will override the
8817 * layout manager and force a fixed position.
8820 clutter_actor_set_position (ClutterActor *self,
8824 ClutterPoint new_position;
8826 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8828 clutter_point_init (&new_position, x, y);
8830 if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
8832 ClutterPoint cur_position;
8834 cur_position.x = clutter_actor_get_x (self);
8835 cur_position.y = clutter_actor_get_y (self);
8837 _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
8842 _clutter_actor_update_transition (self,
8843 obj_props[PROP_POSITION],
8846 clutter_actor_queue_relayout (self);
8850 * clutter_actor_get_fixed_position_set:
8851 * @self: A #ClutterActor
8853 * Checks whether an actor has a fixed position set (and will thus be
8854 * unaffected by any layout manager).
8856 * Return value: %TRUE if the fixed position is set on the actor
8861 clutter_actor_get_fixed_position_set (ClutterActor *self)
8863 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8865 return self->priv->position_set;
8869 * clutter_actor_set_fixed_position_set:
8870 * @self: A #ClutterActor
8871 * @is_set: whether to use fixed position
8873 * Sets whether an actor has a fixed position set (and will thus be
8874 * unaffected by any layout manager).
8879 clutter_actor_set_fixed_position_set (ClutterActor *self,
8882 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8884 if (self->priv->position_set == (is_set != FALSE))
8887 self->priv->position_set = is_set != FALSE;
8888 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8890 clutter_actor_queue_relayout (self);
8894 * clutter_actor_move_by:
8895 * @self: A #ClutterActor
8896 * @dx: Distance to move Actor on X axis.
8897 * @dy: Distance to move Actor on Y axis.
8899 * Moves an actor by the specified distance relative to its current
8900 * position in pixels.
8902 * This function modifies the fixed position of an actor and thus removes
8903 * it from any layout management. Another way to move an actor is with an
8904 * anchor point, see clutter_actor_set_anchor_point().
8909 clutter_actor_move_by (ClutterActor *self,
8913 const ClutterLayoutInfo *info;
8916 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8918 info = _clutter_actor_get_layout_info_or_defaults (self);
8919 x = info->fixed_pos.x;
8920 y = info->fixed_pos.y;
8922 clutter_actor_set_position (self, x + dx, y + dy);
8926 clutter_actor_set_min_width (ClutterActor *self,
8929 ClutterActorPrivate *priv = self->priv;
8930 ClutterActorBox old = { 0, };
8931 ClutterLayoutInfo *info;
8933 /* if we are setting the size on a top-level actor and the
8934 * backend only supports static top-levels (e.g. framebuffers)
8935 * then we ignore the passed value and we override it with
8936 * the stage implementation's preferred size.
8938 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8939 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8942 info = _clutter_actor_get_layout_info (self);
8944 if (priv->min_width_set && min_width == info->minimum.width)
8947 g_object_freeze_notify (G_OBJECT (self));
8949 clutter_actor_store_old_geometry (self, &old);
8951 info->minimum.width = min_width;
8952 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8953 clutter_actor_set_min_width_set (self, TRUE);
8955 clutter_actor_notify_if_geometry_changed (self, &old);
8957 g_object_thaw_notify (G_OBJECT (self));
8959 clutter_actor_queue_relayout (self);
8963 clutter_actor_set_min_height (ClutterActor *self,
8967 ClutterActorPrivate *priv = self->priv;
8968 ClutterActorBox old = { 0, };
8969 ClutterLayoutInfo *info;
8971 /* if we are setting the size on a top-level actor and the
8972 * backend only supports static top-levels (e.g. framebuffers)
8973 * then we ignore the passed value and we override it with
8974 * the stage implementation's preferred size.
8976 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8977 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8980 info = _clutter_actor_get_layout_info (self);
8982 if (priv->min_height_set && min_height == info->minimum.height)
8985 g_object_freeze_notify (G_OBJECT (self));
8987 clutter_actor_store_old_geometry (self, &old);
8989 info->minimum.height = min_height;
8990 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8991 clutter_actor_set_min_height_set (self, TRUE);
8993 clutter_actor_notify_if_geometry_changed (self, &old);
8995 g_object_thaw_notify (G_OBJECT (self));
8997 clutter_actor_queue_relayout (self);
9001 clutter_actor_set_natural_width (ClutterActor *self,
9002 gfloat natural_width)
9004 ClutterActorPrivate *priv = self->priv;
9005 ClutterActorBox old = { 0, };
9006 ClutterLayoutInfo *info;
9008 /* if we are setting the size on a top-level actor and the
9009 * backend only supports static top-levels (e.g. framebuffers)
9010 * then we ignore the passed value and we override it with
9011 * the stage implementation's preferred size.
9013 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9014 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9017 info = _clutter_actor_get_layout_info (self);
9019 if (priv->natural_width_set && natural_width == info->natural.width)
9022 g_object_freeze_notify (G_OBJECT (self));
9024 clutter_actor_store_old_geometry (self, &old);
9026 info->natural.width = natural_width;
9027 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9028 clutter_actor_set_natural_width_set (self, TRUE);
9030 clutter_actor_notify_if_geometry_changed (self, &old);
9032 g_object_thaw_notify (G_OBJECT (self));
9034 clutter_actor_queue_relayout (self);
9038 clutter_actor_set_natural_height (ClutterActor *self,
9039 gfloat natural_height)
9041 ClutterActorPrivate *priv = self->priv;
9042 ClutterActorBox old = { 0, };
9043 ClutterLayoutInfo *info;
9045 /* if we are setting the size on a top-level actor and the
9046 * backend only supports static top-levels (e.g. framebuffers)
9047 * then we ignore the passed value and we override it with
9048 * the stage implementation's preferred size.
9050 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9051 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9054 info = _clutter_actor_get_layout_info (self);
9056 if (priv->natural_height_set && natural_height == info->natural.height)
9059 g_object_freeze_notify (G_OBJECT (self));
9061 clutter_actor_store_old_geometry (self, &old);
9063 info->natural.height = natural_height;
9064 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9065 clutter_actor_set_natural_height_set (self, TRUE);
9067 clutter_actor_notify_if_geometry_changed (self, &old);
9069 g_object_thaw_notify (G_OBJECT (self));
9071 clutter_actor_queue_relayout (self);
9075 clutter_actor_set_min_width_set (ClutterActor *self,
9076 gboolean use_min_width)
9078 ClutterActorPrivate *priv = self->priv;
9079 ClutterActorBox old = { 0, };
9081 if (priv->min_width_set == (use_min_width != FALSE))
9084 clutter_actor_store_old_geometry (self, &old);
9086 priv->min_width_set = use_min_width != FALSE;
9087 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9089 clutter_actor_notify_if_geometry_changed (self, &old);
9091 clutter_actor_queue_relayout (self);
9095 clutter_actor_set_min_height_set (ClutterActor *self,
9096 gboolean use_min_height)
9098 ClutterActorPrivate *priv = self->priv;
9099 ClutterActorBox old = { 0, };
9101 if (priv->min_height_set == (use_min_height != FALSE))
9104 clutter_actor_store_old_geometry (self, &old);
9106 priv->min_height_set = use_min_height != FALSE;
9107 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9109 clutter_actor_notify_if_geometry_changed (self, &old);
9111 clutter_actor_queue_relayout (self);
9115 clutter_actor_set_natural_width_set (ClutterActor *self,
9116 gboolean use_natural_width)
9118 ClutterActorPrivate *priv = self->priv;
9119 ClutterActorBox old = { 0, };
9121 if (priv->natural_width_set == (use_natural_width != FALSE))
9124 clutter_actor_store_old_geometry (self, &old);
9126 priv->natural_width_set = use_natural_width != FALSE;
9127 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9129 clutter_actor_notify_if_geometry_changed (self, &old);
9131 clutter_actor_queue_relayout (self);
9135 clutter_actor_set_natural_height_set (ClutterActor *self,
9136 gboolean use_natural_height)
9138 ClutterActorPrivate *priv = self->priv;
9139 ClutterActorBox old = { 0, };
9141 if (priv->natural_height_set == (use_natural_height != FALSE))
9144 clutter_actor_store_old_geometry (self, &old);
9146 priv->natural_height_set = use_natural_height != FALSE;
9147 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9149 clutter_actor_notify_if_geometry_changed (self, &old);
9151 clutter_actor_queue_relayout (self);
9155 * clutter_actor_set_request_mode:
9156 * @self: a #ClutterActor
9157 * @mode: the request mode
9159 * Sets the geometry request mode of @self.
9161 * The @mode determines the order for invoking
9162 * clutter_actor_get_preferred_width() and
9163 * clutter_actor_get_preferred_height()
9168 clutter_actor_set_request_mode (ClutterActor *self,
9169 ClutterRequestMode mode)
9171 ClutterActorPrivate *priv;
9173 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9177 if (priv->request_mode == mode)
9180 priv->request_mode = mode;
9182 priv->needs_width_request = TRUE;
9183 priv->needs_height_request = TRUE;
9185 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9187 clutter_actor_queue_relayout (self);
9191 * clutter_actor_get_request_mode:
9192 * @self: a #ClutterActor
9194 * Retrieves the geometry request mode of @self
9196 * Return value: the request mode for the actor
9201 clutter_actor_get_request_mode (ClutterActor *self)
9203 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9204 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9206 return self->priv->request_mode;
9209 /* variant of set_width() without checks and without notification
9210 * freeze+thaw, for internal usage only
9213 clutter_actor_set_width_internal (ClutterActor *self,
9218 /* the Stage will use the :min-width to control the minimum
9219 * width to be resized to, so we should not be setting it
9220 * along with the :natural-width
9222 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9223 clutter_actor_set_min_width (self, width);
9225 clutter_actor_set_natural_width (self, width);
9229 /* we only unset the :natural-width for the Stage */
9230 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9231 clutter_actor_set_min_width_set (self, FALSE);
9233 clutter_actor_set_natural_width_set (self, FALSE);
9237 /* variant of set_height() without checks and without notification
9238 * freeze+thaw, for internal usage only
9241 clutter_actor_set_height_internal (ClutterActor *self,
9246 /* see the comment above in set_width_internal() */
9247 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9248 clutter_actor_set_min_height (self, height);
9250 clutter_actor_set_natural_height (self, height);
9254 /* see the comment above in set_width_internal() */
9255 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9256 clutter_actor_set_min_height_set (self, FALSE);
9258 clutter_actor_set_natural_height_set (self, FALSE);
9263 clutter_actor_set_size_internal (ClutterActor *self,
9264 const ClutterSize *size)
9268 clutter_actor_set_width_internal (self, size->width);
9269 clutter_actor_set_height_internal (self, size->height);
9273 clutter_actor_set_width_internal (self, -1);
9274 clutter_actor_set_height_internal (self, -1);
9279 * clutter_actor_set_size:
9280 * @self: A #ClutterActor
9281 * @width: New width of actor in pixels, or -1
9282 * @height: New height of actor in pixels, or -1
9284 * Sets the actor's size request in pixels. This overrides any
9285 * "normal" size request the actor would have. For example
9286 * a text actor might normally request the size of the text;
9287 * this function would force a specific size instead.
9289 * If @width and/or @height are -1 the actor will use its
9290 * "normal" size request instead of overriding it, i.e.
9291 * you can "unset" the size with -1.
9293 * This function sets or unsets both the minimum and natural size.
9296 clutter_actor_set_size (ClutterActor *self,
9300 ClutterSize new_size;
9302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9304 clutter_size_init (&new_size, width, height);
9306 if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9308 /* minor optimization: if we don't have a duration then we can
9309 * skip the get_size() below, to avoid the chance of going through
9310 * get_preferred_width() and get_preferred_height() just to jump to
9311 * a new desired size
9313 if (clutter_actor_get_easing_duration (self) == 0)
9315 g_object_freeze_notify (G_OBJECT (self));
9317 clutter_actor_set_size_internal (self, &new_size);
9319 g_object_thaw_notify (G_OBJECT (self));
9325 ClutterSize cur_size;
9327 clutter_size_init (&cur_size,
9328 clutter_actor_get_width (self),
9329 clutter_actor_get_height (self));
9331 _clutter_actor_create_transition (self,
9332 obj_props[PROP_SIZE],
9338 _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9340 clutter_actor_queue_relayout (self);
9344 * clutter_actor_get_size:
9345 * @self: A #ClutterActor
9346 * @width: (out) (allow-none): return location for the width, or %NULL.
9347 * @height: (out) (allow-none): return location for the height, or %NULL.
9349 * This function tries to "do what you mean" and return
9350 * the size an actor will have. If the actor has a valid
9351 * allocation, the allocation will be returned; otherwise,
9352 * the actors natural size request will be returned.
9354 * If you care whether you get the request vs. the allocation, you
9355 * should probably call a different function like
9356 * clutter_actor_get_allocation_box() or
9357 * clutter_actor_get_preferred_width().
9362 clutter_actor_get_size (ClutterActor *self,
9366 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9369 *width = clutter_actor_get_width (self);
9372 *height = clutter_actor_get_height (self);
9376 * clutter_actor_get_position:
9377 * @self: a #ClutterActor
9378 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9379 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9381 * This function tries to "do what you mean" and tell you where the
9382 * actor is, prior to any transformations. Retrieves the fixed
9383 * position of an actor in pixels, if one has been set; otherwise, if
9384 * the allocation is valid, returns the actor's allocated position;
9385 * otherwise, returns 0,0.
9387 * The returned position is in pixels.
9392 clutter_actor_get_position (ClutterActor *self,
9396 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9399 *x = clutter_actor_get_x (self);
9402 *y = clutter_actor_get_y (self);
9406 * clutter_actor_get_transformed_position:
9407 * @self: A #ClutterActor
9408 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9409 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9411 * Gets the absolute position of an actor, in pixels relative to the stage.
9416 clutter_actor_get_transformed_position (ClutterActor *self,
9423 v1.x = v1.y = v1.z = 0;
9424 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9434 * clutter_actor_get_transformed_size:
9435 * @self: A #ClutterActor
9436 * @width: (out) (allow-none): return location for the width, or %NULL
9437 * @height: (out) (allow-none): return location for the height, or %NULL
9439 * Gets the absolute size of an actor in pixels, taking into account the
9442 * If the actor has a valid allocation, the allocated size will be used.
9443 * If the actor has not a valid allocation then the preferred size will
9444 * be transformed and returned.
9446 * If you want the transformed allocation, see
9447 * clutter_actor_get_abs_allocation_vertices() instead.
9449 * <note>When the actor (or one of its ancestors) is rotated around the
9450 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9451 * as a generic quadrangle; in that case this function returns the size
9452 * of the smallest rectangle that encapsulates the entire quad. Please
9453 * note that in this case no assumptions can be made about the relative
9454 * position of this envelope to the absolute position of the actor, as
9455 * returned by clutter_actor_get_transformed_position(); if you need this
9456 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9457 * to get the coords of the actual quadrangle.</note>
9462 clutter_actor_get_transformed_size (ClutterActor *self,
9466 ClutterActorPrivate *priv;
9468 gfloat x_min, x_max, y_min, y_max;
9471 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9475 /* if the actor hasn't been allocated yet, get the preferred
9476 * size and transform that
9478 if (priv->needs_allocation)
9480 gfloat natural_width, natural_height;
9481 ClutterActorBox box;
9483 /* Make a fake allocation to transform.
9485 * NB: _clutter_actor_transform_and_project_box expects a box in
9486 * the actor's coordinate space... */
9491 natural_width = natural_height = 0;
9492 clutter_actor_get_preferred_size (self, NULL, NULL,
9496 box.x2 = natural_width;
9497 box.y2 = natural_height;
9499 _clutter_actor_transform_and_project_box (self, &box, v);
9502 clutter_actor_get_abs_allocation_vertices (self, v);
9504 x_min = x_max = v[0].x;
9505 y_min = y_max = v[0].y;
9507 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9523 *width = x_max - x_min;
9526 *height = y_max - y_min;
9530 * clutter_actor_get_width:
9531 * @self: A #ClutterActor
9533 * Retrieves the width of a #ClutterActor.
9535 * If the actor has a valid allocation, this function will return the
9536 * width of the allocated area given to the actor.
9538 * If the actor does not have a valid allocation, this function will
9539 * return the actor's natural width, that is the preferred width of
9542 * If you care whether you get the preferred width or the width that
9543 * has been assigned to the actor, you should probably call a different
9544 * function like clutter_actor_get_allocation_box() to retrieve the
9545 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9548 * If an actor has a fixed width, for instance a width that has been
9549 * assigned using clutter_actor_set_width(), the width returned will
9550 * be the same value.
9552 * Return value: the width of the actor, in pixels
9555 clutter_actor_get_width (ClutterActor *self)
9557 ClutterActorPrivate *priv;
9559 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9563 if (priv->needs_allocation)
9565 gfloat natural_width = 0;
9567 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9568 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9571 gfloat natural_height = 0;
9573 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9574 clutter_actor_get_preferred_width (self, natural_height,
9579 return natural_width;
9582 return priv->allocation.x2 - priv->allocation.x1;
9586 * clutter_actor_get_height:
9587 * @self: A #ClutterActor
9589 * Retrieves the height of a #ClutterActor.
9591 * If the actor has a valid allocation, this function will return the
9592 * height of the allocated area given to the actor.
9594 * If the actor does not have a valid allocation, this function will
9595 * return the actor's natural height, that is the preferred height of
9598 * If you care whether you get the preferred height or the height that
9599 * has been assigned to the actor, you should probably call a different
9600 * function like clutter_actor_get_allocation_box() to retrieve the
9601 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9604 * If an actor has a fixed height, for instance a height that has been
9605 * assigned using clutter_actor_set_height(), the height returned will
9606 * be the same value.
9608 * Return value: the height of the actor, in pixels
9611 clutter_actor_get_height (ClutterActor *self)
9613 ClutterActorPrivate *priv;
9615 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9619 if (priv->needs_allocation)
9621 gfloat natural_height = 0;
9623 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9625 gfloat natural_width = 0;
9627 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9628 clutter_actor_get_preferred_height (self, natural_width,
9629 NULL, &natural_height);
9632 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9634 return natural_height;
9637 return priv->allocation.y2 - priv->allocation.y1;
9641 * clutter_actor_set_width:
9642 * @self: A #ClutterActor
9643 * @width: Requested new width for the actor, in pixels, or -1
9645 * Forces a width on an actor, causing the actor's preferred width
9646 * and height (if any) to be ignored.
9648 * If @width is -1 the actor will use its preferred width request
9649 * instead of overriding it, i.e. you can "unset" the width with -1.
9651 * This function sets both the minimum and natural size of the actor.
9656 clutter_actor_set_width (ClutterActor *self,
9659 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9661 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9665 /* minor optimization: if we don't have a duration
9666 * then we can skip the get_width() below, to avoid
9667 * the chance of going through get_preferred_width()
9668 * just to jump to a new desired width.
9670 if (clutter_actor_get_easing_duration (self) == 0)
9672 g_object_freeze_notify (G_OBJECT (self));
9674 clutter_actor_set_width_internal (self, width);
9676 g_object_thaw_notify (G_OBJECT (self));
9681 cur_size = clutter_actor_get_width (self);
9683 _clutter_actor_create_transition (self,
9684 obj_props[PROP_WIDTH],
9689 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9693 * clutter_actor_set_height:
9694 * @self: A #ClutterActor
9695 * @height: Requested new height for the actor, in pixels, or -1
9697 * Forces a height on an actor, causing the actor's preferred width
9698 * and height (if any) to be ignored.
9700 * If @height is -1 the actor will use its preferred height instead of
9701 * overriding it, i.e. you can "unset" the height with -1.
9703 * This function sets both the minimum and natural size of the actor.
9708 clutter_actor_set_height (ClutterActor *self,
9711 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9713 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9717 /* see the comment in clutter_actor_set_width() above */
9718 if (clutter_actor_get_easing_duration (self) == 0)
9720 g_object_freeze_notify (G_OBJECT (self));
9722 clutter_actor_set_height_internal (self, height);
9724 g_object_thaw_notify (G_OBJECT (self));
9729 cur_size = clutter_actor_get_height (self);
9731 _clutter_actor_create_transition (self,
9732 obj_props[PROP_HEIGHT],
9737 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9741 clutter_actor_set_x_internal (ClutterActor *self,
9744 ClutterActorPrivate *priv = self->priv;
9745 ClutterLayoutInfo *linfo;
9746 ClutterActorBox old = { 0, };
9748 linfo = _clutter_actor_get_layout_info (self);
9750 if (priv->position_set && linfo->fixed_pos.x == x)
9753 clutter_actor_store_old_geometry (self, &old);
9755 linfo->fixed_pos.x = x;
9756 clutter_actor_set_fixed_position_set (self, TRUE);
9758 clutter_actor_notify_if_geometry_changed (self, &old);
9760 clutter_actor_queue_relayout (self);
9764 clutter_actor_set_y_internal (ClutterActor *self,
9767 ClutterActorPrivate *priv = self->priv;
9768 ClutterLayoutInfo *linfo;
9769 ClutterActorBox old = { 0, };
9771 linfo = _clutter_actor_get_layout_info (self);
9773 if (priv->position_set && linfo->fixed_pos.y == y)
9776 clutter_actor_store_old_geometry (self, &old);
9778 linfo->fixed_pos.y = y;
9779 clutter_actor_set_fixed_position_set (self, TRUE);
9781 clutter_actor_notify_if_geometry_changed (self, &old);
9783 clutter_actor_queue_relayout (self);
9787 clutter_actor_set_position_internal (ClutterActor *self,
9788 const ClutterPoint *position)
9790 ClutterActorPrivate *priv = self->priv;
9791 ClutterLayoutInfo *linfo;
9792 ClutterActorBox old = { 0, };
9794 linfo = _clutter_actor_get_layout_info (self);
9796 if (priv->position_set &&
9797 clutter_point_equals (position, &linfo->fixed_pos))
9800 clutter_actor_store_old_geometry (self, &old);
9802 if (position != NULL)
9804 linfo->fixed_pos = *position;
9805 clutter_actor_set_fixed_position_set (self, TRUE);
9808 clutter_actor_set_fixed_position_set (self, FALSE);
9810 clutter_actor_notify_if_geometry_changed (self, &old);
9812 clutter_actor_queue_relayout (self);
9816 * clutter_actor_set_x:
9817 * @self: a #ClutterActor
9818 * @x: the actor's position on the X axis
9820 * Sets the actor's X coordinate, relative to its parent, in pixels.
9822 * Overrides any layout manager and forces a fixed position for
9825 * The #ClutterActor:x property is animatable.
9830 clutter_actor_set_x (ClutterActor *self,
9833 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9835 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9837 float cur_position = clutter_actor_get_x (self);
9839 _clutter_actor_create_transition (self, obj_props[PROP_X],
9844 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9848 * clutter_actor_set_y:
9849 * @self: a #ClutterActor
9850 * @y: the actor's position on the Y axis
9852 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9854 * Overrides any layout manager and forces a fixed position for
9857 * The #ClutterActor:y property is animatable.
9862 clutter_actor_set_y (ClutterActor *self,
9865 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9867 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9869 float cur_position = clutter_actor_get_y (self);
9871 _clutter_actor_create_transition (self, obj_props[PROP_Y],
9876 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9880 * clutter_actor_get_x:
9881 * @self: A #ClutterActor
9883 * Retrieves the X coordinate of a #ClutterActor.
9885 * This function tries to "do what you mean", by returning the
9886 * correct value depending on the actor's state.
9888 * If the actor has a valid allocation, this function will return
9889 * the X coordinate of the origin of the allocation box.
9891 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9892 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9893 * function will return that coordinate.
9895 * If both the allocation and a fixed position are missing, this function
9898 * Return value: the X coordinate, in pixels, ignoring any
9899 * transformation (i.e. scaling, rotation)
9902 clutter_actor_get_x (ClutterActor *self)
9904 ClutterActorPrivate *priv;
9906 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9910 if (priv->needs_allocation)
9912 if (priv->position_set)
9914 const ClutterLayoutInfo *info;
9916 info = _clutter_actor_get_layout_info_or_defaults (self);
9918 return info->fixed_pos.x;
9924 return priv->allocation.x1;
9928 * clutter_actor_get_y:
9929 * @self: A #ClutterActor
9931 * Retrieves the Y coordinate of a #ClutterActor.
9933 * This function tries to "do what you mean", by returning the
9934 * correct value depending on the actor's state.
9936 * If the actor has a valid allocation, this function will return
9937 * the Y coordinate of the origin of the allocation box.
9939 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9940 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9941 * function will return that coordinate.
9943 * If both the allocation and a fixed position are missing, this function
9946 * Return value: the Y coordinate, in pixels, ignoring any
9947 * transformation (i.e. scaling, rotation)
9950 clutter_actor_get_y (ClutterActor *self)
9952 ClutterActorPrivate *priv;
9954 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9958 if (priv->needs_allocation)
9960 if (priv->position_set)
9962 const ClutterLayoutInfo *info;
9964 info = _clutter_actor_get_layout_info_or_defaults (self);
9966 return info->fixed_pos.y;
9972 return priv->allocation.y1;
9976 * clutter_actor_set_scale:
9977 * @self: A #ClutterActor
9978 * @scale_x: double factor to scale actor by horizontally.
9979 * @scale_y: double factor to scale actor by vertically.
9981 * Scales an actor with the given factors. The scaling is relative to
9982 * the scale center and the anchor point. The scale center is
9983 * unchanged by this function and defaults to 0,0.
9985 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9991 clutter_actor_set_scale (ClutterActor *self,
9995 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9997 g_object_freeze_notify (G_OBJECT (self));
9999 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10000 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10002 g_object_thaw_notify (G_OBJECT (self));
10006 * clutter_actor_set_scale_full:
10007 * @self: A #ClutterActor
10008 * @scale_x: double factor to scale actor by horizontally.
10009 * @scale_y: double factor to scale actor by vertically.
10010 * @center_x: X coordinate of the center of the scale.
10011 * @center_y: Y coordinate of the center of the scale
10013 * Scales an actor with the given factors around the given center
10014 * point. The center point is specified in pixels relative to the
10015 * anchor point (usually the top left corner of the actor).
10017 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10023 clutter_actor_set_scale_full (ClutterActor *self,
10029 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10031 g_object_freeze_notify (G_OBJECT (self));
10033 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10034 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10035 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10036 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10038 g_object_thaw_notify (G_OBJECT (self));
10042 * clutter_actor_set_scale_with_gravity:
10043 * @self: A #ClutterActor
10044 * @scale_x: double factor to scale actor by horizontally.
10045 * @scale_y: double factor to scale actor by vertically.
10046 * @gravity: the location of the scale center expressed as a compass
10049 * Scales an actor with the given factors around the given
10050 * center point. The center point is specified as one of the compass
10051 * directions in #ClutterGravity. For example, setting it to north
10052 * will cause the top of the actor to remain unchanged and the rest of
10053 * the actor to expand left, right and downwards.
10055 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10061 clutter_actor_set_scale_with_gravity (ClutterActor *self,
10064 ClutterGravity gravity)
10066 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10068 g_object_freeze_notify (G_OBJECT (self));
10070 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10071 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10072 clutter_actor_set_scale_gravity (self, gravity);
10074 g_object_thaw_notify (G_OBJECT (self));
10078 * clutter_actor_get_scale:
10079 * @self: A #ClutterActor
10080 * @scale_x: (out) (allow-none): Location to store horizonal
10081 * scale factor, or %NULL.
10082 * @scale_y: (out) (allow-none): Location to store vertical
10083 * scale factor, or %NULL.
10085 * Retrieves an actors scale factors.
10090 clutter_actor_get_scale (ClutterActor *self,
10094 const ClutterTransformInfo *info;
10096 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10098 info = _clutter_actor_get_transform_info_or_defaults (self);
10101 *scale_x = info->scale_x;
10104 *scale_y = info->scale_y;
10108 * clutter_actor_get_scale_center:
10109 * @self: A #ClutterActor
10110 * @center_x: (out) (allow-none): Location to store the X position
10111 * of the scale center, or %NULL.
10112 * @center_y: (out) (allow-none): Location to store the Y position
10113 * of the scale center, or %NULL.
10115 * Retrieves the scale center coordinate in pixels relative to the top
10116 * left corner of the actor. If the scale center was specified using a
10117 * #ClutterGravity this will calculate the pixel offset using the
10118 * current size of the actor.
10123 clutter_actor_get_scale_center (ClutterActor *self,
10127 const ClutterTransformInfo *info;
10129 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10131 info = _clutter_actor_get_transform_info_or_defaults (self);
10133 clutter_anchor_coord_get_units (self, &info->scale_center,
10140 * clutter_actor_get_scale_gravity:
10141 * @self: A #ClutterActor
10143 * Retrieves the scale center as a compass direction. If the scale
10144 * center was specified in pixels or units this will return
10145 * %CLUTTER_GRAVITY_NONE.
10147 * Return value: the scale gravity
10152 clutter_actor_get_scale_gravity (ClutterActor *self)
10154 const ClutterTransformInfo *info;
10156 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10158 info = _clutter_actor_get_transform_info_or_defaults (self);
10160 return clutter_anchor_coord_get_gravity (&info->scale_center);
10164 clutter_actor_set_opacity_internal (ClutterActor *self,
10167 ClutterActorPrivate *priv = self->priv;
10169 if (priv->opacity != opacity)
10171 priv->opacity = opacity;
10173 /* Queue a redraw from the flatten effect so that it can use
10174 its cached image if available instead of having to redraw the
10175 actual actor. If it doesn't end up using the FBO then the
10176 effect is still able to continue the paint anyway. If there
10177 is no flatten effect yet then this is equivalent to queueing
10179 _clutter_actor_queue_redraw_full (self,
10182 priv->flatten_effect);
10184 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10189 * clutter_actor_set_opacity:
10190 * @self: A #ClutterActor
10191 * @opacity: New opacity value for the actor.
10193 * Sets the actor's opacity, with zero being completely transparent and
10194 * 255 (0xff) being fully opaque.
10196 * The #ClutterActor:opacity property is animatable.
10199 clutter_actor_set_opacity (ClutterActor *self,
10202 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10204 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10206 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10207 self->priv->opacity,
10211 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10215 * clutter_actor_get_paint_opacity_internal:
10216 * @self: a #ClutterActor
10218 * Retrieves the absolute opacity of the actor, as it appears on the stage
10220 * This function does not do type checks
10222 * Return value: the absolute opacity of the actor
10225 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10227 ClutterActorPrivate *priv = self->priv;
10228 ClutterActor *parent;
10230 /* override the top-level opacity to always be 255; even in
10231 * case of ClutterStage:use-alpha being TRUE we want the rest
10232 * of the scene to be painted
10234 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10237 if (priv->opacity_override >= 0)
10238 return priv->opacity_override;
10240 parent = priv->parent;
10242 /* Factor in the actual actors opacity with parents */
10243 if (parent != NULL)
10245 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10247 if (opacity != 0xff)
10248 return (opacity * priv->opacity) / 0xff;
10251 return priv->opacity;
10256 * clutter_actor_get_paint_opacity:
10257 * @self: A #ClutterActor
10259 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10261 * This function traverses the hierarchy chain and composites the opacity of
10262 * the actor with that of its parents.
10264 * This function is intended for subclasses to use in the paint virtual
10265 * function, to paint themselves with the correct opacity.
10267 * Return value: The actor opacity value.
10272 clutter_actor_get_paint_opacity (ClutterActor *self)
10274 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10276 return clutter_actor_get_paint_opacity_internal (self);
10280 * clutter_actor_get_opacity:
10281 * @self: a #ClutterActor
10283 * Retrieves the opacity value of an actor, as set by
10284 * clutter_actor_set_opacity().
10286 * For retrieving the absolute opacity of the actor inside a paint
10287 * virtual function, see clutter_actor_get_paint_opacity().
10289 * Return value: the opacity of the actor
10292 clutter_actor_get_opacity (ClutterActor *self)
10294 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10296 return self->priv->opacity;
10300 * clutter_actor_set_offscreen_redirect:
10301 * @self: A #ClutterActor
10302 * @redirect: New offscreen redirect flags for the actor.
10304 * Defines the circumstances where the actor should be redirected into
10305 * an offscreen image. The offscreen image is used to flatten the
10306 * actor into a single image while painting for two main reasons.
10307 * Firstly, when the actor is painted a second time without any of its
10308 * contents changing it can simply repaint the cached image without
10309 * descending further down the actor hierarchy. Secondly, it will make
10310 * the opacity look correct even if there are overlapping primitives
10313 * Caching the actor could in some cases be a performance win and in
10314 * some cases be a performance lose so it is important to determine
10315 * which value is right for an actor before modifying this value. For
10316 * example, there is never any reason to flatten an actor that is just
10317 * a single texture (such as a #ClutterTexture) because it is
10318 * effectively already cached in an image so the offscreen would be
10319 * redundant. Also if the actor contains primitives that are far apart
10320 * with a large transparent area in the middle (such as a large
10321 * CluterGroup with a small actor in the top left and a small actor in
10322 * the bottom right) then the cached image will contain the entire
10323 * image of the large area and the paint will waste time blending all
10324 * of the transparent pixels in the middle.
10326 * The default method of implementing opacity on a container simply
10327 * forwards on the opacity to all of the children. If the children are
10328 * overlapping then it will appear as if they are two separate glassy
10329 * objects and there will be a break in the color where they
10330 * overlap. By redirecting to an offscreen buffer it will be as if the
10331 * two opaque objects are combined into one and then made transparent
10332 * which is usually what is expected.
10334 * The image below demonstrates the difference between redirecting and
10335 * not. The image shows two Clutter groups, each containing a red and
10336 * a green rectangle which overlap. The opacity on the group is set to
10337 * 128 (which is 50%). When the offscreen redirect is not used, the
10338 * red rectangle can be seen through the blue rectangle as if the two
10339 * rectangles were separately transparent. When the redirect is used
10340 * the group as a whole is transparent instead so the red rectangle is
10341 * not visible where they overlap.
10343 * <figure id="offscreen-redirect">
10344 * <title>Sample of using an offscreen redirect for transparency</title>
10345 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10348 * The default value for this property is 0, so we effectively will
10349 * never redirect an actor offscreen by default. This means that there
10350 * are times that transparent actors may look glassy as described
10351 * above. The reason this is the default is because there is a
10352 * performance trade off between quality and performance here. In many
10353 * cases the default form of glassy opacity looks good enough, but if
10354 * it's not you will need to set the
10355 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10356 * redirection for opacity.
10358 * Custom actors that don't contain any overlapping primitives are
10359 * recommended to override the has_overlaps() virtual to return %FALSE
10360 * for maximum efficiency.
10365 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10366 ClutterOffscreenRedirect redirect)
10368 ClutterActorPrivate *priv;
10370 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10374 if (priv->offscreen_redirect != redirect)
10376 priv->offscreen_redirect = redirect;
10378 /* Queue a redraw from the effect so that it can use its cached
10379 image if available instead of having to redraw the actual
10380 actor. If it doesn't end up using the FBO then the effect is
10381 still able to continue the paint anyway. If there is no
10382 effect then this is equivalent to queuing a full redraw */
10383 _clutter_actor_queue_redraw_full (self,
10386 priv->flatten_effect);
10388 g_object_notify_by_pspec (G_OBJECT (self),
10389 obj_props[PROP_OFFSCREEN_REDIRECT]);
10394 * clutter_actor_get_offscreen_redirect:
10395 * @self: a #ClutterActor
10397 * Retrieves whether to redirect the actor to an offscreen buffer, as
10398 * set by clutter_actor_set_offscreen_redirect().
10400 * Return value: the value of the offscreen-redirect property of the actor
10404 ClutterOffscreenRedirect
10405 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10407 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10409 return self->priv->offscreen_redirect;
10413 * clutter_actor_set_name:
10414 * @self: A #ClutterActor
10415 * @name: Textual tag to apply to actor
10417 * Sets the given name to @self. The name can be used to identify
10421 clutter_actor_set_name (ClutterActor *self,
10424 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10426 g_free (self->priv->name);
10427 self->priv->name = g_strdup (name);
10429 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10433 * clutter_actor_get_name:
10434 * @self: A #ClutterActor
10436 * Retrieves the name of @self.
10438 * Return value: the name of the actor, or %NULL. The returned string is
10439 * owned by the actor and should not be modified or freed.
10442 clutter_actor_get_name (ClutterActor *self)
10444 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10446 return self->priv->name;
10450 * clutter_actor_get_gid:
10451 * @self: A #ClutterActor
10453 * Retrieves the unique id for @self.
10455 * Return value: Globally unique value for this object instance.
10459 * Deprecated: 1.8: The id is not used any longer.
10462 clutter_actor_get_gid (ClutterActor *self)
10464 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10466 return self->priv->id;
10470 clutter_actor_set_depth_internal (ClutterActor *self,
10473 ClutterTransformInfo *info;
10475 info = _clutter_actor_get_transform_info (self);
10477 if (info->depth != depth)
10479 /* Sets Z value - XXX 2.0: should we invert? */
10480 info->depth = depth;
10482 self->priv->transform_valid = FALSE;
10484 /* FIXME - remove this crap; sadly, there are still containers
10485 * in Clutter that depend on this utter brain damage
10487 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10489 clutter_actor_queue_redraw (self);
10491 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10496 * clutter_actor_set_depth:
10497 * @self: a #ClutterActor
10500 * Sets the Z coordinate of @self to @depth.
10502 * The unit used by @depth is dependant on the perspective setup. See
10503 * also clutter_stage_set_perspective().
10506 clutter_actor_set_depth (ClutterActor *self,
10509 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10511 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10513 const ClutterTransformInfo *info;
10515 info = _clutter_actor_get_transform_info_or_defaults (self);
10517 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10522 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10524 clutter_actor_queue_redraw (self);
10528 * clutter_actor_get_depth:
10529 * @self: a #ClutterActor
10531 * Retrieves the depth of @self.
10533 * Return value: the depth of the actor
10536 clutter_actor_get_depth (ClutterActor *self)
10538 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10540 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10544 * clutter_actor_set_rotation:
10545 * @self: a #ClutterActor
10546 * @axis: the axis of rotation
10547 * @angle: the angle of rotation
10548 * @x: X coordinate of the rotation center
10549 * @y: Y coordinate of the rotation center
10550 * @z: Z coordinate of the rotation center
10552 * Sets the rotation angle of @self around the given axis.
10554 * The rotation center coordinates used depend on the value of @axis:
10556 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10557 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10558 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10561 * The rotation coordinates are relative to the anchor point of the
10562 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10563 * point is set, the upper left corner is assumed as the origin.
10568 clutter_actor_set_rotation (ClutterActor *self,
10569 ClutterRotateAxis axis,
10577 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10583 g_object_freeze_notify (G_OBJECT (self));
10585 clutter_actor_set_rotation_angle (self, axis, angle);
10586 clutter_actor_set_rotation_center_internal (self, axis, &v);
10588 g_object_thaw_notify (G_OBJECT (self));
10592 * clutter_actor_set_z_rotation_from_gravity:
10593 * @self: a #ClutterActor
10594 * @angle: the angle of rotation
10595 * @gravity: the center point of the rotation
10597 * Sets the rotation angle of @self around the Z axis using the center
10598 * point specified as a compass point. For example to rotate such that
10599 * the center of the actor remains static you can use
10600 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10601 * will move accordingly.
10606 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10608 ClutterGravity gravity)
10610 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10612 if (gravity == CLUTTER_GRAVITY_NONE)
10613 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10616 GObject *obj = G_OBJECT (self);
10617 ClutterTransformInfo *info;
10619 info = _clutter_actor_get_transform_info (self);
10621 g_object_freeze_notify (obj);
10623 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10625 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10626 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10627 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10629 g_object_thaw_notify (obj);
10634 * clutter_actor_get_rotation:
10635 * @self: a #ClutterActor
10636 * @axis: the axis of rotation
10637 * @x: (out): return value for the X coordinate of the center of rotation
10638 * @y: (out): return value for the Y coordinate of the center of rotation
10639 * @z: (out): return value for the Z coordinate of the center of rotation
10641 * Retrieves the angle and center of rotation on the given axis,
10642 * set using clutter_actor_set_rotation().
10644 * Return value: the angle of rotation
10649 clutter_actor_get_rotation (ClutterActor *self,
10650 ClutterRotateAxis axis,
10655 const ClutterTransformInfo *info;
10656 const AnchorCoord *anchor_coord;
10657 gdouble retval = 0;
10659 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10661 info = _clutter_actor_get_transform_info_or_defaults (self);
10665 case CLUTTER_X_AXIS:
10666 anchor_coord = &info->rx_center;
10667 retval = info->rx_angle;
10670 case CLUTTER_Y_AXIS:
10671 anchor_coord = &info->ry_center;
10672 retval = info->ry_angle;
10675 case CLUTTER_Z_AXIS:
10676 anchor_coord = &info->rz_center;
10677 retval = info->rz_angle;
10681 anchor_coord = NULL;
10686 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10692 * clutter_actor_get_z_rotation_gravity:
10693 * @self: A #ClutterActor
10695 * Retrieves the center for the rotation around the Z axis as a
10696 * compass direction. If the center was specified in pixels or units
10697 * this will return %CLUTTER_GRAVITY_NONE.
10699 * Return value: the Z rotation center
10704 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10706 const ClutterTransformInfo *info;
10708 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10710 info = _clutter_actor_get_transform_info_or_defaults (self);
10712 return clutter_anchor_coord_get_gravity (&info->rz_center);
10716 * clutter_actor_set_clip:
10717 * @self: A #ClutterActor
10718 * @xoff: X offset of the clip rectangle
10719 * @yoff: Y offset of the clip rectangle
10720 * @width: Width of the clip rectangle
10721 * @height: Height of the clip rectangle
10723 * Sets clip area for @self. The clip area is always computed from the
10724 * upper left corner of the actor, even if the anchor point is set
10730 clutter_actor_set_clip (ClutterActor *self,
10736 ClutterActorPrivate *priv;
10738 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10742 if (priv->has_clip &&
10743 priv->clip.x == xoff &&
10744 priv->clip.y == yoff &&
10745 priv->clip.width == width &&
10746 priv->clip.height == height)
10749 priv->clip.x = xoff;
10750 priv->clip.y = yoff;
10751 priv->clip.width = width;
10752 priv->clip.height = height;
10754 priv->has_clip = TRUE;
10756 clutter_actor_queue_redraw (self);
10758 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10759 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10763 * clutter_actor_remove_clip:
10764 * @self: A #ClutterActor
10766 * Removes clip area from @self.
10769 clutter_actor_remove_clip (ClutterActor *self)
10771 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10773 if (!self->priv->has_clip)
10776 self->priv->has_clip = FALSE;
10778 clutter_actor_queue_redraw (self);
10780 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10784 * clutter_actor_has_clip:
10785 * @self: a #ClutterActor
10787 * Determines whether the actor has a clip area set or not.
10789 * Return value: %TRUE if the actor has a clip area set.
10794 clutter_actor_has_clip (ClutterActor *self)
10796 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10798 return self->priv->has_clip;
10802 * clutter_actor_get_clip:
10803 * @self: a #ClutterActor
10804 * @xoff: (out) (allow-none): return location for the X offset of
10805 * the clip rectangle, or %NULL
10806 * @yoff: (out) (allow-none): return location for the Y offset of
10807 * the clip rectangle, or %NULL
10808 * @width: (out) (allow-none): return location for the width of
10809 * the clip rectangle, or %NULL
10810 * @height: (out) (allow-none): return location for the height of
10811 * the clip rectangle, or %NULL
10813 * Gets the clip area for @self, if any is set
10818 clutter_actor_get_clip (ClutterActor *self,
10824 ClutterActorPrivate *priv;
10826 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10830 if (!priv->has_clip)
10834 *xoff = priv->clip.x;
10837 *yoff = priv->clip.y;
10840 *width = priv->clip.width;
10842 if (height != NULL)
10843 *height = priv->clip.height;
10847 * clutter_actor_get_children:
10848 * @self: a #ClutterActor
10850 * Retrieves the list of children of @self.
10852 * Return value: (transfer container) (element-type ClutterActor): A newly
10853 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10859 clutter_actor_get_children (ClutterActor *self)
10861 ClutterActor *iter;
10864 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10866 /* we walk the list backward so that we can use prepend(),
10869 for (iter = self->priv->last_child, res = NULL;
10871 iter = iter->priv->prev_sibling)
10873 res = g_list_prepend (res, iter);
10880 * insert_child_at_depth:
10881 * @self: a #ClutterActor
10882 * @child: a #ClutterActor
10884 * Inserts @child inside the list of children held by @self, using
10885 * the depth as the insertion criteria.
10887 * This sadly makes the insertion not O(1), but we can keep the
10888 * list sorted so that the painters algorithm we use for painting
10889 * the children will work correctly.
10892 insert_child_at_depth (ClutterActor *self,
10893 ClutterActor *child,
10894 gpointer dummy G_GNUC_UNUSED)
10896 ClutterActor *iter;
10899 child->priv->parent = self;
10902 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10904 /* special-case the first child */
10905 if (self->priv->n_children == 0)
10907 self->priv->first_child = child;
10908 self->priv->last_child = child;
10910 child->priv->next_sibling = NULL;
10911 child->priv->prev_sibling = NULL;
10916 /* Find the right place to insert the child so that it will still be
10917 sorted and the child will be after all of the actors at the same
10919 for (iter = self->priv->first_child;
10921 iter = iter->priv->next_sibling)
10926 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10928 if (iter_depth > child_depth)
10934 ClutterActor *tmp = iter->priv->prev_sibling;
10937 tmp->priv->next_sibling = child;
10939 /* Insert the node before the found one */
10940 child->priv->prev_sibling = iter->priv->prev_sibling;
10941 child->priv->next_sibling = iter;
10942 iter->priv->prev_sibling = child;
10946 ClutterActor *tmp = self->priv->last_child;
10949 tmp->priv->next_sibling = child;
10951 /* insert the node at the end of the list */
10952 child->priv->prev_sibling = self->priv->last_child;
10953 child->priv->next_sibling = NULL;
10956 if (child->priv->prev_sibling == NULL)
10957 self->priv->first_child = child;
10959 if (child->priv->next_sibling == NULL)
10960 self->priv->last_child = child;
10964 insert_child_at_index (ClutterActor *self,
10965 ClutterActor *child,
10968 gint index_ = GPOINTER_TO_INT (data_);
10970 child->priv->parent = self;
10974 ClutterActor *tmp = self->priv->first_child;
10977 tmp->priv->prev_sibling = child;
10979 child->priv->prev_sibling = NULL;
10980 child->priv->next_sibling = tmp;
10982 else if (index_ < 0 || index_ >= self->priv->n_children)
10984 ClutterActor *tmp = self->priv->last_child;
10987 tmp->priv->next_sibling = child;
10989 child->priv->prev_sibling = tmp;
10990 child->priv->next_sibling = NULL;
10994 ClutterActor *iter;
10997 for (iter = self->priv->first_child, i = 0;
10999 iter = iter->priv->next_sibling, i += 1)
11003 ClutterActor *tmp = iter->priv->prev_sibling;
11005 child->priv->prev_sibling = tmp;
11006 child->priv->next_sibling = iter;
11008 iter->priv->prev_sibling = child;
11011 tmp->priv->next_sibling = child;
11018 if (child->priv->prev_sibling == NULL)
11019 self->priv->first_child = child;
11021 if (child->priv->next_sibling == NULL)
11022 self->priv->last_child = child;
11026 insert_child_above (ClutterActor *self,
11027 ClutterActor *child,
11030 ClutterActor *sibling = data;
11032 child->priv->parent = self;
11034 if (sibling == NULL)
11035 sibling = self->priv->last_child;
11037 child->priv->prev_sibling = sibling;
11039 if (sibling != NULL)
11041 ClutterActor *tmp = sibling->priv->next_sibling;
11043 child->priv->next_sibling = tmp;
11046 tmp->priv->prev_sibling = child;
11048 sibling->priv->next_sibling = child;
11051 child->priv->next_sibling = NULL;
11053 if (child->priv->prev_sibling == NULL)
11054 self->priv->first_child = child;
11056 if (child->priv->next_sibling == NULL)
11057 self->priv->last_child = child;
11061 insert_child_below (ClutterActor *self,
11062 ClutterActor *child,
11065 ClutterActor *sibling = data;
11067 child->priv->parent = self;
11069 if (sibling == NULL)
11070 sibling = self->priv->first_child;
11072 child->priv->next_sibling = sibling;
11074 if (sibling != NULL)
11076 ClutterActor *tmp = sibling->priv->prev_sibling;
11078 child->priv->prev_sibling = tmp;
11081 tmp->priv->next_sibling = child;
11083 sibling->priv->prev_sibling = child;
11086 child->priv->prev_sibling = NULL;
11088 if (child->priv->prev_sibling == NULL)
11089 self->priv->first_child = child;
11091 if (child->priv->next_sibling == NULL)
11092 self->priv->last_child = child;
11095 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11096 ClutterActor *child,
11100 ADD_CHILD_CREATE_META = 1 << 0,
11101 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
11102 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
11103 ADD_CHILD_CHECK_STATE = 1 << 3,
11104 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
11105 ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11107 /* default flags for public API */
11108 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
11109 ADD_CHILD_EMIT_PARENT_SET |
11110 ADD_CHILD_EMIT_ACTOR_ADDED |
11111 ADD_CHILD_CHECK_STATE |
11112 ADD_CHILD_NOTIFY_FIRST_LAST |
11113 ADD_CHILD_SHOW_ON_SET_PARENT,
11115 /* flags for legacy/deprecated API */
11116 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
11117 ADD_CHILD_CHECK_STATE |
11118 ADD_CHILD_NOTIFY_FIRST_LAST |
11119 ADD_CHILD_SHOW_ON_SET_PARENT
11120 } ClutterActorAddChildFlags;
11123 * clutter_actor_add_child_internal:
11124 * @self: a #ClutterActor
11125 * @child: a #ClutterActor
11126 * @flags: control flags for actions
11127 * @add_func: delegate function
11128 * @data: (closure): data to pass to @add_func
11130 * Adds @child to the list of children of @self.
11132 * The actual insertion inside the list is delegated to @add_func: this
11133 * function will just set up the state, perform basic checks, and emit
11136 * The @flags argument is used to perform additional operations.
11139 clutter_actor_add_child_internal (ClutterActor *self,
11140 ClutterActor *child,
11141 ClutterActorAddChildFlags flags,
11142 ClutterActorAddChildFunc add_func,
11145 ClutterTextDirection text_dir;
11146 gboolean create_meta;
11147 gboolean emit_parent_set, emit_actor_added;
11148 gboolean check_state;
11149 gboolean notify_first_last;
11150 gboolean show_on_set_parent;
11151 ClutterActor *old_first_child, *old_last_child;
11153 if (child->priv->parent != NULL)
11155 g_warning ("The actor '%s' already has a parent, '%s'. You must "
11156 "use clutter_actor_remove_child() first.",
11157 _clutter_actor_get_debug_name (child),
11158 _clutter_actor_get_debug_name (child->priv->parent));
11162 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11164 g_warning ("The actor '%s' is a top-level actor, and cannot be "
11165 "a child of another actor.",
11166 _clutter_actor_get_debug_name (child));
11171 /* XXX - this check disallows calling methods that change the stacking
11172 * order within the destruction sequence, by triggering a critical
11173 * warning first, and leaving the actor in an undefined state, which
11174 * then ends up being caught by an assertion.
11176 * the reproducible sequence is:
11178 * - actor gets destroyed;
11179 * - another actor, linked to the first, will try to change the
11180 * stacking order of the first actor;
11181 * - changing the stacking order is a composite operation composed
11182 * by the following steps:
11183 * 1. ref() the child;
11184 * 2. remove_child_internal(), which removes the reference;
11185 * 3. add_child_internal(), which adds a reference;
11186 * - the state of the actor is not changed between (2) and (3), as
11187 * it could be an expensive recomputation;
11188 * - if (3) bails out, then the actor is in an undefined state, but
11190 * - the destruction sequence terminates, but the actor is unparented
11191 * while its state indicates being parented instead.
11192 * - assertion failure.
11194 * the obvious fix would be to decompose each set_child_*_sibling()
11195 * method into proper remove_child()/add_child(), with state validation;
11196 * this may cause excessive work, though, and trigger a cascade of other
11197 * bugs in code that assumes that a change in the stacking order is an
11198 * atomic operation.
11200 * another potential fix is to just remove this check here, and let
11201 * code doing stacking order changes inside the destruction sequence
11202 * of an actor continue doing the work.
11204 * the third fix is to silently bail out early from every
11205 * set_child_*_sibling() and set_child_at_index() method, and avoid
11208 * I have a preference for the second solution, since it involves the
11209 * least amount of work, and the least amount of code duplication.
11211 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11213 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11215 g_warning ("The actor '%s' is currently being destroyed, and "
11216 "cannot be added as a child of another actor.",
11217 _clutter_actor_get_debug_name (child));
11222 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11223 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11224 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11225 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11226 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11227 show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11229 old_first_child = self->priv->first_child;
11230 old_last_child = self->priv->last_child;
11232 g_object_freeze_notify (G_OBJECT (self));
11235 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11237 g_object_ref_sink (child);
11238 child->priv->parent = NULL;
11239 child->priv->next_sibling = NULL;
11240 child->priv->prev_sibling = NULL;
11242 /* delegate the actual insertion */
11243 add_func (self, child, data);
11245 g_assert (child->priv->parent == self);
11247 self->priv->n_children += 1;
11249 self->priv->age += 1;
11251 /* if push_internal() has been called then we automatically set
11252 * the flag on the actor
11254 if (self->priv->internal_child)
11255 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11257 /* clutter_actor_reparent() will emit ::parent-set for us */
11258 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11259 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11263 /* If parent is mapped or realized, we need to also be mapped or
11264 * realized once we're inside the parent.
11266 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11268 /* propagate the parent's text direction to the child */
11269 text_dir = clutter_actor_get_text_direction (self);
11270 clutter_actor_set_text_direction (child, text_dir);
11273 if (show_on_set_parent && child->priv->show_on_set_parent)
11274 clutter_actor_show (child);
11276 if (CLUTTER_ACTOR_IS_MAPPED (child))
11277 clutter_actor_queue_redraw (child);
11279 /* maintain the invariant that if an actor needs layout,
11280 * its parents do as well
11282 if (child->priv->needs_width_request ||
11283 child->priv->needs_height_request ||
11284 child->priv->needs_allocation)
11286 /* we work around the short-circuiting we do
11287 * in clutter_actor_queue_relayout() since we
11288 * want to force a relayout
11290 child->priv->needs_width_request = TRUE;
11291 child->priv->needs_height_request = TRUE;
11292 child->priv->needs_allocation = TRUE;
11294 clutter_actor_queue_relayout (child->priv->parent);
11297 if (emit_actor_added)
11298 g_signal_emit_by_name (self, "actor-added", child);
11300 if (notify_first_last)
11302 if (old_first_child != self->priv->first_child)
11303 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11305 if (old_last_child != self->priv->last_child)
11306 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11309 g_object_thaw_notify (G_OBJECT (self));
11313 * clutter_actor_add_child:
11314 * @self: a #ClutterActor
11315 * @child: a #ClutterActor
11317 * Adds @child to the children of @self.
11319 * This function will acquire a reference on @child that will only
11320 * be released when calling clutter_actor_remove_child().
11322 * This function will take into consideration the #ClutterActor:depth
11323 * of @child, and will keep the list of children sorted.
11325 * This function will emit the #ClutterContainer::actor-added signal
11331 clutter_actor_add_child (ClutterActor *self,
11332 ClutterActor *child)
11334 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11335 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11336 g_return_if_fail (self != child);
11337 g_return_if_fail (child->priv->parent == NULL);
11339 clutter_actor_add_child_internal (self, child,
11340 ADD_CHILD_DEFAULT_FLAGS,
11341 insert_child_at_depth,
11346 * clutter_actor_insert_child_at_index:
11347 * @self: a #ClutterActor
11348 * @child: a #ClutterActor
11349 * @index_: the index
11351 * Inserts @child into the list of children of @self, using the
11352 * given @index_. If @index_ is greater than the number of children
11353 * in @self, or is less than 0, then the new child is added at the end.
11355 * This function will acquire a reference on @child that will only
11356 * be released when calling clutter_actor_remove_child().
11358 * This function will not take into consideration the #ClutterActor:depth
11361 * This function will emit the #ClutterContainer::actor-added signal
11367 clutter_actor_insert_child_at_index (ClutterActor *self,
11368 ClutterActor *child,
11371 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11372 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11373 g_return_if_fail (self != child);
11374 g_return_if_fail (child->priv->parent == NULL);
11376 clutter_actor_add_child_internal (self, child,
11377 ADD_CHILD_DEFAULT_FLAGS,
11378 insert_child_at_index,
11379 GINT_TO_POINTER (index_));
11383 * clutter_actor_insert_child_above:
11384 * @self: a #ClutterActor
11385 * @child: a #ClutterActor
11386 * @sibling: (allow-none): a child of @self, or %NULL
11388 * Inserts @child into the list of children of @self, above another
11389 * child of @self or, if @sibling is %NULL, above all the children
11392 * This function will acquire a reference on @child that will only
11393 * be released when calling clutter_actor_remove_child().
11395 * This function will not take into consideration the #ClutterActor:depth
11398 * This function will emit the #ClutterContainer::actor-added signal
11404 clutter_actor_insert_child_above (ClutterActor *self,
11405 ClutterActor *child,
11406 ClutterActor *sibling)
11408 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11409 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11410 g_return_if_fail (self != child);
11411 g_return_if_fail (child != sibling);
11412 g_return_if_fail (child->priv->parent == NULL);
11413 g_return_if_fail (sibling == NULL ||
11414 (CLUTTER_IS_ACTOR (sibling) &&
11415 sibling->priv->parent == self));
11417 clutter_actor_add_child_internal (self, child,
11418 ADD_CHILD_DEFAULT_FLAGS,
11419 insert_child_above,
11424 * clutter_actor_insert_child_below:
11425 * @self: a #ClutterActor
11426 * @child: a #ClutterActor
11427 * @sibling: (allow-none): a child of @self, or %NULL
11429 * Inserts @child into the list of children of @self, below another
11430 * child of @self or, if @sibling is %NULL, below all the children
11433 * This function will acquire a reference on @child that will only
11434 * be released when calling clutter_actor_remove_child().
11436 * This function will not take into consideration the #ClutterActor:depth
11439 * This function will emit the #ClutterContainer::actor-added signal
11445 clutter_actor_insert_child_below (ClutterActor *self,
11446 ClutterActor *child,
11447 ClutterActor *sibling)
11449 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11450 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11451 g_return_if_fail (self != child);
11452 g_return_if_fail (child != sibling);
11453 g_return_if_fail (child->priv->parent == NULL);
11454 g_return_if_fail (sibling == NULL ||
11455 (CLUTTER_IS_ACTOR (sibling) &&
11456 sibling->priv->parent == self));
11458 clutter_actor_add_child_internal (self, child,
11459 ADD_CHILD_DEFAULT_FLAGS,
11460 insert_child_below,
11465 * clutter_actor_set_parent:
11466 * @self: A #ClutterActor
11467 * @parent: A new #ClutterActor parent
11469 * Sets the parent of @self to @parent.
11471 * This function will result in @parent acquiring a reference on @self,
11472 * eventually by sinking its floating reference first. The reference
11473 * will be released by clutter_actor_unparent().
11475 * This function should only be called by legacy #ClutterActor<!-- -->s
11476 * implementing the #ClutterContainer interface.
11478 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11481 clutter_actor_set_parent (ClutterActor *self,
11482 ClutterActor *parent)
11484 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11485 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11486 g_return_if_fail (self != parent);
11487 g_return_if_fail (self->priv->parent == NULL);
11489 /* as this function will be called inside ClutterContainer::add
11490 * implementations or when building up a composite actor, we have
11491 * to preserve the old behaviour, and not create child meta or
11492 * emit the ::actor-added signal, to avoid recursion or double
11495 clutter_actor_add_child_internal (parent, self,
11496 ADD_CHILD_LEGACY_FLAGS,
11497 insert_child_at_depth,
11502 * clutter_actor_get_parent:
11503 * @self: A #ClutterActor
11505 * Retrieves the parent of @self.
11507 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11508 * if no parent is set
11511 clutter_actor_get_parent (ClutterActor *self)
11513 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11515 return self->priv->parent;
11519 * clutter_actor_get_paint_visibility:
11520 * @self: A #ClutterActor
11522 * Retrieves the 'paint' visibility of an actor recursively checking for non
11525 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11527 * Return Value: %TRUE if the actor is visibile and will be painted.
11532 clutter_actor_get_paint_visibility (ClutterActor *actor)
11534 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11536 return CLUTTER_ACTOR_IS_MAPPED (actor);
11540 * clutter_actor_remove_child:
11541 * @self: a #ClutterActor
11542 * @child: a #ClutterActor
11544 * Removes @child from the children of @self.
11546 * This function will release the reference added by
11547 * clutter_actor_add_child(), so if you want to keep using @child
11548 * you will have to acquire a referenced on it before calling this
11551 * This function will emit the #ClutterContainer::actor-removed
11557 clutter_actor_remove_child (ClutterActor *self,
11558 ClutterActor *child)
11560 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11561 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11562 g_return_if_fail (self != child);
11563 g_return_if_fail (child->priv->parent != NULL);
11564 g_return_if_fail (child->priv->parent == self);
11566 clutter_actor_remove_child_internal (self, child,
11567 REMOVE_CHILD_DEFAULT_FLAGS);
11571 * clutter_actor_remove_all_children:
11572 * @self: a #ClutterActor
11574 * Removes all children of @self.
11576 * This function releases the reference added by inserting a child actor
11577 * in the list of children of @self.
11579 * If the reference count of a child drops to zero, the child will be
11580 * destroyed. If you want to ensure the destruction of all the children
11581 * of @self, use clutter_actor_destroy_all_children().
11586 clutter_actor_remove_all_children (ClutterActor *self)
11588 ClutterActorIter iter;
11590 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11592 if (self->priv->n_children == 0)
11595 g_object_freeze_notify (G_OBJECT (self));
11597 clutter_actor_iter_init (&iter, self);
11598 while (clutter_actor_iter_next (&iter, NULL))
11599 clutter_actor_iter_remove (&iter);
11601 g_object_thaw_notify (G_OBJECT (self));
11604 g_assert (self->priv->first_child == NULL);
11605 g_assert (self->priv->last_child == NULL);
11606 g_assert (self->priv->n_children == 0);
11610 * clutter_actor_destroy_all_children:
11611 * @self: a #ClutterActor
11613 * Destroys all children of @self.
11615 * This function releases the reference added by inserting a child
11616 * actor in the list of children of @self, and ensures that the
11617 * #ClutterActor::destroy signal is emitted on each child of the
11620 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11621 * when its reference count drops to 0; the default handler of the
11622 * #ClutterActor::destroy signal will destroy all the children of an
11623 * actor. This function ensures that all children are destroyed, instead
11624 * of just removed from @self, unlike clutter_actor_remove_all_children()
11625 * which will merely release the reference and remove each child.
11627 * Unless you acquired an additional reference on each child of @self
11628 * prior to calling clutter_actor_remove_all_children() and want to reuse
11629 * the actors, you should use clutter_actor_destroy_all_children() in
11630 * order to make sure that children are destroyed and signal handlers
11631 * are disconnected even in cases where circular references prevent this
11632 * from automatically happening through reference counting alone.
11637 clutter_actor_destroy_all_children (ClutterActor *self)
11639 ClutterActorIter iter;
11641 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11643 if (self->priv->n_children == 0)
11646 g_object_freeze_notify (G_OBJECT (self));
11648 clutter_actor_iter_init (&iter, self);
11649 while (clutter_actor_iter_next (&iter, NULL))
11650 clutter_actor_iter_destroy (&iter);
11652 g_object_thaw_notify (G_OBJECT (self));
11655 g_assert (self->priv->first_child == NULL);
11656 g_assert (self->priv->last_child == NULL);
11657 g_assert (self->priv->n_children == 0);
11660 typedef struct _InsertBetweenData {
11661 ClutterActor *prev_sibling;
11662 ClutterActor *next_sibling;
11663 } InsertBetweenData;
11666 insert_child_between (ClutterActor *self,
11667 ClutterActor *child,
11670 InsertBetweenData *data = data_;
11671 ClutterActor *prev_sibling = data->prev_sibling;
11672 ClutterActor *next_sibling = data->next_sibling;
11674 child->priv->parent = self;
11675 child->priv->prev_sibling = prev_sibling;
11676 child->priv->next_sibling = next_sibling;
11678 if (prev_sibling != NULL)
11679 prev_sibling->priv->next_sibling = child;
11681 if (next_sibling != NULL)
11682 next_sibling->priv->prev_sibling = child;
11684 if (child->priv->prev_sibling == NULL)
11685 self->priv->first_child = child;
11687 if (child->priv->next_sibling == NULL)
11688 self->priv->last_child = child;
11692 * clutter_actor_replace_child:
11693 * @self: a #ClutterActor
11694 * @old_child: the child of @self to replace
11695 * @new_child: the #ClutterActor to replace @old_child
11697 * Replaces @old_child with @new_child in the list of children of @self.
11702 clutter_actor_replace_child (ClutterActor *self,
11703 ClutterActor *old_child,
11704 ClutterActor *new_child)
11706 ClutterActor *prev_sibling, *next_sibling;
11707 InsertBetweenData clos;
11709 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11710 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11711 g_return_if_fail (old_child->priv->parent == self);
11712 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11713 g_return_if_fail (old_child != new_child);
11714 g_return_if_fail (new_child != self);
11715 g_return_if_fail (new_child->priv->parent == NULL);
11717 prev_sibling = old_child->priv->prev_sibling;
11718 next_sibling = old_child->priv->next_sibling;
11719 clutter_actor_remove_child_internal (self, old_child,
11720 REMOVE_CHILD_DEFAULT_FLAGS);
11722 clos.prev_sibling = prev_sibling;
11723 clos.next_sibling = next_sibling;
11724 clutter_actor_add_child_internal (self, new_child,
11725 ADD_CHILD_DEFAULT_FLAGS,
11726 insert_child_between,
11731 * clutter_actor_unparent:
11732 * @self: a #ClutterActor
11734 * Removes the parent of @self.
11736 * This will cause the parent of @self to release the reference
11737 * acquired when calling clutter_actor_set_parent(), so if you
11738 * want to keep @self you will have to acquire a reference of
11739 * your own, through g_object_ref().
11741 * This function should only be called by legacy #ClutterActor<!-- -->s
11742 * implementing the #ClutterContainer interface.
11746 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11749 clutter_actor_unparent (ClutterActor *self)
11751 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11753 if (self->priv->parent == NULL)
11756 clutter_actor_remove_child_internal (self->priv->parent, self,
11757 REMOVE_CHILD_LEGACY_FLAGS);
11761 * clutter_actor_reparent:
11762 * @self: a #ClutterActor
11763 * @new_parent: the new #ClutterActor parent
11765 * Resets the parent actor of @self.
11767 * This function is logically equivalent to calling clutter_actor_unparent()
11768 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11769 * ensures the child is not finalized when unparented, and emits the
11770 * #ClutterActor::parent-set signal only once.
11772 * In reality, calling this function is less useful than it sounds, as some
11773 * application code may rely on changes in the intermediate state between
11774 * removal and addition of the actor from its old parent to the @new_parent.
11775 * Thus, it is strongly encouraged to avoid using this function in application
11780 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11781 * clutter_actor_add_child() instead; remember to take a reference on
11782 * the actor being removed before calling clutter_actor_remove_child()
11783 * to avoid the reference count dropping to zero and the actor being
11787 clutter_actor_reparent (ClutterActor *self,
11788 ClutterActor *new_parent)
11790 ClutterActorPrivate *priv;
11792 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11793 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11794 g_return_if_fail (self != new_parent);
11796 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11798 g_warning ("Cannot set a parent on a toplevel actor");
11802 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11804 g_warning ("Cannot set a parent currently being destroyed");
11810 if (priv->parent != new_parent)
11812 ClutterActor *old_parent;
11814 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11816 old_parent = priv->parent;
11818 g_object_ref (self);
11820 if (old_parent != NULL)
11822 /* go through the Container implementation if this is a regular
11823 * child and not an internal one
11825 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11827 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11829 /* this will have to call unparent() */
11830 clutter_container_remove_actor (parent, self);
11833 clutter_actor_remove_child_internal (old_parent, self,
11834 REMOVE_CHILD_LEGACY_FLAGS);
11837 /* Note, will call set_parent() */
11838 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11839 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11841 clutter_actor_add_child_internal (new_parent, self,
11842 ADD_CHILD_LEGACY_FLAGS,
11843 insert_child_at_depth,
11846 /* we emit the ::parent-set signal once */
11847 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11849 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11851 /* the IN_REPARENT flag suspends state updates */
11852 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11854 g_object_unref (self);
11859 * clutter_actor_contains:
11860 * @self: A #ClutterActor
11861 * @descendant: A #ClutterActor, possibly contained in @self
11863 * Determines if @descendant is contained inside @self (either as an
11864 * immediate child, or as a deeper descendant). If @self and
11865 * @descendant point to the same actor then it will also return %TRUE.
11867 * Return value: whether @descendent is contained within @self
11872 clutter_actor_contains (ClutterActor *self,
11873 ClutterActor *descendant)
11875 ClutterActor *actor;
11877 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11878 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11880 for (actor = descendant; actor; actor = actor->priv->parent)
11888 * clutter_actor_set_child_above_sibling:
11889 * @self: a #ClutterActor
11890 * @child: a #ClutterActor child of @self
11891 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11893 * Sets @child to be above @sibling in the list of children of @self.
11895 * If @sibling is %NULL, @child will be the new last child of @self.
11897 * This function is logically equivalent to removing @child and using
11898 * clutter_actor_insert_child_above(), but it will not emit signals
11899 * or change state on @child.
11904 clutter_actor_set_child_above_sibling (ClutterActor *self,
11905 ClutterActor *child,
11906 ClutterActor *sibling)
11908 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11909 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11910 g_return_if_fail (child->priv->parent == self);
11911 g_return_if_fail (child != sibling);
11912 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11914 if (sibling != NULL)
11915 g_return_if_fail (sibling->priv->parent == self);
11917 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11918 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11919 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11922 /* we don't want to change the state of child, or emit signals, or
11923 * regenerate ChildMeta instances here, but we still want to follow
11924 * the correct sequence of steps encoded in remove_child() and
11925 * add_child(), so that correctness is ensured, and we only go
11926 * through one known code path.
11928 g_object_ref (child);
11929 clutter_actor_remove_child_internal (self, child, 0);
11930 clutter_actor_add_child_internal (self, child,
11931 ADD_CHILD_NOTIFY_FIRST_LAST,
11932 insert_child_above,
11935 clutter_actor_queue_relayout (self);
11939 * clutter_actor_set_child_below_sibling:
11940 * @self: a #ClutterActor
11941 * @child: a #ClutterActor child of @self
11942 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11944 * Sets @child to be below @sibling in the list of children of @self.
11946 * If @sibling is %NULL, @child will be the new first child of @self.
11948 * This function is logically equivalent to removing @self and using
11949 * clutter_actor_insert_child_below(), but it will not emit signals
11950 * or change state on @child.
11955 clutter_actor_set_child_below_sibling (ClutterActor *self,
11956 ClutterActor *child,
11957 ClutterActor *sibling)
11959 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11960 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11961 g_return_if_fail (child->priv->parent == self);
11962 g_return_if_fail (child != sibling);
11963 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11965 if (sibling != NULL)
11966 g_return_if_fail (sibling->priv->parent == self);
11968 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11969 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11970 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11973 /* see the comment in set_child_above_sibling() */
11974 g_object_ref (child);
11975 clutter_actor_remove_child_internal (self, child, 0);
11976 clutter_actor_add_child_internal (self, child,
11977 ADD_CHILD_NOTIFY_FIRST_LAST,
11978 insert_child_below,
11981 clutter_actor_queue_relayout (self);
11985 * clutter_actor_set_child_at_index:
11986 * @self: a #ClutterActor
11987 * @child: a #ClutterActor child of @self
11988 * @index_: the new index for @child
11990 * Changes the index of @child in the list of children of @self.
11992 * This function is logically equivalent to removing @child and
11993 * calling clutter_actor_insert_child_at_index(), but it will not
11994 * emit signals or change state on @child.
11999 clutter_actor_set_child_at_index (ClutterActor *self,
12000 ClutterActor *child,
12003 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12004 g_return_if_fail (CLUTTER_IS_ACTOR (child));
12005 g_return_if_fail (child->priv->parent == self);
12006 g_return_if_fail (index_ <= self->priv->n_children);
12008 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12009 CLUTTER_ACTOR_IN_DESTRUCTION (child))
12012 g_object_ref (child);
12013 clutter_actor_remove_child_internal (self, child, 0);
12014 clutter_actor_add_child_internal (self, child,
12015 ADD_CHILD_NOTIFY_FIRST_LAST,
12016 insert_child_at_index,
12017 GINT_TO_POINTER (index_));
12019 clutter_actor_queue_relayout (self);
12023 * clutter_actor_raise:
12024 * @self: A #ClutterActor
12025 * @below: (allow-none): A #ClutterActor to raise above.
12027 * Puts @self above @below.
12029 * Both actors must have the same parent, and the parent must implement
12030 * the #ClutterContainer interface
12032 * This function calls clutter_container_raise_child() internally.
12034 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12037 clutter_actor_raise (ClutterActor *self,
12038 ClutterActor *below)
12040 ClutterActor *parent;
12042 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12044 parent = clutter_actor_get_parent (self);
12045 if (parent == NULL)
12047 g_warning ("%s: Actor '%s' is not inside a container",
12049 _clutter_actor_get_debug_name (self));
12055 if (parent != clutter_actor_get_parent (below))
12057 g_warning ("%s Actor '%s' is not in the same container as "
12060 _clutter_actor_get_debug_name (self),
12061 _clutter_actor_get_debug_name (below));
12066 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12070 * clutter_actor_lower:
12071 * @self: A #ClutterActor
12072 * @above: (allow-none): A #ClutterActor to lower below
12074 * Puts @self below @above.
12076 * Both actors must have the same parent, and the parent must implement
12077 * the #ClutterContainer interface.
12079 * This function calls clutter_container_lower_child() internally.
12081 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12084 clutter_actor_lower (ClutterActor *self,
12085 ClutterActor *above)
12087 ClutterActor *parent;
12089 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12091 parent = clutter_actor_get_parent (self);
12092 if (parent == NULL)
12094 g_warning ("%s: Actor of type %s is not inside a container",
12096 _clutter_actor_get_debug_name (self));
12102 if (parent != clutter_actor_get_parent (above))
12104 g_warning ("%s: Actor '%s' is not in the same container as "
12107 _clutter_actor_get_debug_name (self),
12108 _clutter_actor_get_debug_name (above));
12113 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12117 * clutter_actor_raise_top:
12118 * @self: A #ClutterActor
12120 * Raises @self to the top.
12122 * This function calls clutter_actor_raise() internally.
12124 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12125 * a %NULL sibling, instead.
12128 clutter_actor_raise_top (ClutterActor *self)
12130 clutter_actor_raise (self, NULL);
12134 * clutter_actor_lower_bottom:
12135 * @self: A #ClutterActor
12137 * Lowers @self to the bottom.
12139 * This function calls clutter_actor_lower() internally.
12141 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12142 * a %NULL sibling, instead.
12145 clutter_actor_lower_bottom (ClutterActor *self)
12147 clutter_actor_lower (self, NULL);
12155 * clutter_actor_event:
12156 * @actor: a #ClutterActor
12157 * @event: a #ClutterEvent
12158 * @capture: TRUE if event in in capture phase, FALSE otherwise.
12160 * This function is used to emit an event on the main stage.
12161 * You should rarely need to use this function, except for
12162 * synthetising events.
12164 * Return value: the return value from the signal emission: %TRUE
12165 * if the actor handled the event, or %FALSE if the event was
12171 clutter_actor_event (ClutterActor *actor,
12172 ClutterEvent *event,
12175 gboolean retval = FALSE;
12176 gint signal_num = -1;
12178 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12179 g_return_val_if_fail (event != NULL, FALSE);
12181 g_object_ref (actor);
12185 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12191 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12195 switch (event->type)
12197 case CLUTTER_NOTHING:
12199 case CLUTTER_BUTTON_PRESS:
12200 signal_num = BUTTON_PRESS_EVENT;
12202 case CLUTTER_BUTTON_RELEASE:
12203 signal_num = BUTTON_RELEASE_EVENT;
12205 case CLUTTER_SCROLL:
12206 signal_num = SCROLL_EVENT;
12208 case CLUTTER_KEY_PRESS:
12209 signal_num = KEY_PRESS_EVENT;
12211 case CLUTTER_KEY_RELEASE:
12212 signal_num = KEY_RELEASE_EVENT;
12214 case CLUTTER_MOTION:
12215 signal_num = MOTION_EVENT;
12217 case CLUTTER_ENTER:
12218 signal_num = ENTER_EVENT;
12220 case CLUTTER_LEAVE:
12221 signal_num = LEAVE_EVENT;
12223 case CLUTTER_DELETE:
12224 case CLUTTER_DESTROY_NOTIFY:
12225 case CLUTTER_CLIENT_MESSAGE:
12231 if (signal_num != -1)
12232 g_signal_emit (actor, actor_signals[signal_num], 0,
12237 g_object_unref (actor);
12243 * clutter_actor_set_reactive:
12244 * @actor: a #ClutterActor
12245 * @reactive: whether the actor should be reactive to events
12247 * Sets @actor as reactive. Reactive actors will receive events.
12252 clutter_actor_set_reactive (ClutterActor *actor,
12255 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12257 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12261 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12263 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12265 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12269 * clutter_actor_get_reactive:
12270 * @actor: a #ClutterActor
12272 * Checks whether @actor is marked as reactive.
12274 * Return value: %TRUE if the actor is reactive
12279 clutter_actor_get_reactive (ClutterActor *actor)
12281 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12283 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12287 * clutter_actor_get_anchor_point:
12288 * @self: a #ClutterActor
12289 * @anchor_x: (out): return location for the X coordinate of the anchor point
12290 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12292 * Gets the current anchor point of the @actor in pixels.
12297 clutter_actor_get_anchor_point (ClutterActor *self,
12301 const ClutterTransformInfo *info;
12303 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12305 info = _clutter_actor_get_transform_info_or_defaults (self);
12306 clutter_anchor_coord_get_units (self, &info->anchor,
12313 * clutter_actor_set_anchor_point:
12314 * @self: a #ClutterActor
12315 * @anchor_x: X coordinate of the anchor point
12316 * @anchor_y: Y coordinate of the anchor point
12318 * Sets an anchor point for @self. The anchor point is a point in the
12319 * coordinate space of an actor to which the actor position within its
12320 * parent is relative; the default is (0, 0), i.e. the top-left corner
12326 clutter_actor_set_anchor_point (ClutterActor *self,
12330 ClutterTransformInfo *info;
12331 ClutterActorPrivate *priv;
12332 gboolean changed = FALSE;
12333 gfloat old_anchor_x, old_anchor_y;
12336 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12338 obj = G_OBJECT (self);
12340 info = _clutter_actor_get_transform_info (self);
12342 g_object_freeze_notify (obj);
12344 clutter_anchor_coord_get_units (self, &info->anchor,
12349 if (info->anchor.is_fractional)
12350 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12352 if (old_anchor_x != anchor_x)
12354 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12358 if (old_anchor_y != anchor_y)
12360 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12364 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12368 priv->transform_valid = FALSE;
12369 clutter_actor_queue_redraw (self);
12372 g_object_thaw_notify (obj);
12376 * clutter_actor_get_anchor_point_gravity:
12377 * @self: a #ClutterActor
12379 * Retrieves the anchor position expressed as a #ClutterGravity. If
12380 * the anchor point was specified using pixels or units this will
12381 * return %CLUTTER_GRAVITY_NONE.
12383 * Return value: the #ClutterGravity used by the anchor point
12388 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12390 const ClutterTransformInfo *info;
12392 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12394 info = _clutter_actor_get_transform_info_or_defaults (self);
12396 return clutter_anchor_coord_get_gravity (&info->anchor);
12400 * clutter_actor_move_anchor_point:
12401 * @self: a #ClutterActor
12402 * @anchor_x: X coordinate of the anchor point
12403 * @anchor_y: Y coordinate of the anchor point
12405 * Sets an anchor point for the actor, and adjusts the actor postion so that
12406 * the relative position of the actor toward its parent remains the same.
12411 clutter_actor_move_anchor_point (ClutterActor *self,
12415 gfloat old_anchor_x, old_anchor_y;
12416 const ClutterTransformInfo *info;
12418 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12420 info = _clutter_actor_get_transform_info (self);
12421 clutter_anchor_coord_get_units (self, &info->anchor,
12426 g_object_freeze_notify (G_OBJECT (self));
12428 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12430 if (self->priv->position_set)
12431 clutter_actor_move_by (self,
12432 anchor_x - old_anchor_x,
12433 anchor_y - old_anchor_y);
12435 g_object_thaw_notify (G_OBJECT (self));
12439 * clutter_actor_move_anchor_point_from_gravity:
12440 * @self: a #ClutterActor
12441 * @gravity: #ClutterGravity.
12443 * Sets an anchor point on the actor based on the given gravity, adjusting the
12444 * actor postion so that its relative position within its parent remains
12447 * Since version 1.0 the anchor point will be stored as a gravity so
12448 * that if the actor changes size then the anchor point will move. For
12449 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12450 * and later double the size of the actor, the anchor point will move
12451 * to the bottom right.
12456 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12457 ClutterGravity gravity)
12459 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12460 const ClutterTransformInfo *info;
12461 ClutterActorPrivate *priv;
12463 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12466 info = _clutter_actor_get_transform_info (self);
12468 g_object_freeze_notify (G_OBJECT (self));
12470 clutter_anchor_coord_get_units (self, &info->anchor,
12474 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12475 clutter_anchor_coord_get_units (self, &info->anchor,
12480 if (priv->position_set)
12481 clutter_actor_move_by (self,
12482 new_anchor_x - old_anchor_x,
12483 new_anchor_y - old_anchor_y);
12485 g_object_thaw_notify (G_OBJECT (self));
12489 * clutter_actor_set_anchor_point_from_gravity:
12490 * @self: a #ClutterActor
12491 * @gravity: #ClutterGravity.
12493 * Sets an anchor point on the actor, based on the given gravity (this is a
12494 * convenience function wrapping clutter_actor_set_anchor_point()).
12496 * Since version 1.0 the anchor point will be stored as a gravity so
12497 * that if the actor changes size then the anchor point will move. For
12498 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12499 * and later double the size of the actor, the anchor point will move
12500 * to the bottom right.
12505 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12506 ClutterGravity gravity)
12508 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12510 if (gravity == CLUTTER_GRAVITY_NONE)
12511 clutter_actor_set_anchor_point (self, 0, 0);
12514 GObject *obj = G_OBJECT (self);
12515 ClutterTransformInfo *info;
12517 g_object_freeze_notify (obj);
12519 info = _clutter_actor_get_transform_info (self);
12520 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12522 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12523 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12524 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12526 self->priv->transform_valid = FALSE;
12528 clutter_actor_queue_redraw (self);
12530 g_object_thaw_notify (obj);
12535 clutter_actor_store_content_box (ClutterActor *self,
12536 const ClutterActorBox *box)
12540 self->priv->content_box = *box;
12541 self->priv->content_box_valid = TRUE;
12544 self->priv->content_box_valid = FALSE;
12546 clutter_actor_queue_redraw (self);
12548 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12552 clutter_container_iface_init (ClutterContainerIface *iface)
12554 /* we don't override anything, as ClutterContainer already has a default
12555 * implementation that we can use, and which calls into our own API.
12570 parse_units (ClutterActor *self,
12571 ParseDimension dimension,
12574 GValue value = G_VALUE_INIT;
12577 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12580 json_node_get_value (node, &value);
12582 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12584 retval = (gfloat) g_value_get_int64 (&value);
12586 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12588 retval = g_value_get_double (&value);
12590 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12592 ClutterUnits units;
12595 res = clutter_units_from_string (&units, g_value_get_string (&value));
12597 retval = clutter_units_to_pixels (&units);
12600 g_warning ("Invalid value '%s': integers, strings or floating point "
12601 "values can be used for the x, y, width and height "
12602 "properties. Valid modifiers for strings are 'px', 'mm', "
12604 g_value_get_string (&value));
12610 g_warning ("Invalid value of type '%s': integers, strings of floating "
12611 "point values can be used for the x, y, width, height "
12612 "anchor-x and anchor-y properties.",
12613 g_type_name (G_VALUE_TYPE (&value)));
12616 g_value_unset (&value);
12622 ClutterRotateAxis axis;
12631 static inline gboolean
12632 parse_rotation_array (ClutterActor *actor,
12634 RotationInfo *info)
12638 if (json_array_get_length (array) != 2)
12642 element = json_array_get_element (array, 0);
12643 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12644 info->angle = json_node_get_double (element);
12649 element = json_array_get_element (array, 1);
12650 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12652 JsonArray *center = json_node_get_array (element);
12654 if (json_array_get_length (center) != 2)
12657 switch (info->axis)
12659 case CLUTTER_X_AXIS:
12660 info->center_y = parse_units (actor, PARSE_Y,
12661 json_array_get_element (center, 0));
12662 info->center_z = parse_units (actor, PARSE_Y,
12663 json_array_get_element (center, 1));
12666 case CLUTTER_Y_AXIS:
12667 info->center_x = parse_units (actor, PARSE_X,
12668 json_array_get_element (center, 0));
12669 info->center_z = parse_units (actor, PARSE_X,
12670 json_array_get_element (center, 1));
12673 case CLUTTER_Z_AXIS:
12674 info->center_x = parse_units (actor, PARSE_X,
12675 json_array_get_element (center, 0));
12676 info->center_y = parse_units (actor, PARSE_Y,
12677 json_array_get_element (center, 1));
12686 parse_rotation (ClutterActor *actor,
12688 RotationInfo *info)
12692 gboolean retval = FALSE;
12694 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12696 g_warning ("Invalid node of type '%s' found, expecting an array",
12697 json_node_type_name (node));
12701 array = json_node_get_array (node);
12702 len = json_array_get_length (array);
12704 for (i = 0; i < len; i++)
12706 JsonNode *element = json_array_get_element (array, i);
12707 JsonObject *object;
12710 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12712 g_warning ("Invalid node of type '%s' found, expecting an object",
12713 json_node_type_name (element));
12717 object = json_node_get_object (element);
12719 if (json_object_has_member (object, "x-axis"))
12721 member = json_object_get_member (object, "x-axis");
12723 info->axis = CLUTTER_X_AXIS;
12725 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12727 info->angle = json_node_get_double (member);
12730 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12731 retval = parse_rotation_array (actor,
12732 json_node_get_array (member),
12737 else if (json_object_has_member (object, "y-axis"))
12739 member = json_object_get_member (object, "y-axis");
12741 info->axis = CLUTTER_Y_AXIS;
12743 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12745 info->angle = json_node_get_double (member);
12748 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12749 retval = parse_rotation_array (actor,
12750 json_node_get_array (member),
12755 else if (json_object_has_member (object, "z-axis"))
12757 member = json_object_get_member (object, "z-axis");
12759 info->axis = CLUTTER_Z_AXIS;
12761 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12763 info->angle = json_node_get_double (member);
12766 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12767 retval = parse_rotation_array (actor,
12768 json_node_get_array (member),
12779 parse_actor_metas (ClutterScript *script,
12780 ClutterActor *actor,
12783 GList *elements, *l;
12784 GSList *retval = NULL;
12786 if (!JSON_NODE_HOLDS_ARRAY (node))
12789 elements = json_array_get_elements (json_node_get_array (node));
12791 for (l = elements; l != NULL; l = l->next)
12793 JsonNode *element = l->data;
12794 const gchar *id_ = _clutter_script_get_id_from_node (element);
12797 if (id_ == NULL || *id_ == '\0')
12800 meta = clutter_script_get_object (script, id_);
12804 retval = g_slist_prepend (retval, meta);
12807 g_list_free (elements);
12809 return g_slist_reverse (retval);
12813 parse_behaviours (ClutterScript *script,
12814 ClutterActor *actor,
12817 GList *elements, *l;
12818 GSList *retval = NULL;
12820 if (!JSON_NODE_HOLDS_ARRAY (node))
12823 elements = json_array_get_elements (json_node_get_array (node));
12825 for (l = elements; l != NULL; l = l->next)
12827 JsonNode *element = l->data;
12828 const gchar *id_ = _clutter_script_get_id_from_node (element);
12829 GObject *behaviour;
12831 if (id_ == NULL || *id_ == '\0')
12834 behaviour = clutter_script_get_object (script, id_);
12835 if (behaviour == NULL)
12838 retval = g_slist_prepend (retval, behaviour);
12841 g_list_free (elements);
12843 return g_slist_reverse (retval);
12847 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12848 ClutterScript *script,
12853 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12854 gboolean retval = FALSE;
12856 if ((name[0] == 'x' && name[1] == '\0') ||
12857 (name[0] == 'y' && name[1] == '\0') ||
12858 (strcmp (name, "width") == 0) ||
12859 (strcmp (name, "height") == 0) ||
12860 (strcmp (name, "anchor_x") == 0) ||
12861 (strcmp (name, "anchor_y") == 0))
12863 ParseDimension dimension;
12866 if (name[0] == 'x')
12867 dimension = PARSE_X;
12868 else if (name[0] == 'y')
12869 dimension = PARSE_Y;
12870 else if (name[0] == 'w')
12871 dimension = PARSE_WIDTH;
12872 else if (name[0] == 'h')
12873 dimension = PARSE_HEIGHT;
12874 else if (name[0] == 'a' && name[7] == 'x')
12875 dimension = PARSE_ANCHOR_X;
12876 else if (name[0] == 'a' && name[7] == 'y')
12877 dimension = PARSE_ANCHOR_Y;
12881 units = parse_units (actor, dimension, node);
12883 /* convert back to pixels: all properties are pixel-based */
12884 g_value_init (value, G_TYPE_FLOAT);
12885 g_value_set_float (value, units);
12889 else if (strcmp (name, "rotation") == 0)
12891 RotationInfo *info;
12893 info = g_slice_new0 (RotationInfo);
12894 retval = parse_rotation (actor, node, info);
12898 g_value_init (value, G_TYPE_POINTER);
12899 g_value_set_pointer (value, info);
12902 g_slice_free (RotationInfo, info);
12904 else if (strcmp (name, "behaviours") == 0)
12908 #ifdef CLUTTER_ENABLE_DEBUG
12909 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12910 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12911 "and it should not be used in newly "
12912 "written ClutterScript definitions.");
12915 l = parse_behaviours (script, actor, node);
12917 g_value_init (value, G_TYPE_POINTER);
12918 g_value_set_pointer (value, l);
12922 else if (strcmp (name, "actions") == 0 ||
12923 strcmp (name, "constraints") == 0 ||
12924 strcmp (name, "effects") == 0)
12928 l = parse_actor_metas (script, actor, node);
12930 g_value_init (value, G_TYPE_POINTER);
12931 g_value_set_pointer (value, l);
12940 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12941 ClutterScript *script,
12943 const GValue *value)
12945 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12947 #ifdef CLUTTER_ENABLE_DEBUG
12948 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12950 gchar *tmp = g_strdup_value_contents (value);
12952 CLUTTER_NOTE (SCRIPT,
12953 "in ClutterActor::set_custom_property('%s') = %s",
12959 #endif /* CLUTTER_ENABLE_DEBUG */
12961 if (strcmp (name, "rotation") == 0)
12963 RotationInfo *info;
12965 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12968 info = g_value_get_pointer (value);
12970 clutter_actor_set_rotation (actor,
12971 info->axis, info->angle,
12976 g_slice_free (RotationInfo, info);
12981 if (strcmp (name, "behaviours") == 0)
12983 GSList *behaviours, *l;
12985 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12988 behaviours = g_value_get_pointer (value);
12989 for (l = behaviours; l != NULL; l = l->next)
12991 ClutterBehaviour *behaviour = l->data;
12993 clutter_behaviour_apply (behaviour, actor);
12996 g_slist_free (behaviours);
13001 if (strcmp (name, "actions") == 0 ||
13002 strcmp (name, "constraints") == 0 ||
13003 strcmp (name, "effects") == 0)
13007 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13010 metas = g_value_get_pointer (value);
13011 for (l = metas; l != NULL; l = l->next)
13013 if (name[0] == 'a')
13014 clutter_actor_add_action (actor, l->data);
13016 if (name[0] == 'c')
13017 clutter_actor_add_constraint (actor, l->data);
13019 if (name[0] == 'e')
13020 clutter_actor_add_effect (actor, l->data);
13023 g_slist_free (metas);
13028 g_object_set_property (G_OBJECT (scriptable), name, value);
13032 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13034 iface->parse_custom_node = clutter_actor_parse_custom_node;
13035 iface->set_custom_property = clutter_actor_set_custom_property;
13038 static ClutterActorMeta *
13039 get_meta_from_animation_property (ClutterActor *actor,
13043 ClutterActorPrivate *priv = actor->priv;
13044 ClutterActorMeta *meta = NULL;
13047 /* if this is not a special property, fall through */
13048 if (name[0] != '@')
13051 /* detect the properties named using the following spec:
13053 * @<section>.<meta-name>.<property-name>
13055 * where <section> can be one of the following:
13061 * and <meta-name> is the name set on a specific ActorMeta
13064 tokens = g_strsplit (name + 1, ".", -1);
13065 if (tokens == NULL || g_strv_length (tokens) != 3)
13067 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13069 g_strfreev (tokens);
13073 if (strcmp (tokens[0], "actions") == 0)
13074 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13076 if (strcmp (tokens[0], "constraints") == 0)
13077 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13079 if (strcmp (tokens[0], "effects") == 0)
13080 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13082 if (name_p != NULL)
13083 *name_p = g_strdup (tokens[2]);
13085 CLUTTER_NOTE (ANIMATION,
13086 "Looking for property '%s' of object '%s' in section '%s'",
13091 g_strfreev (tokens);
13096 static GParamSpec *
13097 clutter_actor_find_property (ClutterAnimatable *animatable,
13098 const gchar *property_name)
13100 ClutterActorMeta *meta = NULL;
13101 GObjectClass *klass = NULL;
13102 GParamSpec *pspec = NULL;
13103 gchar *p_name = NULL;
13105 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13111 klass = G_OBJECT_GET_CLASS (meta);
13113 pspec = g_object_class_find_property (klass, p_name);
13117 klass = G_OBJECT_GET_CLASS (animatable);
13119 pspec = g_object_class_find_property (klass, property_name);
13128 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13129 const gchar *property_name,
13132 ClutterActorMeta *meta = NULL;
13133 gchar *p_name = NULL;
13135 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13140 g_object_get_property (G_OBJECT (meta), p_name, initial);
13142 g_object_get_property (G_OBJECT (animatable), property_name, initial);
13148 * clutter_actor_set_animatable_property:
13149 * @actor: a #ClutterActor
13150 * @prop_id: the paramspec id
13151 * @value: the value to set
13152 * @pspec: the paramspec
13154 * Sets values of animatable properties.
13156 * This is a variant of clutter_actor_set_property() that gets called
13157 * by the #ClutterAnimatable implementation of #ClutterActor for the
13158 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13161 * Unlike the implementation of #GObjectClass.set_property(), this
13162 * function will not update the interval if a transition involving an
13163 * animatable property is in progress - this avoids cycles with the
13164 * transition API calling the public API.
13167 clutter_actor_set_animatable_property (ClutterActor *actor,
13169 const GValue *value,
13172 GObject *obj = G_OBJECT (actor);
13174 g_object_freeze_notify (obj);
13179 clutter_actor_set_x_internal (actor, g_value_get_float (value));
13183 clutter_actor_set_y_internal (actor, g_value_get_float (value));
13186 case PROP_POSITION:
13187 clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13191 clutter_actor_set_width_internal (actor, g_value_get_float (value));
13195 clutter_actor_set_height_internal (actor, g_value_get_float (value));
13199 clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13203 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13207 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13210 case PROP_BACKGROUND_COLOR:
13211 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13215 clutter_actor_set_scale_factor_internal (actor,
13216 g_value_get_double (value),
13221 clutter_actor_set_scale_factor_internal (actor,
13222 g_value_get_double (value),
13226 case PROP_ROTATION_ANGLE_X:
13227 clutter_actor_set_rotation_angle_internal (actor,
13229 g_value_get_double (value));
13232 case PROP_ROTATION_ANGLE_Y:
13233 clutter_actor_set_rotation_angle_internal (actor,
13235 g_value_get_double (value));
13238 case PROP_ROTATION_ANGLE_Z:
13239 clutter_actor_set_rotation_angle_internal (actor,
13241 g_value_get_double (value));
13244 case PROP_CONTENT_BOX:
13245 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13249 g_object_set_property (obj, pspec->name, value);
13253 g_object_thaw_notify (obj);
13257 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13258 const gchar *property_name,
13259 const GValue *final)
13261 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13262 ClutterActorMeta *meta = NULL;
13263 gchar *p_name = NULL;
13265 meta = get_meta_from_animation_property (actor,
13269 g_object_set_property (G_OBJECT (meta), p_name, final);
13272 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13275 pspec = g_object_class_find_property (obj_class, property_name);
13277 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13279 /* XXX - I'm going to the special hell for this */
13280 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13283 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13290 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13292 iface->find_property = clutter_actor_find_property;
13293 iface->get_initial_state = clutter_actor_get_initial_state;
13294 iface->set_final_state = clutter_actor_set_final_state;
13298 * clutter_actor_transform_stage_point:
13299 * @self: A #ClutterActor
13300 * @x: (in): x screen coordinate of the point to unproject
13301 * @y: (in): y screen coordinate of the point to unproject
13302 * @x_out: (out): return location for the unprojected x coordinance
13303 * @y_out: (out): return location for the unprojected y coordinance
13305 * This function translates screen coordinates (@x, @y) to
13306 * coordinates relative to the actor. For example, it can be used to translate
13307 * screen events from global screen coordinates into actor-local coordinates.
13309 * The conversion can fail, notably if the transform stack results in the
13310 * actor being projected on the screen as a mere line.
13312 * The conversion should not be expected to be pixel-perfect due to the
13313 * nature of the operation. In general the error grows when the skewing
13314 * of the actor rectangle on screen increases.
13316 * <note><para>This function can be computationally intensive.</para></note>
13318 * <note><para>This function only works when the allocation is up-to-date,
13319 * i.e. inside of paint().</para></note>
13321 * Return value: %TRUE if conversion was successful.
13326 clutter_actor_transform_stage_point (ClutterActor *self,
13332 ClutterVertex v[4];
13335 int du, dv, xi, yi;
13337 float xf, yf, wf, det;
13338 ClutterActorPrivate *priv;
13340 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13344 /* This implementation is based on the quad -> quad projection algorithm
13345 * described by Paul Heckbert in:
13347 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13349 * and the sample implementation at:
13351 * http://www.cs.cmu.edu/~ph/src/texfund/
13353 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13354 * quad to rectangle only, which significantly simplifies things; the
13355 * function calls have been unrolled, and most of the math is done in fixed
13359 clutter_actor_get_abs_allocation_vertices (self, v);
13361 /* Keeping these as ints simplifies the multiplication (no significant
13362 * loss of precision here).
13364 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13365 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13370 #define UX2FP(x) (x)
13371 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13373 /* First, find mapping from unit uv square to xy quadrilateral; this
13374 * equivalent to the pmap_square_quad() functions in the sample
13375 * implementation, which we can simplify, since our target is always
13378 px = v[0].x - v[1].x + v[3].x - v[2].x;
13379 py = v[0].y - v[1].y + v[3].y - v[2].y;
13383 /* affine transform */
13384 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13385 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13386 RQ[2][0] = UX2FP (v[0].x);
13387 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13388 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13389 RQ[2][1] = UX2FP (v[0].y);
13396 /* projective transform */
13397 double dx1, dx2, dy1, dy2, del;
13399 dx1 = UX2FP (v[1].x - v[3].x);
13400 dx2 = UX2FP (v[2].x - v[3].x);
13401 dy1 = UX2FP (v[1].y - v[3].y);
13402 dy2 = UX2FP (v[2].y - v[3].y);
13404 del = DET2FP (dx1, dx2, dy1, dy2);
13409 * The division here needs to be done in floating point for
13410 * precisions reasons.
13412 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13413 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13414 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13416 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13417 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13418 RQ[2][0] = UX2FP (v[0].x);
13419 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13420 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13421 RQ[2][1] = UX2FP (v[0].y);
13425 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13426 * square. Since our rectangle is based at 0,0 we only need to scale.
13436 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13439 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13440 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13441 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13442 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13443 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13444 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13445 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13446 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13447 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13450 * Check the resulting matrix is OK.
13452 det = (RQ[0][0] * ST[0][0])
13453 + (RQ[0][1] * ST[0][1])
13454 + (RQ[0][2] * ST[0][2]);
13459 * Now transform our point with the ST matrix; the notional w
13460 * coordinate is 1, hence the last part is simply added.
13465 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13466 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13467 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13482 * clutter_actor_is_rotated:
13483 * @self: a #ClutterActor
13485 * Checks whether any rotation is applied to the actor.
13487 * Return value: %TRUE if the actor is rotated.
13492 clutter_actor_is_rotated (ClutterActor *self)
13494 const ClutterTransformInfo *info;
13496 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13498 info = _clutter_actor_get_transform_info_or_defaults (self);
13500 if (info->rx_angle || info->ry_angle || info->rz_angle)
13507 * clutter_actor_is_scaled:
13508 * @self: a #ClutterActor
13510 * Checks whether the actor is scaled in either dimension.
13512 * Return value: %TRUE if the actor is scaled.
13517 clutter_actor_is_scaled (ClutterActor *self)
13519 const ClutterTransformInfo *info;
13521 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13523 info = _clutter_actor_get_transform_info_or_defaults (self);
13525 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13532 _clutter_actor_get_stage_internal (ClutterActor *actor)
13534 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13535 actor = actor->priv->parent;
13541 * clutter_actor_get_stage:
13542 * @actor: a #ClutterActor
13544 * Retrieves the #ClutterStage where @actor is contained.
13546 * Return value: (transfer none) (type Clutter.Stage): the stage
13547 * containing the actor, or %NULL
13552 clutter_actor_get_stage (ClutterActor *actor)
13554 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13556 return _clutter_actor_get_stage_internal (actor);
13560 * clutter_actor_allocate_available_size:
13561 * @self: a #ClutterActor
13562 * @x: the actor's X coordinate
13563 * @y: the actor's Y coordinate
13564 * @available_width: the maximum available width, or -1 to use the
13565 * actor's natural width
13566 * @available_height: the maximum available height, or -1 to use the
13567 * actor's natural height
13568 * @flags: flags controlling the allocation
13570 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13571 * preferred size, but limiting it to the maximum available width
13572 * and height provided.
13574 * This function will do the right thing when dealing with the
13575 * actor's request mode.
13577 * The implementation of this function is equivalent to:
13580 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13582 * clutter_actor_get_preferred_width (self, available_height,
13584 * &natural_width);
13585 * width = CLAMP (natural_width, min_width, available_width);
13587 * clutter_actor_get_preferred_height (self, width,
13589 * &natural_height);
13590 * height = CLAMP (natural_height, min_height, available_height);
13594 * clutter_actor_get_preferred_height (self, available_width,
13596 * &natural_height);
13597 * height = CLAMP (natural_height, min_height, available_height);
13599 * clutter_actor_get_preferred_width (self, height,
13601 * &natural_width);
13602 * width = CLAMP (natural_width, min_width, available_width);
13605 * box.x1 = x; box.y1 = y;
13606 * box.x2 = box.x1 + available_width;
13607 * box.y2 = box.y1 + available_height;
13608 * clutter_actor_allocate (self, &box, flags);
13611 * This function can be used by fluid layout managers to allocate
13612 * an actor's preferred size without making it bigger than the area
13613 * available for the container.
13618 clutter_actor_allocate_available_size (ClutterActor *self,
13621 gfloat available_width,
13622 gfloat available_height,
13623 ClutterAllocationFlags flags)
13625 ClutterActorPrivate *priv;
13626 gfloat width, height;
13627 gfloat min_width, min_height;
13628 gfloat natural_width, natural_height;
13629 ClutterActorBox box;
13631 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13635 width = height = 0.0;
13637 switch (priv->request_mode)
13639 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13640 clutter_actor_get_preferred_width (self, available_height,
13643 width = CLAMP (natural_width, min_width, available_width);
13645 clutter_actor_get_preferred_height (self, width,
13648 height = CLAMP (natural_height, min_height, available_height);
13651 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13652 clutter_actor_get_preferred_height (self, available_width,
13655 height = CLAMP (natural_height, min_height, available_height);
13657 clutter_actor_get_preferred_width (self, height,
13660 width = CLAMP (natural_width, min_width, available_width);
13667 box.x2 = box.x1 + width;
13668 box.y2 = box.y1 + height;
13669 clutter_actor_allocate (self, &box, flags);
13673 * clutter_actor_allocate_preferred_size:
13674 * @self: a #ClutterActor
13675 * @flags: flags controlling the allocation
13677 * Allocates the natural size of @self.
13679 * This function is a utility call for #ClutterActor implementations
13680 * that allocates the actor's preferred natural size. It can be used
13681 * by fixed layout managers (like #ClutterGroup or so called
13682 * 'composite actors') inside the ClutterActor::allocate
13683 * implementation to give each child exactly how much space it
13686 * This function is not meant to be used by applications. It is also
13687 * not meant to be used outside the implementation of the
13688 * ClutterActor::allocate virtual function.
13693 clutter_actor_allocate_preferred_size (ClutterActor *self,
13694 ClutterAllocationFlags flags)
13696 gfloat actor_x, actor_y;
13697 gfloat natural_width, natural_height;
13698 ClutterActorBox actor_box;
13700 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13702 actor_x = clutter_actor_get_x (self);
13703 actor_y = clutter_actor_get_y (self);
13705 clutter_actor_get_preferred_size (self,
13710 actor_box.x1 = actor_x;
13711 actor_box.y1 = actor_y;
13712 actor_box.x2 = actor_box.x1 + natural_width;
13713 actor_box.y2 = actor_box.y1 + natural_height;
13715 clutter_actor_allocate (self, &actor_box, flags);
13719 * clutter_actor_allocate_align_fill:
13720 * @self: a #ClutterActor
13721 * @box: a #ClutterActorBox, containing the available width and height
13722 * @x_align: the horizontal alignment, between 0 and 1
13723 * @y_align: the vertical alignment, between 0 and 1
13724 * @x_fill: whether the actor should fill horizontally
13725 * @y_fill: whether the actor should fill vertically
13726 * @flags: allocation flags to be passed to clutter_actor_allocate()
13728 * Allocates @self by taking into consideration the available allocation
13729 * area; an alignment factor on either axis; and whether the actor should
13730 * fill the allocation on either axis.
13732 * The @box should contain the available allocation width and height;
13733 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13734 * allocation will be offset by their value.
13736 * This function takes into consideration the geometry request specified by
13737 * the #ClutterActor:request-mode property, and the text direction.
13739 * This function is useful for fluid layout managers, like #ClutterBinLayout
13740 * or #ClutterTableLayout
13745 clutter_actor_allocate_align_fill (ClutterActor *self,
13746 const ClutterActorBox *box,
13751 ClutterAllocationFlags flags)
13753 ClutterActorPrivate *priv;
13754 ClutterActorBox allocation = { 0, };
13755 gfloat x_offset, y_offset;
13756 gfloat available_width, available_height;
13757 gfloat child_width, child_height;
13759 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13760 g_return_if_fail (box != NULL);
13761 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13762 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13766 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13767 clutter_actor_box_get_size (box, &available_width, &available_height);
13769 if (available_width < 0)
13770 available_width = 0;
13772 if (available_height < 0)
13773 available_height = 0;
13777 allocation.x1 = x_offset;
13778 allocation.x2 = allocation.x1 + available_width;
13783 allocation.y1 = y_offset;
13784 allocation.y2 = allocation.y1 + available_height;
13787 /* if we are filling horizontally and vertically then we're done */
13788 if (x_fill && y_fill)
13791 child_width = child_height = 0.0f;
13793 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13795 gfloat min_width, natural_width;
13796 gfloat min_height, natural_height;
13798 clutter_actor_get_preferred_width (self, available_height,
13802 child_width = CLAMP (natural_width, min_width, available_width);
13806 clutter_actor_get_preferred_height (self, child_width,
13810 child_height = CLAMP (natural_height, min_height, available_height);
13815 gfloat min_width, natural_width;
13816 gfloat min_height, natural_height;
13818 clutter_actor_get_preferred_height (self, available_width,
13822 child_height = CLAMP (natural_height, min_height, available_height);
13826 clutter_actor_get_preferred_width (self, child_height,
13830 child_width = CLAMP (natural_width, min_width, available_width);
13834 /* invert the horizontal alignment for RTL languages */
13835 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13836 x_align = 1.0 - x_align;
13840 allocation.x1 = x_offset
13841 + ((available_width - child_width) * x_align);
13842 allocation.x2 = allocation.x1 + child_width;
13847 allocation.y1 = y_offset
13848 + ((available_height - child_height) * y_align);
13849 allocation.y2 = allocation.y1 + child_height;
13853 clutter_actor_box_clamp_to_pixel (&allocation);
13854 clutter_actor_allocate (self, &allocation, flags);
13858 * clutter_actor_grab_key_focus:
13859 * @self: a #ClutterActor
13861 * Sets the key focus of the #ClutterStage including @self
13862 * to this #ClutterActor.
13867 clutter_actor_grab_key_focus (ClutterActor *self)
13869 ClutterActor *stage;
13871 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13873 stage = _clutter_actor_get_stage_internal (self);
13875 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13879 * clutter_actor_get_pango_context:
13880 * @self: a #ClutterActor
13882 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13883 * is already configured using the appropriate font map, resolution
13884 * and font options.
13886 * Unlike clutter_actor_create_pango_context(), this context is owend
13887 * by the #ClutterActor and it will be updated each time the options
13888 * stored by the #ClutterBackend change.
13890 * You can use the returned #PangoContext to create a #PangoLayout
13891 * and render text using cogl_pango_render_layout() to reuse the
13892 * glyphs cache also used by Clutter.
13894 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13895 * The returned #PangoContext is owned by the actor and should not be
13896 * unreferenced by the application code
13901 clutter_actor_get_pango_context (ClutterActor *self)
13903 ClutterActorPrivate *priv;
13905 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13909 if (priv->pango_context != NULL)
13910 return priv->pango_context;
13912 priv->pango_context = _clutter_context_get_pango_context ();
13913 g_object_ref (priv->pango_context);
13915 return priv->pango_context;
13919 * clutter_actor_create_pango_context:
13920 * @self: a #ClutterActor
13922 * Creates a #PangoContext for the given actor. The #PangoContext
13923 * is already configured using the appropriate font map, resolution
13924 * and font options.
13926 * See also clutter_actor_get_pango_context().
13928 * Return value: (transfer full): the newly created #PangoContext.
13929 * Use g_object_unref() on the returned value to deallocate its
13935 clutter_actor_create_pango_context (ClutterActor *self)
13937 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13939 return _clutter_context_create_pango_context ();
13943 * clutter_actor_create_pango_layout:
13944 * @self: a #ClutterActor
13945 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13947 * Creates a new #PangoLayout from the same #PangoContext used
13948 * by the #ClutterActor. The #PangoLayout is already configured
13949 * with the font map, resolution and font options, and the
13952 * If you want to keep around a #PangoLayout created by this
13953 * function you will have to connect to the #ClutterBackend::font-changed
13954 * and #ClutterBackend::resolution-changed signals, and call
13955 * pango_layout_context_changed() in response to them.
13957 * Return value: (transfer full): the newly created #PangoLayout.
13958 * Use g_object_unref() when done
13963 clutter_actor_create_pango_layout (ClutterActor *self,
13966 PangoContext *context;
13967 PangoLayout *layout;
13969 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13971 context = clutter_actor_get_pango_context (self);
13972 layout = pango_layout_new (context);
13975 pango_layout_set_text (layout, text, -1);
13980 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13981 * ClutterOffscreenEffect.
13984 _clutter_actor_set_opacity_override (ClutterActor *self,
13987 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13989 self->priv->opacity_override = opacity;
13993 _clutter_actor_get_opacity_override (ClutterActor *self)
13995 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13997 return self->priv->opacity_override;
14000 /* Allows you to disable applying the actors model view transform during
14001 * a paint. Used by ClutterClone. */
14003 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14006 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14008 self->priv->enable_model_view_transform = enable;
14012 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14015 ClutterActorPrivate *priv;
14017 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14021 priv->enable_paint_unmapped = enable;
14023 if (priv->enable_paint_unmapped)
14025 /* Make sure that the parents of the widget are realized first;
14026 * otherwise checks in clutter_actor_update_map_state() will
14029 clutter_actor_realize (self);
14031 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14035 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14040 clutter_anchor_coord_get_units (ClutterActor *self,
14041 const AnchorCoord *coord,
14046 if (coord->is_fractional)
14048 gfloat actor_width, actor_height;
14050 clutter_actor_get_size (self, &actor_width, &actor_height);
14053 *x = actor_width * coord->v.fraction.x;
14056 *y = actor_height * coord->v.fraction.y;
14064 *x = coord->v.units.x;
14067 *y = coord->v.units.y;
14070 *z = coord->v.units.z;
14075 clutter_anchor_coord_set_units (AnchorCoord *coord,
14080 coord->is_fractional = FALSE;
14081 coord->v.units.x = x;
14082 coord->v.units.y = y;
14083 coord->v.units.z = z;
14086 static ClutterGravity
14087 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14089 if (coord->is_fractional)
14091 if (coord->v.fraction.x == 0.0)
14093 if (coord->v.fraction.y == 0.0)
14094 return CLUTTER_GRAVITY_NORTH_WEST;
14095 else if (coord->v.fraction.y == 0.5)
14096 return CLUTTER_GRAVITY_WEST;
14097 else if (coord->v.fraction.y == 1.0)
14098 return CLUTTER_GRAVITY_SOUTH_WEST;
14100 return CLUTTER_GRAVITY_NONE;
14102 else if (coord->v.fraction.x == 0.5)
14104 if (coord->v.fraction.y == 0.0)
14105 return CLUTTER_GRAVITY_NORTH;
14106 else if (coord->v.fraction.y == 0.5)
14107 return CLUTTER_GRAVITY_CENTER;
14108 else if (coord->v.fraction.y == 1.0)
14109 return CLUTTER_GRAVITY_SOUTH;
14111 return CLUTTER_GRAVITY_NONE;
14113 else if (coord->v.fraction.x == 1.0)
14115 if (coord->v.fraction.y == 0.0)
14116 return CLUTTER_GRAVITY_NORTH_EAST;
14117 else if (coord->v.fraction.y == 0.5)
14118 return CLUTTER_GRAVITY_EAST;
14119 else if (coord->v.fraction.y == 1.0)
14120 return CLUTTER_GRAVITY_SOUTH_EAST;
14122 return CLUTTER_GRAVITY_NONE;
14125 return CLUTTER_GRAVITY_NONE;
14128 return CLUTTER_GRAVITY_NONE;
14132 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14133 ClutterGravity gravity)
14137 case CLUTTER_GRAVITY_NORTH:
14138 coord->v.fraction.x = 0.5;
14139 coord->v.fraction.y = 0.0;
14142 case CLUTTER_GRAVITY_NORTH_EAST:
14143 coord->v.fraction.x = 1.0;
14144 coord->v.fraction.y = 0.0;
14147 case CLUTTER_GRAVITY_EAST:
14148 coord->v.fraction.x = 1.0;
14149 coord->v.fraction.y = 0.5;
14152 case CLUTTER_GRAVITY_SOUTH_EAST:
14153 coord->v.fraction.x = 1.0;
14154 coord->v.fraction.y = 1.0;
14157 case CLUTTER_GRAVITY_SOUTH:
14158 coord->v.fraction.x = 0.5;
14159 coord->v.fraction.y = 1.0;
14162 case CLUTTER_GRAVITY_SOUTH_WEST:
14163 coord->v.fraction.x = 0.0;
14164 coord->v.fraction.y = 1.0;
14167 case CLUTTER_GRAVITY_WEST:
14168 coord->v.fraction.x = 0.0;
14169 coord->v.fraction.y = 0.5;
14172 case CLUTTER_GRAVITY_NORTH_WEST:
14173 coord->v.fraction.x = 0.0;
14174 coord->v.fraction.y = 0.0;
14177 case CLUTTER_GRAVITY_CENTER:
14178 coord->v.fraction.x = 0.5;
14179 coord->v.fraction.y = 0.5;
14183 coord->v.fraction.x = 0.0;
14184 coord->v.fraction.y = 0.0;
14188 coord->is_fractional = TRUE;
14192 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14194 if (coord->is_fractional)
14195 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14197 return (coord->v.units.x == 0.0
14198 && coord->v.units.y == 0.0
14199 && coord->v.units.z == 0.0);
14203 * clutter_actor_get_flags:
14204 * @self: a #ClutterActor
14206 * Retrieves the flags set on @self
14208 * Return value: a bitwise or of #ClutterActorFlags or 0
14213 clutter_actor_get_flags (ClutterActor *self)
14215 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14217 return self->flags;
14221 * clutter_actor_set_flags:
14222 * @self: a #ClutterActor
14223 * @flags: the flags to set
14225 * Sets @flags on @self
14227 * This function will emit notifications for the changed properties
14232 clutter_actor_set_flags (ClutterActor *self,
14233 ClutterActorFlags flags)
14235 ClutterActorFlags old_flags;
14237 gboolean was_reactive_set, reactive_set;
14238 gboolean was_realized_set, realized_set;
14239 gboolean was_mapped_set, mapped_set;
14240 gboolean was_visible_set, visible_set;
14242 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14244 if (self->flags == flags)
14247 obj = G_OBJECT (self);
14248 g_object_ref (obj);
14249 g_object_freeze_notify (obj);
14251 old_flags = self->flags;
14253 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14254 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14255 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14256 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14258 self->flags |= flags;
14260 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14261 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14262 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14263 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14265 if (reactive_set != was_reactive_set)
14266 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14268 if (realized_set != was_realized_set)
14269 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14271 if (mapped_set != was_mapped_set)
14272 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14274 if (visible_set != was_visible_set)
14275 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14277 g_object_thaw_notify (obj);
14278 g_object_unref (obj);
14282 * clutter_actor_unset_flags:
14283 * @self: a #ClutterActor
14284 * @flags: the flags to unset
14286 * Unsets @flags on @self
14288 * This function will emit notifications for the changed properties
14293 clutter_actor_unset_flags (ClutterActor *self,
14294 ClutterActorFlags flags)
14296 ClutterActorFlags old_flags;
14298 gboolean was_reactive_set, reactive_set;
14299 gboolean was_realized_set, realized_set;
14300 gboolean was_mapped_set, mapped_set;
14301 gboolean was_visible_set, visible_set;
14303 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14305 obj = G_OBJECT (self);
14306 g_object_freeze_notify (obj);
14308 old_flags = self->flags;
14310 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14311 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14312 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14313 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14315 self->flags &= ~flags;
14317 if (self->flags == old_flags)
14320 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14321 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14322 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14323 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14325 if (reactive_set != was_reactive_set)
14326 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14328 if (realized_set != was_realized_set)
14329 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14331 if (mapped_set != was_mapped_set)
14332 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14334 if (visible_set != was_visible_set)
14335 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14337 g_object_thaw_notify (obj);
14341 * clutter_actor_get_transformation_matrix:
14342 * @self: a #ClutterActor
14343 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14345 * Retrieves the transformations applied to @self relative to its
14351 clutter_actor_get_transformation_matrix (ClutterActor *self,
14352 CoglMatrix *matrix)
14354 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14356 cogl_matrix_init_identity (matrix);
14358 _clutter_actor_apply_modelview_transform (self, matrix);
14362 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14363 gboolean is_in_clone_paint)
14365 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14366 self->priv->in_clone_paint = is_in_clone_paint;
14370 * clutter_actor_is_in_clone_paint:
14371 * @self: a #ClutterActor
14373 * Checks whether @self is being currently painted by a #ClutterClone
14375 * This function is useful only inside the ::paint virtual function
14376 * implementations or within handlers for the #ClutterActor::paint
14379 * This function should not be used by applications
14381 * Return value: %TRUE if the #ClutterActor is currently being painted
14382 * by a #ClutterClone, and %FALSE otherwise
14387 clutter_actor_is_in_clone_paint (ClutterActor *self)
14389 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14391 return self->priv->in_clone_paint;
14395 set_direction_recursive (ClutterActor *actor,
14396 gpointer user_data)
14398 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14400 clutter_actor_set_text_direction (actor, text_dir);
14406 * clutter_actor_set_text_direction:
14407 * @self: a #ClutterActor
14408 * @text_dir: the text direction for @self
14410 * Sets the #ClutterTextDirection for an actor
14412 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14414 * If @self implements #ClutterContainer then this function will recurse
14415 * inside all the children of @self (including the internal ones).
14417 * Composite actors not implementing #ClutterContainer, or actors requiring
14418 * special handling when the text direction changes, should connect to
14419 * the #GObject::notify signal for the #ClutterActor:text-direction property
14424 clutter_actor_set_text_direction (ClutterActor *self,
14425 ClutterTextDirection text_dir)
14427 ClutterActorPrivate *priv;
14429 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14430 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14434 if (priv->text_direction != text_dir)
14436 priv->text_direction = text_dir;
14438 /* we need to emit the notify::text-direction first, so that
14439 * the sub-classes can catch that and do specific handling of
14440 * the text direction; see clutter_text_direction_changed_cb()
14441 * inside clutter-text.c
14443 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14445 _clutter_actor_foreach_child (self, set_direction_recursive,
14446 GINT_TO_POINTER (text_dir));
14448 clutter_actor_queue_relayout (self);
14453 _clutter_actor_set_has_pointer (ClutterActor *self,
14454 gboolean has_pointer)
14456 ClutterActorPrivate *priv = self->priv;
14458 if (priv->has_pointer != has_pointer)
14460 priv->has_pointer = has_pointer;
14462 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14467 * clutter_actor_get_text_direction:
14468 * @self: a #ClutterActor
14470 * Retrieves the value set using clutter_actor_set_text_direction()
14472 * If no text direction has been previously set, the default text
14473 * direction, as returned by clutter_get_default_text_direction(), will
14474 * be returned instead
14476 * Return value: the #ClutterTextDirection for the actor
14480 ClutterTextDirection
14481 clutter_actor_get_text_direction (ClutterActor *self)
14483 ClutterActorPrivate *priv;
14485 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14486 CLUTTER_TEXT_DIRECTION_LTR);
14490 /* if no direction has been set yet use the default */
14491 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14492 priv->text_direction = clutter_get_default_text_direction ();
14494 return priv->text_direction;
14498 * clutter_actor_push_internal:
14499 * @self: a #ClutterActor
14501 * Should be used by actors implementing the #ClutterContainer and with
14502 * internal children added through clutter_actor_set_parent(), for instance:
14506 * my_actor_init (MyActor *self)
14508 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14510 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14512 * /* calling clutter_actor_set_parent() now will result in
14513 * * the internal flag being set on a child of MyActor
14516 * /* internal child - a background texture */
14517 * self->priv->background_tex = clutter_texture_new ();
14518 * clutter_actor_set_parent (self->priv->background_tex,
14519 * CLUTTER_ACTOR (self));
14521 * /* internal child - a label */
14522 * self->priv->label = clutter_text_new ();
14523 * clutter_actor_set_parent (self->priv->label,
14524 * CLUTTER_ACTOR (self));
14526 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14528 * /* calling clutter_actor_set_parent() now will not result in
14529 * * the internal flag being set on a child of MyActor
14534 * This function will be used by Clutter to toggle an "internal child"
14535 * flag whenever clutter_actor_set_parent() is called; internal children
14536 * are handled differently by Clutter, specifically when destroying their
14539 * Call clutter_actor_pop_internal() when you finished adding internal
14542 * Nested calls to clutter_actor_push_internal() are allowed, but each
14543 * one must by followed by a clutter_actor_pop_internal() call.
14547 * Deprecated: 1.10: All children of an actor are accessible through
14548 * the #ClutterActor API, and #ClutterActor implements the
14549 * #ClutterContainer interface, so this function is only useful
14550 * for legacy containers overriding the default implementation.
14553 clutter_actor_push_internal (ClutterActor *self)
14555 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14557 self->priv->internal_child += 1;
14561 * clutter_actor_pop_internal:
14562 * @self: a #ClutterActor
14564 * Disables the effects of clutter_actor_push_internal().
14568 * Deprecated: 1.10: All children of an actor are accessible through
14569 * the #ClutterActor API. This function is only useful for legacy
14570 * containers overriding the default implementation of the
14571 * #ClutterContainer interface.
14574 clutter_actor_pop_internal (ClutterActor *self)
14576 ClutterActorPrivate *priv;
14578 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14582 if (priv->internal_child == 0)
14584 g_warning ("Mismatched %s: you need to call "
14585 "clutter_actor_push_composite() at least once before "
14586 "calling this function", G_STRFUNC);
14590 priv->internal_child -= 1;
14594 * clutter_actor_has_pointer:
14595 * @self: a #ClutterActor
14597 * Checks whether an actor contains the pointer of a
14598 * #ClutterInputDevice
14600 * Return value: %TRUE if the actor contains the pointer, and
14606 clutter_actor_has_pointer (ClutterActor *self)
14608 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14610 return self->priv->has_pointer;
14613 /* XXX: This is a workaround for not being able to break the ABI of
14614 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14615 * clutter_actor_queue_clipped_redraw() for details.
14617 ClutterPaintVolume *
14618 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14620 return g_object_get_data (G_OBJECT (self),
14621 "-clutter-actor-queue-redraw-clip");
14625 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14626 ClutterPaintVolume *clip)
14628 g_object_set_data (G_OBJECT (self),
14629 "-clutter-actor-queue-redraw-clip",
14634 * clutter_actor_has_allocation:
14635 * @self: a #ClutterActor
14637 * Checks if the actor has an up-to-date allocation assigned to
14638 * it. This means that the actor should have an allocation: it's
14639 * visible and has a parent. It also means that there is no
14640 * outstanding relayout request in progress for the actor or its
14641 * children (There might be other outstanding layout requests in
14642 * progress that will cause the actor to get a new allocation
14643 * when the stage is laid out, however).
14645 * If this function returns %FALSE, then the actor will normally
14646 * be allocated before it is next drawn on the screen.
14648 * Return value: %TRUE if the actor has an up-to-date allocation
14653 clutter_actor_has_allocation (ClutterActor *self)
14655 ClutterActorPrivate *priv;
14657 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14661 return priv->parent != NULL &&
14662 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14663 !priv->needs_allocation;
14667 * clutter_actor_add_action:
14668 * @self: a #ClutterActor
14669 * @action: a #ClutterAction
14671 * Adds @action to the list of actions applied to @self
14673 * A #ClutterAction can only belong to one actor at a time
14675 * The #ClutterActor will hold a reference on @action until either
14676 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14682 clutter_actor_add_action (ClutterActor *self,
14683 ClutterAction *action)
14685 ClutterActorPrivate *priv;
14687 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14688 g_return_if_fail (CLUTTER_IS_ACTION (action));
14692 if (priv->actions == NULL)
14694 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14695 priv->actions->actor = self;
14698 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14700 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14704 * clutter_actor_add_action_with_name:
14705 * @self: a #ClutterActor
14706 * @name: the name to set on the action
14707 * @action: a #ClutterAction
14709 * A convenience function for setting the name of a #ClutterAction
14710 * while adding it to the list of actions applied to @self
14712 * This function is the logical equivalent of:
14715 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14716 * clutter_actor_add_action (self, action);
14722 clutter_actor_add_action_with_name (ClutterActor *self,
14724 ClutterAction *action)
14726 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14727 g_return_if_fail (name != NULL);
14728 g_return_if_fail (CLUTTER_IS_ACTION (action));
14730 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14731 clutter_actor_add_action (self, action);
14735 * clutter_actor_remove_action:
14736 * @self: a #ClutterActor
14737 * @action: a #ClutterAction
14739 * Removes @action from the list of actions applied to @self
14741 * The reference held by @self on the #ClutterAction will be released
14746 clutter_actor_remove_action (ClutterActor *self,
14747 ClutterAction *action)
14749 ClutterActorPrivate *priv;
14751 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14752 g_return_if_fail (CLUTTER_IS_ACTION (action));
14756 if (priv->actions == NULL)
14759 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14761 if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14762 g_clear_object (&priv->actions);
14764 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14768 * clutter_actor_remove_action_by_name:
14769 * @self: a #ClutterActor
14770 * @name: the name of the action to remove
14772 * Removes the #ClutterAction with the given name from the list
14773 * of actions applied to @self
14778 clutter_actor_remove_action_by_name (ClutterActor *self,
14781 ClutterActorPrivate *priv;
14782 ClutterActorMeta *meta;
14784 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14785 g_return_if_fail (name != NULL);
14789 if (priv->actions == NULL)
14792 meta = _clutter_meta_group_get_meta (priv->actions, name);
14796 _clutter_meta_group_remove_meta (priv->actions, meta);
14798 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14802 * clutter_actor_get_actions:
14803 * @self: a #ClutterActor
14805 * Retrieves the list of actions applied to @self
14807 * Return value: (transfer container) (element-type Clutter.Action): a copy
14808 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14809 * owned by the #ClutterActor. Use g_list_free() to free the resources
14810 * allocated by the returned #GList
14815 clutter_actor_get_actions (ClutterActor *self)
14817 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14819 if (self->priv->actions == NULL)
14822 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14826 * clutter_actor_get_action:
14827 * @self: a #ClutterActor
14828 * @name: the name of the action to retrieve
14830 * Retrieves the #ClutterAction with the given name in the list
14831 * of actions applied to @self
14833 * Return value: (transfer none): a #ClutterAction for the given
14834 * name, or %NULL. The returned #ClutterAction is owned by the
14835 * actor and it should not be unreferenced directly
14840 clutter_actor_get_action (ClutterActor *self,
14843 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14844 g_return_val_if_fail (name != NULL, NULL);
14846 if (self->priv->actions == NULL)
14849 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14853 * clutter_actor_clear_actions:
14854 * @self: a #ClutterActor
14856 * Clears the list of actions applied to @self
14861 clutter_actor_clear_actions (ClutterActor *self)
14863 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14865 if (self->priv->actions == NULL)
14868 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14872 * clutter_actor_add_constraint:
14873 * @self: a #ClutterActor
14874 * @constraint: a #ClutterConstraint
14876 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14879 * The #ClutterActor will hold a reference on the @constraint until
14880 * either clutter_actor_remove_constraint() or
14881 * clutter_actor_clear_constraints() is called.
14886 clutter_actor_add_constraint (ClutterActor *self,
14887 ClutterConstraint *constraint)
14889 ClutterActorPrivate *priv;
14891 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14892 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14896 if (priv->constraints == NULL)
14898 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14899 priv->constraints->actor = self;
14902 _clutter_meta_group_add_meta (priv->constraints,
14903 CLUTTER_ACTOR_META (constraint));
14904 clutter_actor_queue_relayout (self);
14906 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14910 * clutter_actor_add_constraint_with_name:
14911 * @self: a #ClutterActor
14912 * @name: the name to set on the constraint
14913 * @constraint: a #ClutterConstraint
14915 * A convenience function for setting the name of a #ClutterConstraint
14916 * while adding it to the list of constraints applied to @self
14918 * This function is the logical equivalent of:
14921 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14922 * clutter_actor_add_constraint (self, constraint);
14928 clutter_actor_add_constraint_with_name (ClutterActor *self,
14930 ClutterConstraint *constraint)
14932 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14933 g_return_if_fail (name != NULL);
14934 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14936 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14937 clutter_actor_add_constraint (self, constraint);
14941 * clutter_actor_remove_constraint:
14942 * @self: a #ClutterActor
14943 * @constraint: a #ClutterConstraint
14945 * Removes @constraint from the list of constraints applied to @self
14947 * The reference held by @self on the #ClutterConstraint will be released
14952 clutter_actor_remove_constraint (ClutterActor *self,
14953 ClutterConstraint *constraint)
14955 ClutterActorPrivate *priv;
14957 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14958 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14962 if (priv->constraints == NULL)
14965 _clutter_meta_group_remove_meta (priv->constraints,
14966 CLUTTER_ACTOR_META (constraint));
14968 if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
14969 g_clear_object (&priv->constraints);
14971 clutter_actor_queue_relayout (self);
14973 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14977 * clutter_actor_remove_constraint_by_name:
14978 * @self: a #ClutterActor
14979 * @name: the name of the constraint to remove
14981 * Removes the #ClutterConstraint with the given name from the list
14982 * of constraints applied to @self
14987 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14990 ClutterActorPrivate *priv;
14991 ClutterActorMeta *meta;
14993 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14994 g_return_if_fail (name != NULL);
14998 if (priv->constraints == NULL)
15001 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15005 _clutter_meta_group_remove_meta (priv->constraints, meta);
15006 clutter_actor_queue_relayout (self);
15010 * clutter_actor_get_constraints:
15011 * @self: a #ClutterActor
15013 * Retrieves the list of constraints applied to @self
15015 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15016 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15017 * owned by the #ClutterActor. Use g_list_free() to free the resources
15018 * allocated by the returned #GList
15023 clutter_actor_get_constraints (ClutterActor *self)
15025 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15027 if (self->priv->constraints == NULL)
15030 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15034 * clutter_actor_get_constraint:
15035 * @self: a #ClutterActor
15036 * @name: the name of the constraint to retrieve
15038 * Retrieves the #ClutterConstraint with the given name in the list
15039 * of constraints applied to @self
15041 * Return value: (transfer none): a #ClutterConstraint for the given
15042 * name, or %NULL. The returned #ClutterConstraint is owned by the
15043 * actor and it should not be unreferenced directly
15047 ClutterConstraint *
15048 clutter_actor_get_constraint (ClutterActor *self,
15051 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15052 g_return_val_if_fail (name != NULL, NULL);
15054 if (self->priv->constraints == NULL)
15057 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15061 * clutter_actor_clear_constraints:
15062 * @self: a #ClutterActor
15064 * Clears the list of constraints applied to @self
15069 clutter_actor_clear_constraints (ClutterActor *self)
15071 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15073 if (self->priv->constraints == NULL)
15076 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15078 clutter_actor_queue_relayout (self);
15082 * clutter_actor_set_clip_to_allocation:
15083 * @self: a #ClutterActor
15084 * @clip_set: %TRUE to apply a clip tracking the allocation
15086 * Sets whether @self should be clipped to the same size as its
15092 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15095 ClutterActorPrivate *priv;
15097 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15099 clip_set = !!clip_set;
15103 if (priv->clip_to_allocation != clip_set)
15105 priv->clip_to_allocation = clip_set;
15107 clutter_actor_queue_redraw (self);
15109 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15114 * clutter_actor_get_clip_to_allocation:
15115 * @self: a #ClutterActor
15117 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15119 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15124 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15126 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15128 return self->priv->clip_to_allocation;
15132 * clutter_actor_add_effect:
15133 * @self: a #ClutterActor
15134 * @effect: a #ClutterEffect
15136 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15138 * The #ClutterActor will hold a reference on the @effect until either
15139 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15145 clutter_actor_add_effect (ClutterActor *self,
15146 ClutterEffect *effect)
15148 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15149 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15151 _clutter_actor_add_effect_internal (self, effect);
15153 clutter_actor_queue_redraw (self);
15155 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15159 * clutter_actor_add_effect_with_name:
15160 * @self: a #ClutterActor
15161 * @name: the name to set on the effect
15162 * @effect: a #ClutterEffect
15164 * A convenience function for setting the name of a #ClutterEffect
15165 * while adding it to the list of effectss applied to @self
15167 * This function is the logical equivalent of:
15170 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15171 * clutter_actor_add_effect (self, effect);
15177 clutter_actor_add_effect_with_name (ClutterActor *self,
15179 ClutterEffect *effect)
15181 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15182 g_return_if_fail (name != NULL);
15183 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15185 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15186 clutter_actor_add_effect (self, effect);
15190 * clutter_actor_remove_effect:
15191 * @self: a #ClutterActor
15192 * @effect: a #ClutterEffect
15194 * Removes @effect from the list of effects applied to @self
15196 * The reference held by @self on the #ClutterEffect will be released
15201 clutter_actor_remove_effect (ClutterActor *self,
15202 ClutterEffect *effect)
15204 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15205 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15207 _clutter_actor_remove_effect_internal (self, effect);
15209 clutter_actor_queue_redraw (self);
15211 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15215 * clutter_actor_remove_effect_by_name:
15216 * @self: a #ClutterActor
15217 * @name: the name of the effect to remove
15219 * Removes the #ClutterEffect with the given name from the list
15220 * of effects applied to @self
15225 clutter_actor_remove_effect_by_name (ClutterActor *self,
15228 ClutterActorPrivate *priv;
15229 ClutterActorMeta *meta;
15231 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15232 g_return_if_fail (name != NULL);
15236 if (priv->effects == NULL)
15239 meta = _clutter_meta_group_get_meta (priv->effects, name);
15243 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15247 * clutter_actor_get_effects:
15248 * @self: a #ClutterActor
15250 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15252 * Return value: (transfer container) (element-type Clutter.Effect): a list
15253 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15254 * list are owned by Clutter and they should not be freed. You should
15255 * free the returned list using g_list_free() when done
15260 clutter_actor_get_effects (ClutterActor *self)
15262 ClutterActorPrivate *priv;
15264 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15268 if (priv->effects == NULL)
15271 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15275 * clutter_actor_get_effect:
15276 * @self: a #ClutterActor
15277 * @name: the name of the effect to retrieve
15279 * Retrieves the #ClutterEffect with the given name in the list
15280 * of effects applied to @self
15282 * Return value: (transfer none): a #ClutterEffect for the given
15283 * name, or %NULL. The returned #ClutterEffect is owned by the
15284 * actor and it should not be unreferenced directly
15289 clutter_actor_get_effect (ClutterActor *self,
15292 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15293 g_return_val_if_fail (name != NULL, NULL);
15295 if (self->priv->effects == NULL)
15298 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15302 * clutter_actor_clear_effects:
15303 * @self: a #ClutterActor
15305 * Clears the list of effects applied to @self
15310 clutter_actor_clear_effects (ClutterActor *self)
15312 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15314 if (self->priv->effects == NULL)
15317 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15319 clutter_actor_queue_redraw (self);
15323 * clutter_actor_has_key_focus:
15324 * @self: a #ClutterActor
15326 * Checks whether @self is the #ClutterActor that has key focus
15328 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15333 clutter_actor_has_key_focus (ClutterActor *self)
15335 ClutterActor *stage;
15337 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15339 stage = _clutter_actor_get_stage_internal (self);
15343 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15347 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15348 ClutterPaintVolume *pv)
15350 ClutterActorPrivate *priv = self->priv;
15352 /* Actors are only expected to report a valid paint volume
15353 * while they have a valid allocation. */
15354 if (G_UNLIKELY (priv->needs_allocation))
15356 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15357 "Actor needs allocation",
15358 _clutter_actor_get_debug_name (self));
15362 /* Check if there are any handlers connected to the paint
15363 * signal. If there are then all bets are off for what the paint
15364 * volume for this actor might possibly be!
15366 * XXX: It's expected that this is going to end up being quite a
15367 * costly check to have to do here, but we haven't come up with
15368 * another solution that can reliably catch paint signal handlers at
15369 * the right time to either avoid artefacts due to invalid stage
15370 * clipping or due to incorrect culling.
15372 * Previously we checked in clutter_actor_paint(), but at that time
15373 * we may already be using a stage clip that could be derived from
15374 * an invalid paint-volume. We used to try and handle that by
15375 * queuing a follow up, unclipped, redraw but still the previous
15376 * checking wasn't enough to catch invalid volumes involved in
15377 * culling (considering that containers may derive their volume from
15378 * children that haven't yet been painted)
15380 * Longer term, improved solutions could be:
15381 * - Disallow painting in the paint signal, only allow using it
15382 * for tracking when paints happen. We can add another API that
15383 * allows monkey patching the paint of arbitrary actors but in a
15384 * more controlled way and that also supports modifying the
15386 * - If we could be notified somehow when signal handlers are
15387 * connected we wouldn't have to poll for handlers like this.
15389 if (g_signal_has_handler_pending (self,
15390 actor_signals[PAINT],
15394 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15395 "Actor has \"paint\" signal handlers",
15396 _clutter_actor_get_debug_name (self));
15400 _clutter_paint_volume_init_static (pv, self);
15402 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15404 clutter_paint_volume_free (pv);
15405 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15406 "Actor failed to report a volume",
15407 _clutter_actor_get_debug_name (self));
15411 /* since effects can modify the paint volume, we allow them to actually
15412 * do this by making get_paint_volume() "context sensitive"
15414 if (priv->effects != NULL)
15416 if (priv->current_effect != NULL)
15418 const GList *effects, *l;
15420 /* if we are being called from within the paint sequence of
15421 * an actor, get the paint volume up to the current effect
15423 effects = _clutter_meta_group_peek_metas (priv->effects);
15425 l != NULL || (l != NULL && l->data != priv->current_effect);
15428 if (!_clutter_effect_get_paint_volume (l->data, pv))
15430 clutter_paint_volume_free (pv);
15431 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15432 "Effect (%s) failed to report a volume",
15433 _clutter_actor_get_debug_name (self),
15434 _clutter_actor_meta_get_debug_name (l->data));
15441 const GList *effects, *l;
15443 /* otherwise, get the cumulative volume */
15444 effects = _clutter_meta_group_peek_metas (priv->effects);
15445 for (l = effects; l != NULL; l = l->next)
15446 if (!_clutter_effect_get_paint_volume (l->data, pv))
15448 clutter_paint_volume_free (pv);
15449 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15450 "Effect (%s) failed to report a volume",
15451 _clutter_actor_get_debug_name (self),
15452 _clutter_actor_meta_get_debug_name (l->data));
15461 /* The public clutter_actor_get_paint_volume API returns a const
15462 * pointer since we return a pointer directly to the cached
15463 * PaintVolume associated with the actor and don't want the user to
15464 * inadvertently modify it, but for internal uses we sometimes need
15465 * access to the same PaintVolume but need to apply some book-keeping
15466 * modifications to it so we don't want a const pointer.
15468 static ClutterPaintVolume *
15469 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15471 ClutterActorPrivate *priv;
15475 if (priv->paint_volume_valid)
15476 clutter_paint_volume_free (&priv->paint_volume);
15478 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15480 priv->paint_volume_valid = TRUE;
15481 return &priv->paint_volume;
15485 priv->paint_volume_valid = FALSE;
15491 * clutter_actor_get_paint_volume:
15492 * @self: a #ClutterActor
15494 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15495 * when a paint volume can't be determined.
15497 * The paint volume is defined as the 3D space occupied by an actor
15498 * when being painted.
15500 * This function will call the <function>get_paint_volume()</function>
15501 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15502 * should not usually care about overriding the default implementation,
15503 * unless they are, for instance: painting outside their allocation, or
15504 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15507 * <note>2D actors overriding <function>get_paint_volume()</function>
15508 * ensure their volume has a depth of 0. (This will be true so long as
15509 * you don't call clutter_paint_volume_set_depth().)</note>
15511 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15512 * or %NULL if no volume could be determined. The returned pointer
15513 * is not guaranteed to be valid across multiple frames; if you want
15514 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15518 const ClutterPaintVolume *
15519 clutter_actor_get_paint_volume (ClutterActor *self)
15521 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15523 return _clutter_actor_get_paint_volume_mutable (self);
15527 * clutter_actor_get_transformed_paint_volume:
15528 * @self: a #ClutterActor
15529 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15530 * (or %NULL for the stage)
15532 * Retrieves the 3D paint volume of an actor like
15533 * clutter_actor_get_paint_volume() does (Please refer to the
15534 * documentation of clutter_actor_get_paint_volume() for more
15535 * details.) and it additionally transforms the paint volume into the
15536 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15537 * is passed for @relative_to_ancestor)
15539 * This can be used by containers that base their paint volume on
15540 * the volume of their children. Such containers can query the
15541 * transformed paint volume of all of its children and union them
15542 * together using clutter_paint_volume_union().
15544 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15545 * or %NULL if no volume could be determined. The returned pointer is
15546 * not guaranteed to be valid across multiple frames; if you wish to
15547 * keep it, you will have to copy it using clutter_paint_volume_copy().
15551 const ClutterPaintVolume *
15552 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15553 ClutterActor *relative_to_ancestor)
15555 const ClutterPaintVolume *volume;
15556 ClutterActor *stage;
15557 ClutterPaintVolume *transformed_volume;
15559 stage = _clutter_actor_get_stage_internal (self);
15560 if (G_UNLIKELY (stage == NULL))
15563 if (relative_to_ancestor == NULL)
15564 relative_to_ancestor = stage;
15566 volume = clutter_actor_get_paint_volume (self);
15567 if (volume == NULL)
15570 transformed_volume =
15571 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15573 _clutter_paint_volume_copy_static (volume, transformed_volume);
15575 _clutter_paint_volume_transform_relative (transformed_volume,
15576 relative_to_ancestor);
15578 return transformed_volume;
15582 * clutter_actor_get_paint_box:
15583 * @self: a #ClutterActor
15584 * @box: (out): return location for a #ClutterActorBox
15586 * Retrieves the paint volume of the passed #ClutterActor, and
15587 * transforms it into a 2D bounding box in stage coordinates.
15589 * This function is useful to determine the on screen area occupied by
15590 * the actor. The box is only an approximation and may often be
15591 * considerably larger due to the optimizations used to calculate the
15592 * box. The box is never smaller though, so it can reliably be used
15595 * There are times when a 2D paint box can't be determined, e.g.
15596 * because the actor isn't yet parented under a stage or because
15597 * the actor is unable to determine a paint volume.
15599 * Return value: %TRUE if a 2D paint box could be determined, else
15605 clutter_actor_get_paint_box (ClutterActor *self,
15606 ClutterActorBox *box)
15608 ClutterActor *stage;
15609 ClutterPaintVolume *pv;
15611 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15612 g_return_val_if_fail (box != NULL, FALSE);
15614 stage = _clutter_actor_get_stage_internal (self);
15615 if (G_UNLIKELY (!stage))
15618 pv = _clutter_actor_get_paint_volume_mutable (self);
15619 if (G_UNLIKELY (!pv))
15622 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15628 * clutter_actor_has_overlaps:
15629 * @self: A #ClutterActor
15631 * Asks the actor's implementation whether it may contain overlapping
15634 * For example; Clutter may use this to determine whether the painting
15635 * should be redirected to an offscreen buffer to correctly implement
15636 * the opacity property.
15638 * Custom actors can override the default response by implementing the
15639 * #ClutterActor <function>has_overlaps</function> virtual function. See
15640 * clutter_actor_set_offscreen_redirect() for more information.
15642 * Return value: %TRUE if the actor may have overlapping primitives, and
15648 clutter_actor_has_overlaps (ClutterActor *self)
15650 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15652 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15656 * clutter_actor_has_effects:
15657 * @self: A #ClutterActor
15659 * Returns whether the actor has any effects applied.
15661 * Return value: %TRUE if the actor has any effects,
15667 clutter_actor_has_effects (ClutterActor *self)
15669 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15671 if (self->priv->effects == NULL)
15674 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15678 * clutter_actor_has_constraints:
15679 * @self: A #ClutterActor
15681 * Returns whether the actor has any constraints applied.
15683 * Return value: %TRUE if the actor has any constraints,
15689 clutter_actor_has_constraints (ClutterActor *self)
15691 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15693 return self->priv->constraints != NULL;
15697 * clutter_actor_has_actions:
15698 * @self: A #ClutterActor
15700 * Returns whether the actor has any actions applied.
15702 * Return value: %TRUE if the actor has any actions,
15708 clutter_actor_has_actions (ClutterActor *self)
15710 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15712 return self->priv->actions != NULL;
15716 * clutter_actor_get_n_children:
15717 * @self: a #ClutterActor
15719 * Retrieves the number of children of @self.
15721 * Return value: the number of children of an actor
15726 clutter_actor_get_n_children (ClutterActor *self)
15728 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15730 return self->priv->n_children;
15734 * clutter_actor_get_child_at_index:
15735 * @self: a #ClutterActor
15736 * @index_: the position in the list of children
15738 * Retrieves the actor at the given @index_ inside the list of
15739 * children of @self.
15741 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15746 clutter_actor_get_child_at_index (ClutterActor *self,
15749 ClutterActor *iter;
15752 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15753 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15755 for (iter = self->priv->first_child, i = 0;
15756 iter != NULL && i < index_;
15757 iter = iter->priv->next_sibling, i += 1)
15764 * _clutter_actor_foreach_child:
15765 * @actor: The actor whos children you want to iterate
15766 * @callback: The function to call for each child
15767 * @user_data: Private data to pass to @callback
15769 * Calls a given @callback once for each child of the specified @actor and
15770 * passing the @user_data pointer each time.
15772 * Return value: returns %TRUE if all children were iterated, else
15773 * %FALSE if a callback broke out of iteration early.
15776 _clutter_actor_foreach_child (ClutterActor *self,
15777 ClutterForeachCallback callback,
15778 gpointer user_data)
15780 ClutterActor *iter;
15783 if (self->priv->first_child == NULL)
15787 iter = self->priv->first_child;
15789 /* we use this form so that it's safe to change the children
15790 * list while iterating it
15792 while (cont && iter != NULL)
15794 ClutterActor *next = iter->priv->next_sibling;
15796 cont = callback (iter, user_data);
15805 /* For debugging purposes this gives us a simple way to print out
15806 * the scenegraph e.g in gdb using:
15808 * _clutter_actor_traverse (stage,
15810 * clutter_debug_print_actor_cb,
15815 static ClutterActorTraverseVisitFlags
15816 clutter_debug_print_actor_cb (ClutterActor *actor,
15820 g_print ("%*s%s:%p\n",
15822 _clutter_actor_get_debug_name (actor),
15825 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15830 _clutter_actor_traverse_breadth (ClutterActor *actor,
15831 ClutterTraverseCallback callback,
15832 gpointer user_data)
15834 GQueue *queue = g_queue_new ();
15835 ClutterActor dummy;
15836 int current_depth = 0;
15838 g_queue_push_tail (queue, actor);
15839 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15841 while ((actor = g_queue_pop_head (queue)))
15843 ClutterActorTraverseVisitFlags flags;
15845 if (actor == &dummy)
15848 g_queue_push_tail (queue, &dummy);
15852 flags = callback (actor, current_depth, user_data);
15853 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15855 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15857 ClutterActor *iter;
15859 for (iter = actor->priv->first_child;
15861 iter = iter->priv->next_sibling)
15863 g_queue_push_tail (queue, iter);
15868 g_queue_free (queue);
15871 static ClutterActorTraverseVisitFlags
15872 _clutter_actor_traverse_depth (ClutterActor *actor,
15873 ClutterTraverseCallback before_children_callback,
15874 ClutterTraverseCallback after_children_callback,
15876 gpointer user_data)
15878 ClutterActorTraverseVisitFlags flags;
15880 flags = before_children_callback (actor, current_depth, user_data);
15881 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15882 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15884 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15886 ClutterActor *iter;
15888 for (iter = actor->priv->first_child;
15890 iter = iter->priv->next_sibling)
15892 flags = _clutter_actor_traverse_depth (iter,
15893 before_children_callback,
15894 after_children_callback,
15898 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15899 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15903 if (after_children_callback)
15904 return after_children_callback (actor, current_depth, user_data);
15906 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15909 /* _clutter_actor_traverse:
15910 * @actor: The actor to start traversing the graph from
15911 * @flags: These flags may affect how the traversal is done
15912 * @before_children_callback: A function to call before visiting the
15913 * children of the current actor.
15914 * @after_children_callback: A function to call after visiting the
15915 * children of the current actor. (Ignored if
15916 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15917 * @user_data: The private data to pass to the callbacks
15919 * Traverses the scenegraph starting at the specified @actor and
15920 * descending through all its children and its children's children.
15921 * For each actor traversed @before_children_callback and
15922 * @after_children_callback are called with the specified
15923 * @user_data, before and after visiting that actor's children.
15925 * The callbacks can return flags that affect the ongoing traversal
15926 * such as by skipping over an actors children or bailing out of
15927 * any further traversing.
15930 _clutter_actor_traverse (ClutterActor *actor,
15931 ClutterActorTraverseFlags flags,
15932 ClutterTraverseCallback before_children_callback,
15933 ClutterTraverseCallback after_children_callback,
15934 gpointer user_data)
15936 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15937 _clutter_actor_traverse_breadth (actor,
15938 before_children_callback,
15940 else /* DEPTH_FIRST */
15941 _clutter_actor_traverse_depth (actor,
15942 before_children_callback,
15943 after_children_callback,
15944 0, /* start depth */
15949 on_layout_manager_changed (ClutterLayoutManager *manager,
15950 ClutterActor *self)
15952 clutter_actor_queue_relayout (self);
15956 * clutter_actor_set_layout_manager:
15957 * @self: a #ClutterActor
15958 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15960 * Sets the #ClutterLayoutManager delegate object that will be used to
15961 * lay out the children of @self.
15963 * The #ClutterActor will take a reference on the passed @manager which
15964 * will be released either when the layout manager is removed, or when
15965 * the actor is destroyed.
15970 clutter_actor_set_layout_manager (ClutterActor *self,
15971 ClutterLayoutManager *manager)
15973 ClutterActorPrivate *priv;
15975 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15976 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15980 if (priv->layout_manager != NULL)
15982 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15983 G_CALLBACK (on_layout_manager_changed),
15985 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15986 g_clear_object (&priv->layout_manager);
15989 priv->layout_manager = manager;
15991 if (priv->layout_manager != NULL)
15993 g_object_ref_sink (priv->layout_manager);
15994 clutter_layout_manager_set_container (priv->layout_manager,
15995 CLUTTER_CONTAINER (self));
15996 g_signal_connect (priv->layout_manager, "layout-changed",
15997 G_CALLBACK (on_layout_manager_changed),
16001 clutter_actor_queue_relayout (self);
16003 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16007 * clutter_actor_get_layout_manager:
16008 * @self: a #ClutterActor
16010 * Retrieves the #ClutterLayoutManager used by @self.
16012 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16017 ClutterLayoutManager *
16018 clutter_actor_get_layout_manager (ClutterActor *self)
16020 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16022 return self->priv->layout_manager;
16025 static const ClutterLayoutInfo default_layout_info = {
16026 CLUTTER_POINT_INIT_ZERO, /* fixed-pos */
16027 { 0, 0, 0, 0 }, /* margin */
16028 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16029 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16030 CLUTTER_SIZE_INIT_ZERO, /* minimum */
16031 CLUTTER_SIZE_INIT_ZERO, /* natural */
16035 layout_info_free (gpointer data)
16037 if (G_LIKELY (data != NULL))
16038 g_slice_free (ClutterLayoutInfo, data);
16042 * _clutter_actor_get_layout_info:
16043 * @self: a #ClutterActor
16045 * Retrieves a pointer to the ClutterLayoutInfo structure.
16047 * If the actor does not have a ClutterLayoutInfo associated to it, one
16048 * will be created and initialized to the default values.
16050 * This function should be used for setters.
16052 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16055 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16057 ClutterLayoutInfo *
16058 _clutter_actor_get_layout_info (ClutterActor *self)
16060 ClutterLayoutInfo *retval;
16062 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16063 if (retval == NULL)
16065 retval = g_slice_new (ClutterLayoutInfo);
16067 *retval = default_layout_info;
16069 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16078 * _clutter_actor_get_layout_info_or_defaults:
16079 * @self: a #ClutterActor
16081 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16083 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16084 * then the default structure will be returned.
16086 * This function should only be used for getters.
16088 * Return value: a const pointer to the ClutterLayoutInfo structure
16090 const ClutterLayoutInfo *
16091 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16093 const ClutterLayoutInfo *info;
16095 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16097 return &default_layout_info;
16103 * clutter_actor_set_x_align:
16104 * @self: a #ClutterActor
16105 * @x_align: the horizontal alignment policy
16107 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16108 * actor received extra horizontal space.
16110 * See also the #ClutterActor:x-align property.
16115 clutter_actor_set_x_align (ClutterActor *self,
16116 ClutterActorAlign x_align)
16118 ClutterLayoutInfo *info;
16120 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16122 info = _clutter_actor_get_layout_info (self);
16124 if (info->x_align != x_align)
16126 info->x_align = x_align;
16128 clutter_actor_queue_relayout (self);
16130 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16135 * clutter_actor_get_x_align:
16136 * @self: a #ClutterActor
16138 * Retrieves the horizontal alignment policy set using
16139 * clutter_actor_set_x_align().
16141 * Return value: the horizontal alignment policy.
16146 clutter_actor_get_x_align (ClutterActor *self)
16148 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16150 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16154 * clutter_actor_set_y_align:
16155 * @self: a #ClutterActor
16156 * @y_align: the vertical alignment policy
16158 * Sets the vertical alignment policy of a #ClutterActor, in case the
16159 * actor received extra vertical space.
16161 * See also the #ClutterActor:y-align property.
16166 clutter_actor_set_y_align (ClutterActor *self,
16167 ClutterActorAlign y_align)
16169 ClutterLayoutInfo *info;
16171 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16173 info = _clutter_actor_get_layout_info (self);
16175 if (info->y_align != y_align)
16177 info->y_align = y_align;
16179 clutter_actor_queue_relayout (self);
16181 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16186 * clutter_actor_get_y_align:
16187 * @self: a #ClutterActor
16189 * Retrieves the vertical alignment policy set using
16190 * clutter_actor_set_y_align().
16192 * Return value: the vertical alignment policy.
16197 clutter_actor_get_y_align (ClutterActor *self)
16199 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16201 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16205 * clutter_actor_set_margin:
16206 * @self: a #ClutterActor
16207 * @margin: a #ClutterMargin
16209 * Sets all the components of the margin of a #ClutterActor.
16214 clutter_actor_set_margin (ClutterActor *self,
16215 const ClutterMargin *margin)
16217 ClutterLayoutInfo *info;
16221 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16222 g_return_if_fail (margin != NULL);
16224 obj = G_OBJECT (self);
16227 g_object_freeze_notify (obj);
16229 info = _clutter_actor_get_layout_info (self);
16231 if (info->margin.top != margin->top)
16233 info->margin.top = margin->top;
16234 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16238 if (info->margin.right != margin->right)
16240 info->margin.right = margin->right;
16241 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16245 if (info->margin.bottom != margin->bottom)
16247 info->margin.bottom = margin->bottom;
16248 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16252 if (info->margin.left != margin->left)
16254 info->margin.left = margin->left;
16255 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16260 clutter_actor_queue_relayout (self);
16262 g_object_thaw_notify (obj);
16266 * clutter_actor_get_margin:
16267 * @self: a #ClutterActor
16268 * @margin: (out caller-allocates): return location for a #ClutterMargin
16270 * Retrieves all the components of the margin of a #ClutterActor.
16275 clutter_actor_get_margin (ClutterActor *self,
16276 ClutterMargin *margin)
16278 const ClutterLayoutInfo *info;
16280 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16281 g_return_if_fail (margin != NULL);
16283 info = _clutter_actor_get_layout_info_or_defaults (self);
16285 *margin = info->margin;
16289 * clutter_actor_set_margin_top:
16290 * @self: a #ClutterActor
16291 * @margin: the top margin
16293 * Sets the margin from the top of a #ClutterActor.
16298 clutter_actor_set_margin_top (ClutterActor *self,
16301 ClutterLayoutInfo *info;
16303 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16304 g_return_if_fail (margin >= 0.f);
16306 info = _clutter_actor_get_layout_info (self);
16308 if (info->margin.top == margin)
16311 info->margin.top = margin;
16313 clutter_actor_queue_relayout (self);
16315 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16319 * clutter_actor_get_margin_top:
16320 * @self: a #ClutterActor
16322 * Retrieves the top margin of a #ClutterActor.
16324 * Return value: the top margin
16329 clutter_actor_get_margin_top (ClutterActor *self)
16331 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16333 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16337 * clutter_actor_set_margin_bottom:
16338 * @self: a #ClutterActor
16339 * @margin: the bottom margin
16341 * Sets the margin from the bottom of a #ClutterActor.
16346 clutter_actor_set_margin_bottom (ClutterActor *self,
16349 ClutterLayoutInfo *info;
16351 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16352 g_return_if_fail (margin >= 0.f);
16354 info = _clutter_actor_get_layout_info (self);
16356 if (info->margin.bottom == margin)
16359 info->margin.bottom = margin;
16361 clutter_actor_queue_relayout (self);
16363 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16367 * clutter_actor_get_margin_bottom:
16368 * @self: a #ClutterActor
16370 * Retrieves the bottom margin of a #ClutterActor.
16372 * Return value: the bottom margin
16377 clutter_actor_get_margin_bottom (ClutterActor *self)
16379 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16381 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16385 * clutter_actor_set_margin_left:
16386 * @self: a #ClutterActor
16387 * @margin: the left margin
16389 * Sets the margin from the left of a #ClutterActor.
16394 clutter_actor_set_margin_left (ClutterActor *self,
16397 ClutterLayoutInfo *info;
16399 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16400 g_return_if_fail (margin >= 0.f);
16402 info = _clutter_actor_get_layout_info (self);
16404 if (info->margin.left == margin)
16407 info->margin.left = margin;
16409 clutter_actor_queue_relayout (self);
16411 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16415 * clutter_actor_get_margin_left:
16416 * @self: a #ClutterActor
16418 * Retrieves the left margin of a #ClutterActor.
16420 * Return value: the left margin
16425 clutter_actor_get_margin_left (ClutterActor *self)
16427 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16429 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16433 * clutter_actor_set_margin_right:
16434 * @self: a #ClutterActor
16435 * @margin: the right margin
16437 * Sets the margin from the right of a #ClutterActor.
16442 clutter_actor_set_margin_right (ClutterActor *self,
16445 ClutterLayoutInfo *info;
16447 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16448 g_return_if_fail (margin >= 0.f);
16450 info = _clutter_actor_get_layout_info (self);
16452 if (info->margin.right == margin)
16455 info->margin.right = margin;
16457 clutter_actor_queue_relayout (self);
16459 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16463 * clutter_actor_get_margin_right:
16464 * @self: a #ClutterActor
16466 * Retrieves the right margin of a #ClutterActor.
16468 * Return value: the right margin
16473 clutter_actor_get_margin_right (ClutterActor *self)
16475 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16477 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16481 clutter_actor_set_background_color_internal (ClutterActor *self,
16482 const ClutterColor *color)
16484 ClutterActorPrivate *priv = self->priv;
16487 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16490 obj = G_OBJECT (self);
16492 priv->bg_color = *color;
16493 priv->bg_color_set = TRUE;
16495 clutter_actor_queue_redraw (self);
16497 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16498 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16502 * clutter_actor_set_background_color:
16503 * @self: a #ClutterActor
16504 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16507 * Sets the background color of a #ClutterActor.
16509 * The background color will be used to cover the whole allocation of the
16510 * actor. The default background color of an actor is transparent.
16512 * To check whether an actor has a background color, you can use the
16513 * #ClutterActor:background-color-set actor property.
16515 * The #ClutterActor:background-color property is animatable.
16520 clutter_actor_set_background_color (ClutterActor *self,
16521 const ClutterColor *color)
16523 ClutterActorPrivate *priv;
16525 GParamSpec *bg_color_pspec;
16527 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16529 obj = G_OBJECT (self);
16535 priv->bg_color_set = FALSE;
16536 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16537 clutter_actor_queue_redraw (self);
16541 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16542 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16544 _clutter_actor_create_transition (self, bg_color_pspec,
16549 _clutter_actor_update_transition (self, bg_color_pspec, color);
16551 clutter_actor_queue_redraw (self);
16555 * clutter_actor_get_background_color:
16556 * @self: a #ClutterActor
16557 * @color: (out caller-allocates): return location for a #ClutterColor
16559 * Retrieves the color set using clutter_actor_set_background_color().
16564 clutter_actor_get_background_color (ClutterActor *self,
16565 ClutterColor *color)
16567 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16568 g_return_if_fail (color != NULL);
16570 *color = self->priv->bg_color;
16574 * clutter_actor_get_previous_sibling:
16575 * @self: a #ClutterActor
16577 * Retrieves the sibling of @self that comes before it in the list
16578 * of children of @self's parent.
16580 * The returned pointer is only valid until the scene graph changes; it
16581 * is not safe to modify the list of children of @self while iterating
16584 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16589 clutter_actor_get_previous_sibling (ClutterActor *self)
16591 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16593 return self->priv->prev_sibling;
16597 * clutter_actor_get_next_sibling:
16598 * @self: a #ClutterActor
16600 * Retrieves the sibling of @self that comes after it in the list
16601 * of children of @self's parent.
16603 * The returned pointer is only valid until the scene graph changes; it
16604 * is not safe to modify the list of children of @self while iterating
16607 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16612 clutter_actor_get_next_sibling (ClutterActor *self)
16614 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16616 return self->priv->next_sibling;
16620 * clutter_actor_get_first_child:
16621 * @self: a #ClutterActor
16623 * Retrieves the first child of @self.
16625 * The returned pointer is only valid until the scene graph changes; it
16626 * is not safe to modify the list of children of @self while iterating
16629 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16634 clutter_actor_get_first_child (ClutterActor *self)
16636 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16638 return self->priv->first_child;
16642 * clutter_actor_get_last_child:
16643 * @self: a #ClutterActor
16645 * Retrieves the last child of @self.
16647 * The returned pointer is only valid until the scene graph changes; it
16648 * is not safe to modify the list of children of @self while iterating
16651 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16656 clutter_actor_get_last_child (ClutterActor *self)
16658 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16660 return self->priv->last_child;
16663 /* easy way to have properly named fields instead of the dummy ones
16664 * we use in the public structure
16666 typedef struct _RealActorIter
16668 ClutterActor *root; /* dummy1 */
16669 ClutterActor *current; /* dummy2 */
16670 gpointer padding_1; /* dummy3 */
16671 gint age; /* dummy4 */
16672 gpointer padding_2; /* dummy5 */
16676 * clutter_actor_iter_init:
16677 * @iter: a #ClutterActorIter
16678 * @root: a #ClutterActor
16680 * Initializes a #ClutterActorIter, which can then be used to iterate
16681 * efficiently over a section of the scene graph, and associates it
16684 * Modifying the scene graph section that contains @root will invalidate
16688 * ClutterActorIter iter;
16689 * ClutterActor *child;
16691 * clutter_actor_iter_init (&iter, container);
16692 * while (clutter_actor_iter_next (&iter, &child))
16694 * /* do something with child */
16701 clutter_actor_iter_init (ClutterActorIter *iter,
16702 ClutterActor *root)
16704 RealActorIter *ri = (RealActorIter *) iter;
16706 g_return_if_fail (iter != NULL);
16707 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16710 ri->current = NULL;
16711 ri->age = root->priv->age;
16715 * clutter_actor_iter_next:
16716 * @iter: a #ClutterActorIter
16717 * @child: (out): return location for a #ClutterActor
16719 * Advances the @iter and retrieves the next child of the root #ClutterActor
16720 * that was used to initialize the #ClutterActorIterator.
16722 * If the iterator can advance, this function returns %TRUE and sets the
16725 * If the iterator cannot advance, this function returns %FALSE, and
16726 * the contents of @child are undefined.
16728 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16733 clutter_actor_iter_next (ClutterActorIter *iter,
16734 ClutterActor **child)
16736 RealActorIter *ri = (RealActorIter *) iter;
16738 g_return_val_if_fail (iter != NULL, FALSE);
16739 g_return_val_if_fail (ri->root != NULL, FALSE);
16740 #ifndef G_DISABLE_ASSERT
16741 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16744 if (ri->current == NULL)
16745 ri->current = ri->root->priv->first_child;
16747 ri->current = ri->current->priv->next_sibling;
16750 *child = ri->current;
16752 return ri->current != NULL;
16756 * clutter_actor_iter_prev:
16757 * @iter: a #ClutterActorIter
16758 * @child: (out): return location for a #ClutterActor
16760 * Advances the @iter and retrieves the previous child of the root
16761 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16763 * If the iterator can advance, this function returns %TRUE and sets the
16766 * If the iterator cannot advance, this function returns %FALSE, and
16767 * the contents of @child are undefined.
16769 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16774 clutter_actor_iter_prev (ClutterActorIter *iter,
16775 ClutterActor **child)
16777 RealActorIter *ri = (RealActorIter *) iter;
16779 g_return_val_if_fail (iter != NULL, FALSE);
16780 g_return_val_if_fail (ri->root != NULL, FALSE);
16781 #ifndef G_DISABLE_ASSERT
16782 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16785 if (ri->current == NULL)
16786 ri->current = ri->root->priv->last_child;
16788 ri->current = ri->current->priv->prev_sibling;
16791 *child = ri->current;
16793 return ri->current != NULL;
16797 * clutter_actor_iter_remove:
16798 * @iter: a #ClutterActorIter
16800 * Safely removes the #ClutterActor currently pointer to by the iterator
16803 * This function can only be called after clutter_actor_iter_next() or
16804 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16805 * than once for the same actor.
16807 * This function will call clutter_actor_remove_child() internally.
16812 clutter_actor_iter_remove (ClutterActorIter *iter)
16814 RealActorIter *ri = (RealActorIter *) iter;
16817 g_return_if_fail (iter != NULL);
16818 g_return_if_fail (ri->root != NULL);
16819 #ifndef G_DISABLE_ASSERT
16820 g_return_if_fail (ri->age == ri->root->priv->age);
16822 g_return_if_fail (ri->current != NULL);
16828 ri->current = cur->priv->prev_sibling;
16830 clutter_actor_remove_child_internal (ri->root, cur,
16831 REMOVE_CHILD_DEFAULT_FLAGS);
16838 * clutter_actor_iter_destroy:
16839 * @iter: a #ClutterActorIter
16841 * Safely destroys the #ClutterActor currently pointer to by the iterator
16844 * This function can only be called after clutter_actor_iter_next() or
16845 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16846 * than once for the same actor.
16848 * This function will call clutter_actor_destroy() internally.
16853 clutter_actor_iter_destroy (ClutterActorIter *iter)
16855 RealActorIter *ri = (RealActorIter *) iter;
16858 g_return_if_fail (iter != NULL);
16859 g_return_if_fail (ri->root != NULL);
16860 #ifndef G_DISABLE_ASSERT
16861 g_return_if_fail (ri->age == ri->root->priv->age);
16863 g_return_if_fail (ri->current != NULL);
16869 ri->current = cur->priv->prev_sibling;
16871 clutter_actor_destroy (cur);
16877 static const ClutterAnimationInfo default_animation_info = {
16878 NULL, /* transitions */
16880 NULL, /* cur_state */
16884 clutter_animation_info_free (gpointer data)
16888 ClutterAnimationInfo *info = data;
16890 if (info->transitions != NULL)
16891 g_hash_table_unref (info->transitions);
16893 if (info->states != NULL)
16894 g_array_unref (info->states);
16896 g_slice_free (ClutterAnimationInfo, info);
16900 const ClutterAnimationInfo *
16901 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16903 const ClutterAnimationInfo *res;
16904 GObject *obj = G_OBJECT (self);
16906 res = g_object_get_qdata (obj, quark_actor_animation_info);
16910 return &default_animation_info;
16913 ClutterAnimationInfo *
16914 _clutter_actor_get_animation_info (ClutterActor *self)
16916 GObject *obj = G_OBJECT (self);
16917 ClutterAnimationInfo *res;
16919 res = g_object_get_qdata (obj, quark_actor_animation_info);
16922 res = g_slice_new (ClutterAnimationInfo);
16924 *res = default_animation_info;
16926 g_object_set_qdata_full (obj, quark_actor_animation_info,
16928 clutter_animation_info_free);
16934 ClutterTransition *
16935 _clutter_actor_get_transition (ClutterActor *actor,
16938 const ClutterAnimationInfo *info;
16940 info = _clutter_actor_get_animation_info_or_defaults (actor);
16942 if (info->transitions == NULL)
16945 return g_hash_table_lookup (info->transitions, pspec->name);
16948 typedef struct _TransitionClosure
16950 ClutterActor *actor;
16951 ClutterTransition *transition;
16953 gulong completed_id;
16954 } TransitionClosure;
16957 transition_closure_free (gpointer data)
16959 if (G_LIKELY (data != NULL))
16961 TransitionClosure *clos = data;
16962 ClutterTimeline *timeline;
16964 timeline = CLUTTER_TIMELINE (clos->transition);
16966 if (clutter_timeline_is_playing (timeline))
16967 clutter_timeline_stop (timeline);
16969 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16971 g_object_unref (clos->transition);
16972 g_free (clos->name);
16974 g_slice_free (TransitionClosure, clos);
16979 on_transition_completed (ClutterTransition *transition,
16980 TransitionClosure *clos)
16982 ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
16983 ClutterActor *actor = clos->actor;
16984 ClutterAnimationInfo *info;
16985 gint n_repeats, cur_repeat;
16987 info = _clutter_actor_get_animation_info (actor);
16989 /* reset the caches used by animations */
16990 clutter_actor_store_content_box (actor, NULL);
16992 /* ensure that we remove the transition only at the end
16993 * of its run; we emit ::completed for every repeat
16995 n_repeats = clutter_timeline_get_repeat_count (timeline);
16996 cur_repeat = clutter_timeline_get_current_repeat (timeline);
16998 if (cur_repeat == n_repeats)
17000 if (clutter_transition_get_remove_on_complete (transition))
17002 /* we take a reference here because removing the closure
17003 * will release the reference on the transition, and we
17004 * want the transition to survive the signal emission;
17005 * the master clock will release the last reference at
17006 * the end of the frame processing.
17008 g_object_ref (transition);
17009 g_hash_table_remove (info->transitions, clos->name);
17013 /* if it's the last transition then we clean up */
17014 if (g_hash_table_size (info->transitions) == 0)
17016 g_hash_table_unref (info->transitions);
17017 info->transitions = NULL;
17019 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17020 _clutter_actor_get_debug_name (actor));
17022 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17027 _clutter_actor_update_transition (ClutterActor *actor,
17031 TransitionClosure *clos;
17032 ClutterTimeline *timeline;
17033 ClutterInterval *interval;
17034 const ClutterAnimationInfo *info;
17037 GValue initial = G_VALUE_INIT;
17038 GValue final = G_VALUE_INIT;
17039 char *error = NULL;
17041 info = _clutter_actor_get_animation_info_or_defaults (actor);
17043 if (info->transitions == NULL)
17046 clos = g_hash_table_lookup (info->transitions, pspec->name);
17050 timeline = CLUTTER_TIMELINE (clos->transition);
17052 va_start (var_args, pspec);
17054 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17056 g_value_init (&initial, ptype);
17057 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17061 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17064 g_critical ("%s: %s", G_STRLOC, error);
17069 interval = clutter_transition_get_interval (clos->transition);
17070 clutter_interval_set_initial_value (interval, &initial);
17071 clutter_interval_set_final_value (interval, &final);
17073 /* if we're updating with an easing duration of zero milliseconds,
17074 * we just jump the timeline to the end and let it run its course
17076 if (info->cur_state != NULL &&
17077 info->cur_state->easing_duration != 0)
17079 guint cur_duration = clutter_timeline_get_duration (timeline);
17080 ClutterAnimationMode cur_mode =
17081 clutter_timeline_get_progress_mode (timeline);
17083 if (cur_duration != info->cur_state->easing_duration)
17084 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17086 if (cur_mode != info->cur_state->easing_mode)
17087 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17089 clutter_timeline_rewind (timeline);
17093 guint duration = clutter_timeline_get_duration (timeline);
17095 clutter_timeline_advance (timeline, duration);
17099 g_value_unset (&initial);
17100 g_value_unset (&final);
17106 * _clutter_actor_create_transition:
17107 * @actor: a #ClutterActor
17108 * @pspec: the property used for the transition
17109 * @...: initial and final state
17111 * Creates a #ClutterTransition for the property represented by @pspec.
17113 * Return value: a #ClutterTransition
17115 ClutterTransition *
17116 _clutter_actor_create_transition (ClutterActor *actor,
17120 ClutterAnimationInfo *info;
17121 ClutterTransition *res = NULL;
17122 gboolean call_restore = FALSE;
17123 TransitionClosure *clos;
17126 info = _clutter_actor_get_animation_info (actor);
17128 /* XXX - this will go away in 2.0
17130 * if no state has been pushed, we assume that the easing state is
17131 * in "compatibility mode": all transitions have a duration of 0
17132 * msecs, which means that they happen immediately. in Clutter 2.0
17133 * this will turn into a g_assert(info->states != NULL), as every
17134 * actor will start with a predefined easing state
17136 if (info->states == NULL)
17138 clutter_actor_save_easing_state (actor);
17139 clutter_actor_set_easing_duration (actor, 0);
17140 call_restore = TRUE;
17143 if (info->transitions == NULL)
17144 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17146 transition_closure_free);
17148 va_start (var_args, pspec);
17150 clos = g_hash_table_lookup (info->transitions, pspec->name);
17153 ClutterInterval *interval;
17154 GValue initial = G_VALUE_INIT;
17155 GValue final = G_VALUE_INIT;
17159 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17161 G_VALUE_COLLECT_INIT (&initial, ptype,
17166 g_critical ("%s: %s", G_STRLOC, error);
17171 G_VALUE_COLLECT_INIT (&final, ptype,
17177 g_critical ("%s: %s", G_STRLOC, error);
17178 g_value_unset (&initial);
17183 /* if the current easing state has a duration of 0, then we don't
17184 * bother to create the transition, and we just set the final value
17185 * directly on the actor; we don't go through the Animatable
17186 * interface because we know we got here through an animatable
17189 if (info->cur_state->easing_duration == 0)
17191 clutter_actor_set_animatable_property (actor,
17195 g_value_unset (&initial);
17196 g_value_unset (&final);
17201 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17203 g_value_unset (&initial);
17204 g_value_unset (&final);
17206 res = clutter_property_transition_new (pspec->name);
17208 clutter_transition_set_interval (res, interval);
17209 clutter_transition_set_remove_on_complete (res, TRUE);
17211 /* this will start the transition as well */
17212 clutter_actor_add_transition (actor, pspec->name, res);
17214 /* the actor now owns the transition */
17215 g_object_unref (res);
17218 res = clos->transition;
17222 clutter_actor_restore_easing_state (actor);
17230 * clutter_actor_add_transition:
17231 * @self: a #ClutterActor
17232 * @name: the name of the transition to add
17233 * @transition: the #ClutterTransition to add
17235 * Adds a @transition to the #ClutterActor's list of animations.
17237 * The @name string is a per-actor unique identifier of the @transition: only
17238 * one #ClutterTransition can be associated to the specified @name.
17240 * The @transition will be given the easing duration, mode, and delay
17241 * associated to the actor's current easing state; it is possible to modify
17242 * these values after calling clutter_actor_add_transition().
17244 * The @transition will be started once added.
17246 * This function will take a reference on the @transition.
17248 * This function is usually called implicitly when modifying an animatable
17254 clutter_actor_add_transition (ClutterActor *self,
17256 ClutterTransition *transition)
17258 ClutterTimeline *timeline;
17259 TransitionClosure *clos;
17260 ClutterAnimationInfo *info;
17262 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17263 g_return_if_fail (name != NULL);
17264 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17266 info = _clutter_actor_get_animation_info (self);
17268 if (info->cur_state == NULL)
17270 g_warning ("No easing state is defined for the actor '%s'; you "
17271 "must call clutter_actor_save_easing_state() before "
17272 "calling clutter_actor_add_transition().",
17273 _clutter_actor_get_debug_name (self));
17277 if (info->transitions == NULL)
17278 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17280 transition_closure_free);
17282 if (g_hash_table_lookup (info->transitions, name) != NULL)
17284 g_warning ("A transition with name '%s' already exists for "
17287 _clutter_actor_get_debug_name (self));
17291 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17293 timeline = CLUTTER_TIMELINE (transition);
17295 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17296 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17297 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17299 clos = g_slice_new (TransitionClosure);
17300 clos->actor = self;
17301 clos->transition = g_object_ref (transition);
17302 clos->name = g_strdup (name);
17303 clos->completed_id = g_signal_connect (timeline, "completed",
17304 G_CALLBACK (on_transition_completed),
17307 CLUTTER_NOTE (ANIMATION,
17308 "Adding transition '%s' [%p] to actor '%s'",
17311 _clutter_actor_get_debug_name (self));
17313 g_hash_table_insert (info->transitions, clos->name, clos);
17314 clutter_timeline_start (timeline);
17318 * clutter_actor_remove_transition:
17319 * @self: a #ClutterActor
17320 * @name: the name of the transition to remove
17322 * Removes the transition stored inside a #ClutterActor using @name
17325 * If the transition is currently in progress, it will be stopped.
17327 * This function releases the reference acquired when the transition
17328 * was added to the #ClutterActor.
17333 clutter_actor_remove_transition (ClutterActor *self,
17336 const ClutterAnimationInfo *info;
17338 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17339 g_return_if_fail (name != NULL);
17341 info = _clutter_actor_get_animation_info_or_defaults (self);
17343 if (info->transitions == NULL)
17346 g_hash_table_remove (info->transitions, name);
17350 * clutter_actor_remove_all_transitions:
17351 * @self: a #ClutterActor
17353 * Removes all transitions associated to @self.
17358 clutter_actor_remove_all_transitions (ClutterActor *self)
17360 const ClutterAnimationInfo *info;
17362 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17364 info = _clutter_actor_get_animation_info_or_defaults (self);
17365 if (info->transitions == NULL)
17368 g_hash_table_remove_all (info->transitions);
17372 * clutter_actor_set_easing_duration:
17373 * @self: a #ClutterActor
17374 * @msecs: the duration of the easing, or %NULL
17376 * Sets the duration of the tweening for animatable properties
17377 * of @self for the current easing state.
17382 clutter_actor_set_easing_duration (ClutterActor *self,
17385 ClutterAnimationInfo *info;
17387 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17389 info = _clutter_actor_get_animation_info (self);
17391 if (info->cur_state == NULL)
17393 g_warning ("You must call clutter_actor_save_easing_state() prior "
17394 "to calling clutter_actor_set_easing_duration().");
17398 if (info->cur_state->easing_duration != msecs)
17399 info->cur_state->easing_duration = msecs;
17403 * clutter_actor_get_easing_duration:
17404 * @self: a #ClutterActor
17406 * Retrieves the duration of the tweening for animatable
17407 * properties of @self for the current easing state.
17409 * Return value: the duration of the tweening, in milliseconds
17414 clutter_actor_get_easing_duration (ClutterActor *self)
17416 const ClutterAnimationInfo *info;
17418 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17420 info = _clutter_actor_get_animation_info_or_defaults (self);
17422 if (info->cur_state != NULL)
17423 return info->cur_state->easing_duration;
17429 * clutter_actor_set_easing_mode:
17430 * @self: a #ClutterActor
17431 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17433 * Sets the easing mode for the tweening of animatable properties
17439 clutter_actor_set_easing_mode (ClutterActor *self,
17440 ClutterAnimationMode mode)
17442 ClutterAnimationInfo *info;
17444 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17445 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17446 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17448 info = _clutter_actor_get_animation_info (self);
17450 if (info->cur_state == NULL)
17452 g_warning ("You must call clutter_actor_save_easing_state() prior "
17453 "to calling clutter_actor_set_easing_mode().");
17457 if (info->cur_state->easing_mode != mode)
17458 info->cur_state->easing_mode = mode;
17462 * clutter_actor_get_easing_mode:
17463 * @self: a #ClutterActor
17465 * Retrieves the easing mode for the tweening of animatable properties
17466 * of @self for the current easing state.
17468 * Return value: an easing mode
17472 ClutterAnimationMode
17473 clutter_actor_get_easing_mode (ClutterActor *self)
17475 const ClutterAnimationInfo *info;
17477 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17479 info = _clutter_actor_get_animation_info_or_defaults (self);
17481 if (info->cur_state != NULL)
17482 return info->cur_state->easing_mode;
17484 return CLUTTER_EASE_OUT_CUBIC;
17488 * clutter_actor_set_easing_delay:
17489 * @self: a #ClutterActor
17490 * @msecs: the delay before the start of the tweening, in milliseconds
17492 * Sets the delay that should be applied before tweening animatable
17498 clutter_actor_set_easing_delay (ClutterActor *self,
17501 ClutterAnimationInfo *info;
17503 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17505 info = _clutter_actor_get_animation_info (self);
17507 if (info->cur_state == NULL)
17509 g_warning ("You must call clutter_actor_save_easing_state() prior "
17510 "to calling clutter_actor_set_easing_delay().");
17514 if (info->cur_state->easing_delay != msecs)
17515 info->cur_state->easing_delay = msecs;
17519 * clutter_actor_get_easing_delay:
17520 * @self: a #ClutterActor
17522 * Retrieves the delay that should be applied when tweening animatable
17525 * Return value: a delay, in milliseconds
17530 clutter_actor_get_easing_delay (ClutterActor *self)
17532 const ClutterAnimationInfo *info;
17534 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17536 info = _clutter_actor_get_animation_info_or_defaults (self);
17538 if (info->cur_state != NULL)
17539 return info->cur_state->easing_delay;
17545 * clutter_actor_get_transition:
17546 * @self: a #ClutterActor
17547 * @name: the name of the transition
17549 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17550 * transition @name.
17552 * Transitions created for animatable properties use the name of the
17553 * property itself, for instance the code below:
17556 * clutter_actor_set_easing_duration (actor, 1000);
17557 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17559 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17560 * g_signal_connect (transition, "completed",
17561 * G_CALLBACK (on_transition_complete),
17565 * will call the <function>on_transition_complete</function> callback when
17566 * the transition is complete.
17568 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17569 * was found to match the passed name; the returned instance is owned
17570 * by Clutter and it should not be freed
17574 ClutterTransition *
17575 clutter_actor_get_transition (ClutterActor *self,
17578 TransitionClosure *clos;
17579 const ClutterAnimationInfo *info;
17581 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17582 g_return_val_if_fail (name != NULL, NULL);
17584 info = _clutter_actor_get_animation_info_or_defaults (self);
17585 if (info->transitions == NULL)
17588 clos = g_hash_table_lookup (info->transitions, name);
17592 return clos->transition;
17596 * clutter_actor_save_easing_state:
17597 * @self: a #ClutterActor
17599 * Saves the current easing state for animatable properties, and creates
17600 * a new state with the default values for easing mode and duration.
17605 clutter_actor_save_easing_state (ClutterActor *self)
17607 ClutterAnimationInfo *info;
17610 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17612 info = _clutter_actor_get_animation_info (self);
17614 if (info->states == NULL)
17615 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17617 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17618 new_state.easing_duration = 250;
17619 new_state.easing_delay = 0;
17621 g_array_append_val (info->states, new_state);
17623 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17627 * clutter_actor_restore_easing_state:
17628 * @self: a #ClutterActor
17630 * Restores the easing state as it was prior to a call to
17631 * clutter_actor_save_easing_state().
17636 clutter_actor_restore_easing_state (ClutterActor *self)
17638 ClutterAnimationInfo *info;
17640 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17642 info = _clutter_actor_get_animation_info (self);
17644 if (info->states == NULL)
17646 g_critical ("The function clutter_actor_restore_easing_state() has "
17647 "called without a previous call to "
17648 "clutter_actor_save_easing_state().");
17652 g_array_remove_index (info->states, info->states->len - 1);
17654 if (info->states->len > 0)
17655 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17658 g_array_unref (info->states);
17659 info->states = NULL;
17660 info->cur_state = NULL;
17665 * clutter_actor_set_content:
17666 * @self: a #ClutterActor
17667 * @content: (allow-none): a #ClutterContent, or %NULL
17669 * Sets the contents of a #ClutterActor.
17674 clutter_actor_set_content (ClutterActor *self,
17675 ClutterContent *content)
17677 ClutterActorPrivate *priv;
17679 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17680 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17684 if (priv->content != NULL)
17686 _clutter_content_detached (priv->content, self);
17687 g_clear_object (&priv->content);
17690 priv->content = content;
17692 if (priv->content != NULL)
17694 g_object_ref (priv->content);
17695 _clutter_content_attached (priv->content, self);
17698 /* given that the content is always painted within the allocation,
17699 * we only need to queue a redraw here
17701 clutter_actor_queue_redraw (self);
17703 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17705 /* if the content gravity is not resize-fill, and the new content has a
17706 * different preferred size than the previous one, then the content box
17707 * may have been changed. since we compute that lazily, we just notify
17708 * here, and let whomever watches :content-box do whatever they need to
17711 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17712 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17716 * clutter_actor_get_content:
17717 * @self: a #ClutterActor
17719 * Retrieves the contents of @self.
17721 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17722 * or %NULL if none was set
17727 clutter_actor_get_content (ClutterActor *self)
17729 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17731 return self->priv->content;
17735 * clutter_actor_set_content_gravity:
17736 * @self: a #ClutterActor
17737 * @gravity: the #ClutterContentGravity
17739 * Sets the gravity of the #ClutterContent used by @self.
17741 * See the description of the #ClutterActor:content-gravity property for
17742 * more information.
17744 * The #ClutterActor:content-gravity property is animatable.
17749 clutter_actor_set_content_gravity (ClutterActor *self,
17750 ClutterContentGravity gravity)
17752 ClutterActorPrivate *priv;
17754 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17758 if (priv->content_gravity == gravity)
17761 priv->content_box_valid = FALSE;
17763 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17765 ClutterActorBox from_box, to_box;
17767 clutter_actor_get_content_box (self, &from_box);
17769 priv->content_gravity = gravity;
17771 clutter_actor_get_content_box (self, &to_box);
17773 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17779 ClutterActorBox to_box;
17781 priv->content_gravity = gravity;
17783 clutter_actor_get_content_box (self, &to_box);
17785 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17789 clutter_actor_queue_redraw (self);
17791 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
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_box_valid)
17856 *box = priv->content_box;
17860 /* no need to do any more work */
17861 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17864 if (priv->content == NULL)
17867 /* if the content does not have a preferred size then there is
17868 * no point in computing the content box
17870 if (!clutter_content_get_preferred_size (priv->content,
17878 switch (priv->content_gravity)
17880 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17881 box->x2 = box->x1 + MIN (content_w, alloc_w);
17882 box->y2 = box->y1 + MIN (content_h, alloc_h);
17885 case CLUTTER_CONTENT_GRAVITY_TOP:
17886 if (alloc_w > content_w)
17888 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17889 box->x2 = box->x1 + content_w;
17891 box->y2 = box->y1 + MIN (content_h, alloc_h);
17894 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17895 if (alloc_w > content_w)
17897 box->x1 += (alloc_w - content_w);
17898 box->x2 = box->x1 + content_w;
17900 box->y2 = box->y1 + MIN (content_h, alloc_h);
17903 case CLUTTER_CONTENT_GRAVITY_LEFT:
17904 box->x2 = box->x1 + MIN (content_w, alloc_w);
17905 if (alloc_h > content_h)
17907 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17908 box->y2 = box->y1 + content_h;
17912 case CLUTTER_CONTENT_GRAVITY_CENTER:
17913 if (alloc_w > content_w)
17915 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17916 box->x2 = box->x1 + content_w;
17918 if (alloc_h > content_h)
17920 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17921 box->y2 = box->y1 + content_h;
17925 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17926 if (alloc_w > content_w)
17928 box->x1 += (alloc_w - content_w);
17929 box->x2 = box->x1 + content_w;
17931 if (alloc_h > content_h)
17933 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17934 box->y2 = box->y1 + content_h;
17938 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17939 box->x2 = box->x1 + MIN (content_w, alloc_w);
17940 if (alloc_h > content_h)
17942 box->y1 += (alloc_h - content_h);
17943 box->y2 = box->y1 + content_h;
17947 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17948 if (alloc_w > content_w)
17950 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17951 box->x2 = box->x1 + content_w;
17953 if (alloc_h > content_h)
17955 box->y1 += (alloc_h - content_h);
17956 box->y2 = box->y1 + content_h;
17960 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17961 if (alloc_w > content_w)
17963 box->x1 += (alloc_w - content_w);
17964 box->x2 = box->x1 + content_w;
17966 if (alloc_h > content_h)
17968 box->y1 += (alloc_h - content_h);
17969 box->y2 = box->y1 + content_h;
17973 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17974 g_assert_not_reached ();
17977 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17979 double r_c = content_w / content_h;
17980 double r_a = alloc_w / alloc_h;
17989 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17990 box->y2 = box->y1 + (alloc_w * r_c);
17997 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17998 box->x2 = box->x1 + (alloc_h * r_c);
18008 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18009 box->x2 = box->x1 + (alloc_h * r_c);
18016 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18017 box->y2 = box->y1 + (alloc_w * r_c);
18026 * clutter_actor_set_content_scaling_filters:
18027 * @self: a #ClutterActor
18028 * @min_filter: the minification filter for the content
18029 * @mag_filter: the magnification filter for the content
18031 * Sets the minification and magnification filter to be applied when
18032 * scaling the #ClutterActor:content of a #ClutterActor.
18034 * The #ClutterActor:minification-filter will be used when reducing
18035 * the size of the content; the #ClutterActor:magnification-filter
18036 * will be used when increasing the size of the content.
18041 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18042 ClutterScalingFilter min_filter,
18043 ClutterScalingFilter mag_filter)
18045 ClutterActorPrivate *priv;
18049 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18052 obj = G_OBJECT (self);
18054 g_object_freeze_notify (obj);
18058 if (priv->min_filter != min_filter)
18060 priv->min_filter = min_filter;
18063 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18066 if (priv->mag_filter != mag_filter)
18068 priv->mag_filter = mag_filter;
18071 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18075 clutter_actor_queue_redraw (self);
18077 g_object_thaw_notify (obj);
18081 * clutter_actor_get_content_scaling_filters:
18082 * @self: a #ClutterActor
18083 * @min_filter: (out) (allow-none): return location for the minification
18085 * @mag_filter: (out) (allow-none): return location for the magnification
18088 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18093 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18094 ClutterScalingFilter *min_filter,
18095 ClutterScalingFilter *mag_filter)
18097 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18099 if (min_filter != NULL)
18100 *min_filter = self->priv->min_filter;
18102 if (mag_filter != NULL)
18103 *mag_filter = self->priv->mag_filter;