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
791 /* Then the rest of these size-related properties are the "actual"
792 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
797 PROP_FIXED_POSITION_SET,
806 PROP_NATURAL_WIDTH_SET,
809 PROP_NATURAL_HEIGHT_SET,
813 /* Allocation properties are read-only */
820 PROP_CLIP_TO_ALLOCATION,
824 PROP_OFFSCREEN_REDIRECT,
837 PROP_ROTATION_ANGLE_X,
838 PROP_ROTATION_ANGLE_Y,
839 PROP_ROTATION_ANGLE_Z,
840 PROP_ROTATION_CENTER_X,
841 PROP_ROTATION_CENTER_Y,
842 PROP_ROTATION_CENTER_Z,
843 /* This property only makes sense for the z rotation because the
844 others would depend on the actor having a size along the
846 PROP_ROTATION_CENTER_Z_GRAVITY,
852 PROP_SHOW_ON_SET_PARENT,
870 PROP_BACKGROUND_COLOR,
871 PROP_BACKGROUND_COLOR_SET,
877 PROP_CONTENT_GRAVITY,
879 PROP_MINIFICATION_FILTER,
880 PROP_MAGNIFICATION_FILTER,
885 static GParamSpec *obj_props[PROP_LAST];
904 BUTTON_RELEASE_EVENT,
912 TRANSITIONS_COMPLETED,
917 static guint actor_signals[LAST_SIGNAL] = { 0, };
919 static void clutter_container_iface_init (ClutterContainerIface *iface);
920 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
921 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
922 static void atk_implementor_iface_init (AtkImplementorIface *iface);
924 /* These setters are all static for now, maybe they should be in the
925 * public API, but they are perhaps obscure enough to leave only as
928 static void clutter_actor_set_min_width (ClutterActor *self,
930 static void clutter_actor_set_min_height (ClutterActor *self,
932 static void clutter_actor_set_natural_width (ClutterActor *self,
933 gfloat natural_width);
934 static void clutter_actor_set_natural_height (ClutterActor *self,
935 gfloat natural_height);
936 static void clutter_actor_set_min_width_set (ClutterActor *self,
937 gboolean use_min_width);
938 static void clutter_actor_set_min_height_set (ClutterActor *self,
939 gboolean use_min_height);
940 static void clutter_actor_set_natural_width_set (ClutterActor *self,
941 gboolean use_natural_width);
942 static void clutter_actor_set_natural_height_set (ClutterActor *self,
943 gboolean use_natural_height);
944 static void clutter_actor_update_map_state (ClutterActor *self,
945 MapStateChange change);
946 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
948 /* Helper routines for managing anchor coords */
949 static void clutter_anchor_coord_get_units (ClutterActor *self,
950 const AnchorCoord *coord,
954 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
959 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
960 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
961 ClutterGravity gravity);
963 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
965 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
967 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
968 ClutterActor *ancestor,
971 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
973 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
975 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
976 const ClutterColor *color);
978 static void on_layout_manager_changed (ClutterLayoutManager *manager,
981 /* Helper macro which translates by the anchor coord, applies the
982 given transformation and then translates back */
983 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
984 gfloat _tx, _ty, _tz; \
985 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
986 cogl_matrix_translate ((m), _tx, _ty, _tz); \
988 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
990 static GQuark quark_shader_data = 0;
991 static GQuark quark_actor_layout_info = 0;
992 static GQuark quark_actor_transform_info = 0;
993 static GQuark quark_actor_animation_info = 0;
995 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
997 G_TYPE_INITIALLY_UNOWNED,
998 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
999 clutter_container_iface_init)
1000 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1001 clutter_scriptable_iface_init)
1002 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1003 clutter_animatable_iface_init)
1004 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1005 atk_implementor_iface_init));
1008 * clutter_actor_get_debug_name:
1009 * @actor: a #ClutterActor
1011 * Retrieves a printable name of @actor for debugging messages
1013 * Return value: a string with a printable name
1016 _clutter_actor_get_debug_name (ClutterActor *actor)
1018 return actor->priv->name != NULL ? actor->priv->name
1019 : G_OBJECT_TYPE_NAME (actor);
1022 #ifdef CLUTTER_ENABLE_DEBUG
1023 /* XXX - this is for debugging only, remove once working (or leave
1024 * in only in some debug mode). Should leave it for a little while
1025 * until we're confident in the new map/realize/visible handling.
1028 clutter_actor_verify_map_state (ClutterActor *self)
1030 ClutterActorPrivate *priv = self->priv;
1032 if (CLUTTER_ACTOR_IS_REALIZED (self))
1034 /* all bets are off during reparent when we're potentially realized,
1035 * but should not be according to invariants
1037 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1039 if (priv->parent == NULL)
1041 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1045 g_warning ("Realized non-toplevel actor '%s' should "
1047 _clutter_actor_get_debug_name (self));
1049 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1051 g_warning ("Realized actor %s has an unrealized parent %s",
1052 _clutter_actor_get_debug_name (self),
1053 _clutter_actor_get_debug_name (priv->parent));
1058 if (CLUTTER_ACTOR_IS_MAPPED (self))
1060 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1061 g_warning ("Actor '%s' is mapped but not realized",
1062 _clutter_actor_get_debug_name (self));
1064 /* remaining bets are off during reparent when we're potentially
1065 * mapped, but should not be according to invariants
1067 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1069 if (priv->parent == NULL)
1071 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1073 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1074 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1076 g_warning ("Toplevel actor '%s' is mapped "
1078 _clutter_actor_get_debug_name (self));
1083 g_warning ("Mapped actor '%s' should have a parent",
1084 _clutter_actor_get_debug_name (self));
1089 ClutterActor *iter = self;
1091 /* check for the enable_paint_unmapped flag on the actor
1092 * and parents; if the flag is enabled at any point of this
1093 * branch of the scene graph then all the later checks
1096 while (iter != NULL)
1098 if (iter->priv->enable_paint_unmapped)
1101 iter = iter->priv->parent;
1104 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1106 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1108 _clutter_actor_get_debug_name (self),
1109 _clutter_actor_get_debug_name (priv->parent));
1112 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1114 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1116 _clutter_actor_get_debug_name (self),
1117 _clutter_actor_get_debug_name (priv->parent));
1120 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1122 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1123 g_warning ("Actor '%s' is mapped but its non-toplevel "
1124 "parent '%s' is not mapped",
1125 _clutter_actor_get_debug_name (self),
1126 _clutter_actor_get_debug_name (priv->parent));
1133 #endif /* CLUTTER_ENABLE_DEBUG */
1136 clutter_actor_set_mapped (ClutterActor *self,
1139 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1144 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1145 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1149 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1150 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1154 /* this function updates the mapped and realized states according to
1155 * invariants, in the appropriate order.
1158 clutter_actor_update_map_state (ClutterActor *self,
1159 MapStateChange change)
1161 gboolean was_mapped;
1163 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1165 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1167 /* the mapped flag on top-level actors must be set by the
1168 * per-backend implementation because it might be asynchronous.
1170 * That is, the MAPPED flag on toplevels currently tracks the X
1171 * server mapped-ness of the window, while the expected behavior
1172 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1173 * This creates some weird complexity by breaking the invariant
1174 * that if we're visible and all ancestors shown then we are
1175 * also mapped - instead, we are mapped if all ancestors
1176 * _possibly excepting_ the stage are mapped. The stage
1177 * will map/unmap for example when it is minimized or
1178 * moved to another workspace.
1180 * So, the only invariant on the stage is that if visible it
1181 * should be realized, and that it has to be visible to be
1184 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1185 clutter_actor_realize (self);
1189 case MAP_STATE_CHECK:
1192 case MAP_STATE_MAKE_MAPPED:
1193 g_assert (!was_mapped);
1194 clutter_actor_set_mapped (self, TRUE);
1197 case MAP_STATE_MAKE_UNMAPPED:
1198 g_assert (was_mapped);
1199 clutter_actor_set_mapped (self, FALSE);
1202 case MAP_STATE_MAKE_UNREALIZED:
1203 /* we only use MAKE_UNREALIZED in unparent,
1204 * and unparenting a stage isn't possible.
1205 * If someone wants to just unrealize a stage
1206 * then clutter_actor_unrealize() doesn't
1207 * go through this codepath.
1209 g_warning ("Trying to force unrealize stage is not allowed");
1213 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1214 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1215 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1217 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1218 "it is somehow still mapped",
1219 _clutter_actor_get_debug_name (self));
1224 ClutterActorPrivate *priv = self->priv;
1225 ClutterActor *parent = priv->parent;
1226 gboolean should_be_mapped;
1227 gboolean may_be_realized;
1228 gboolean must_be_realized;
1230 should_be_mapped = FALSE;
1231 may_be_realized = TRUE;
1232 must_be_realized = FALSE;
1234 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1236 may_be_realized = FALSE;
1240 /* Maintain invariant that if parent is mapped, and we are
1241 * visible, then we are mapped ... unless parent is a
1242 * stage, in which case we map regardless of parent's map
1243 * state but do require stage to be visible and realized.
1245 * If parent is realized, that does not force us to be
1246 * realized; but if parent is unrealized, that does force
1247 * us to be unrealized.
1249 * The reason we don't force children to realize with
1250 * parents is _clutter_actor_rerealize(); if we require that
1251 * a realized parent means children are realized, then to
1252 * unrealize an actor we would have to unrealize its
1253 * parents, which would end up meaning unrealizing and
1254 * hiding the entire stage. So we allow unrealizing a
1255 * child (as long as that child is not mapped) while that
1256 * child still has a realized parent.
1258 * Also, if we unrealize from leaf nodes to root, and
1259 * realize from root to leaf, the invariants are never
1260 * violated if we allow children to be unrealized
1261 * while parents are realized.
1263 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1264 * to force us to unmap, even though parent is still
1265 * mapped. This is because we're unmapping from leaf nodes
1268 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1269 change != MAP_STATE_MAKE_UNMAPPED)
1271 gboolean parent_is_visible_realized_toplevel;
1273 parent_is_visible_realized_toplevel =
1274 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1275 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1276 CLUTTER_ACTOR_IS_REALIZED (parent));
1278 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1279 parent_is_visible_realized_toplevel)
1281 must_be_realized = TRUE;
1282 should_be_mapped = TRUE;
1286 /* if the actor has been set to be painted even if unmapped
1287 * then we should map it and check for realization as well;
1288 * this is an override for the branch of the scene graph
1289 * which begins with this node
1291 if (priv->enable_paint_unmapped)
1293 if (priv->parent == NULL)
1294 g_warning ("Attempting to map an unparented actor '%s'",
1295 _clutter_actor_get_debug_name (self));
1297 should_be_mapped = TRUE;
1298 must_be_realized = TRUE;
1301 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1302 may_be_realized = FALSE;
1305 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1308 g_warning ("Attempting to map a child that does not "
1309 "meet the necessary invariants: the actor '%s' "
1311 _clutter_actor_get_debug_name (self));
1313 g_warning ("Attempting to map a child that does not "
1314 "meet the necessary invariants: the actor '%s' "
1315 "is parented to an unmapped actor '%s'",
1316 _clutter_actor_get_debug_name (self),
1317 _clutter_actor_get_debug_name (priv->parent));
1320 /* If in reparent, we temporarily suspend unmap and unrealize.
1322 * We want to go in the order "realize, map" and "unmap, unrealize"
1326 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1327 clutter_actor_set_mapped (self, FALSE);
1330 if (must_be_realized)
1331 clutter_actor_realize (self);
1333 /* if we must be realized then we may be, presumably */
1334 g_assert (!(must_be_realized && !may_be_realized));
1337 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1338 clutter_actor_unrealize_not_hiding (self);
1341 if (should_be_mapped)
1343 if (!must_be_realized)
1344 g_warning ("Somehow we think actor '%s' should be mapped but "
1345 "not realized, which isn't allowed",
1346 _clutter_actor_get_debug_name (self));
1348 /* realization is allowed to fail (though I don't know what
1349 * an app is supposed to do about that - shouldn't it just
1350 * be a g_error? anyway, we have to avoid mapping if this
1353 if (CLUTTER_ACTOR_IS_REALIZED (self))
1354 clutter_actor_set_mapped (self, TRUE);
1358 #ifdef CLUTTER_ENABLE_DEBUG
1359 /* check all invariants were kept */
1360 clutter_actor_verify_map_state (self);
1365 clutter_actor_real_map (ClutterActor *self)
1367 ClutterActorPrivate *priv = self->priv;
1368 ClutterActor *stage, *iter;
1370 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1372 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1373 _clutter_actor_get_debug_name (self));
1375 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1377 stage = _clutter_actor_get_stage_internal (self);
1378 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1380 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1382 _clutter_actor_get_debug_name (self));
1384 /* notify on parent mapped before potentially mapping
1385 * children, so apps see a top-down notification.
1387 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1389 for (iter = self->priv->first_child;
1391 iter = iter->priv->next_sibling)
1393 clutter_actor_map (iter);
1398 * clutter_actor_map:
1399 * @self: A #ClutterActor
1401 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1402 * and realizes its children if they are visible. Does nothing if the
1403 * actor is not visible.
1405 * Calling this function is strongly disencouraged: the default
1406 * implementation of #ClutterActorClass.map() will map all the children
1407 * of an actor when mapping its parent.
1409 * When overriding map, it is mandatory to chain up to the parent
1415 clutter_actor_map (ClutterActor *self)
1417 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1419 if (CLUTTER_ACTOR_IS_MAPPED (self))
1422 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1425 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1429 clutter_actor_real_unmap (ClutterActor *self)
1431 ClutterActorPrivate *priv = self->priv;
1434 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1436 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1437 _clutter_actor_get_debug_name (self));
1439 for (iter = self->priv->first_child;
1441 iter = iter->priv->next_sibling)
1443 clutter_actor_unmap (iter);
1446 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1448 /* clear the contents of the last paint volume, so that hiding + moving +
1449 * showing will not result in the wrong area being repainted
1451 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1452 priv->last_paint_volume_valid = TRUE;
1454 /* notify on parent mapped after potentially unmapping
1455 * children, so apps see a bottom-up notification.
1457 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1459 /* relinquish keyboard focus if we were unmapped while owning it */
1460 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1462 ClutterStage *stage;
1464 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1467 _clutter_stage_release_pick_id (stage, priv->pick_id);
1471 if (stage != NULL &&
1472 clutter_stage_get_key_focus (stage) == self)
1474 clutter_stage_set_key_focus (stage, NULL);
1480 * clutter_actor_unmap:
1481 * @self: A #ClutterActor
1483 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1484 * unmaps its children if they were mapped.
1486 * Calling this function is not encouraged: the default #ClutterActor
1487 * implementation of #ClutterActorClass.unmap() will also unmap any
1488 * eventual children by default when their parent is unmapped.
1490 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1491 * chain up to the parent implementation.
1493 * <note>It is important to note that the implementation of the
1494 * #ClutterActorClass.unmap() virtual function may be called after
1495 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1496 * implementation, but it is guaranteed to be called before the
1497 * #GObjectClass.finalize() implementation.</note>
1502 clutter_actor_unmap (ClutterActor *self)
1504 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1506 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1509 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1513 clutter_actor_real_show (ClutterActor *self)
1515 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1517 ClutterActorPrivate *priv = self->priv;
1519 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1521 /* we notify on the "visible" flag in the clutter_actor_show()
1522 * wrapper so the entire show signal emission completes first
1525 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1527 /* we queue a relayout unless the actor is inside a
1528 * container that explicitly told us not to
1530 if (priv->parent != NULL &&
1531 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1533 /* While an actor is hidden the parent may not have
1534 * allocated/requested so we need to start from scratch
1535 * and avoid the short-circuiting in
1536 * clutter_actor_queue_relayout().
1538 priv->needs_width_request = FALSE;
1539 priv->needs_height_request = FALSE;
1540 priv->needs_allocation = FALSE;
1541 clutter_actor_queue_relayout (self);
1547 set_show_on_set_parent (ClutterActor *self,
1550 ClutterActorPrivate *priv = self->priv;
1552 set_show = !!set_show;
1554 if (priv->show_on_set_parent == set_show)
1557 priv->show_on_set_parent = set_show;
1558 g_object_notify_by_pspec (G_OBJECT (self),
1559 obj_props[PROP_SHOW_ON_SET_PARENT]);
1563 * clutter_actor_show:
1564 * @self: A #ClutterActor
1566 * Flags an actor to be displayed. An actor that isn't shown will not
1567 * be rendered on the stage.
1569 * Actors are visible by default.
1571 * If this function is called on an actor without a parent, the
1572 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1576 clutter_actor_show (ClutterActor *self)
1578 ClutterActorPrivate *priv;
1580 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1582 /* simple optimization */
1583 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1585 /* we still need to set the :show-on-set-parent property, in
1586 * case show() is called on an unparented actor
1588 set_show_on_set_parent (self, TRUE);
1592 #ifdef CLUTTER_ENABLE_DEBUG
1593 clutter_actor_verify_map_state (self);
1598 g_object_freeze_notify (G_OBJECT (self));
1600 set_show_on_set_parent (self, TRUE);
1602 g_signal_emit (self, actor_signals[SHOW], 0);
1603 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1605 if (priv->parent != NULL)
1606 clutter_actor_queue_redraw (priv->parent);
1608 g_object_thaw_notify (G_OBJECT (self));
1612 * clutter_actor_show_all:
1613 * @self: a #ClutterActor
1615 * Calls clutter_actor_show() on all children of an actor (if any).
1619 * Deprecated: 1.10: Actors are visible by default
1622 clutter_actor_show_all (ClutterActor *self)
1624 ClutterActorClass *klass;
1626 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1628 klass = CLUTTER_ACTOR_GET_CLASS (self);
1629 if (klass->show_all)
1630 klass->show_all (self);
1634 clutter_actor_real_hide (ClutterActor *self)
1636 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1638 ClutterActorPrivate *priv = self->priv;
1640 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1642 /* we notify on the "visible" flag in the clutter_actor_hide()
1643 * wrapper so the entire hide signal emission completes first
1646 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1648 /* we queue a relayout unless the actor is inside a
1649 * container that explicitly told us not to
1651 if (priv->parent != NULL &&
1652 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1653 clutter_actor_queue_relayout (priv->parent);
1658 * clutter_actor_hide:
1659 * @self: A #ClutterActor
1661 * Flags an actor to be hidden. A hidden actor will not be
1662 * rendered on the stage.
1664 * Actors are visible by default.
1666 * If this function is called on an actor without a parent, the
1667 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1671 clutter_actor_hide (ClutterActor *self)
1673 ClutterActorPrivate *priv;
1675 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1677 /* simple optimization */
1678 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1680 /* we still need to set the :show-on-set-parent property, in
1681 * case hide() is called on an unparented actor
1683 set_show_on_set_parent (self, FALSE);
1687 #ifdef CLUTTER_ENABLE_DEBUG
1688 clutter_actor_verify_map_state (self);
1693 g_object_freeze_notify (G_OBJECT (self));
1695 set_show_on_set_parent (self, FALSE);
1697 g_signal_emit (self, actor_signals[HIDE], 0);
1698 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1700 if (priv->parent != NULL)
1701 clutter_actor_queue_redraw (priv->parent);
1703 g_object_thaw_notify (G_OBJECT (self));
1707 * clutter_actor_hide_all:
1708 * @self: a #ClutterActor
1710 * Calls clutter_actor_hide() on all child actors (if any).
1714 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1715 * prevent its children from being painted as well.
1718 clutter_actor_hide_all (ClutterActor *self)
1720 ClutterActorClass *klass;
1722 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1724 klass = CLUTTER_ACTOR_GET_CLASS (self);
1725 if (klass->hide_all)
1726 klass->hide_all (self);
1730 * clutter_actor_realize:
1731 * @self: A #ClutterActor
1733 * Realization informs the actor that it is attached to a stage. It
1734 * can use this to allocate resources if it wanted to delay allocation
1735 * until it would be rendered. However it is perfectly acceptable for
1736 * an actor to create resources before being realized because Clutter
1737 * only ever has a single rendering context so that actor is free to
1738 * be moved from one stage to another.
1740 * This function does nothing if the actor is already realized.
1742 * Because a realized actor must have realized parent actors, calling
1743 * clutter_actor_realize() will also realize all parents of the actor.
1745 * This function does not realize child actors, except in the special
1746 * case that realizing the stage, when the stage is visible, will
1747 * suddenly map (and thus realize) the children of the stage.
1750 clutter_actor_realize (ClutterActor *self)
1752 ClutterActorPrivate *priv;
1754 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1758 #ifdef CLUTTER_ENABLE_DEBUG
1759 clutter_actor_verify_map_state (self);
1762 if (CLUTTER_ACTOR_IS_REALIZED (self))
1765 /* To be realized, our parent actors must be realized first.
1766 * This will only succeed if we're inside a toplevel.
1768 if (priv->parent != NULL)
1769 clutter_actor_realize (priv->parent);
1771 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1773 /* toplevels can be realized at any time */
1777 /* "Fail" the realization if parent is missing or unrealized;
1778 * this should really be a g_warning() not some kind of runtime
1779 * failure; how can an app possibly recover? Instead it's a bug
1780 * in the app and the app should get an explanatory warning so
1781 * someone can fix it. But for now it's too hard to fix this
1782 * because e.g. ClutterTexture needs reworking.
1784 if (priv->parent == NULL ||
1785 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1789 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1791 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1792 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1794 g_signal_emit (self, actor_signals[REALIZE], 0);
1796 /* Stage actor is allowed to unset the realized flag again in its
1797 * default signal handler, though that is a pathological situation.
1800 /* If realization "failed" we'll have to update child state. */
1801 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1805 clutter_actor_real_unrealize (ClutterActor *self)
1807 /* we must be unmapped (implying our children are also unmapped) */
1808 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1812 * clutter_actor_unrealize:
1813 * @self: A #ClutterActor
1815 * Unrealization informs the actor that it may be being destroyed or
1816 * moved to another stage. The actor may want to destroy any
1817 * underlying graphics resources at this point. However it is
1818 * perfectly acceptable for it to retain the resources until the actor
1819 * is destroyed because Clutter only ever uses a single rendering
1820 * context and all of the graphics resources are valid on any stage.
1822 * Because mapped actors must be realized, actors may not be
1823 * unrealized if they are mapped. This function hides the actor to be
1824 * sure it isn't mapped, an application-visible side effect that you
1825 * may not be expecting.
1827 * This function should not be called by application code.
1830 clutter_actor_unrealize (ClutterActor *self)
1832 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1833 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1835 /* This function should not really be in the public API, because
1836 * there isn't a good reason to call it. ClutterActor will already
1837 * unrealize things for you when it's important to do so.
1839 * If you were using clutter_actor_unrealize() in a dispose
1840 * implementation, then don't, just chain up to ClutterActor's
1843 * If you were using clutter_actor_unrealize() to implement
1844 * unrealizing children of your container, then don't, ClutterActor
1845 * will already take care of that.
1847 * If you were using clutter_actor_unrealize() to re-realize to
1848 * create your resources in a different way, then use
1849 * _clutter_actor_rerealize() (inside Clutter) or just call your
1850 * code that recreates your resources directly (outside Clutter).
1853 #ifdef CLUTTER_ENABLE_DEBUG
1854 clutter_actor_verify_map_state (self);
1857 clutter_actor_hide (self);
1859 clutter_actor_unrealize_not_hiding (self);
1862 static ClutterActorTraverseVisitFlags
1863 unrealize_actor_before_children_cb (ClutterActor *self,
1867 /* If an actor is already unrealized we know its children have also
1868 * already been unrealized... */
1869 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1870 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1872 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1874 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1877 static ClutterActorTraverseVisitFlags
1878 unrealize_actor_after_children_cb (ClutterActor *self,
1882 /* We want to unset the realized flag only _after_
1883 * child actors are unrealized, to maintain invariants.
1885 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1886 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1887 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1891 * clutter_actor_unrealize_not_hiding:
1892 * @self: A #ClutterActor
1894 * Unrealization informs the actor that it may be being destroyed or
1895 * moved to another stage. The actor may want to destroy any
1896 * underlying graphics resources at this point. However it is
1897 * perfectly acceptable for it to retain the resources until the actor
1898 * is destroyed because Clutter only ever uses a single rendering
1899 * context and all of the graphics resources are valid on any stage.
1901 * Because mapped actors must be realized, actors may not be
1902 * unrealized if they are mapped. You must hide the actor or one of
1903 * its parents before attempting to unrealize.
1905 * This function is separate from clutter_actor_unrealize() because it
1906 * does not automatically hide the actor.
1907 * Actors need not be hidden to be unrealized, they just need to
1908 * be unmapped. In fact we don't want to mess up the application's
1909 * setting of the "visible" flag, so hiding is very undesirable.
1911 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1912 * backward compatibility.
1915 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1917 _clutter_actor_traverse (self,
1918 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1919 unrealize_actor_before_children_cb,
1920 unrealize_actor_after_children_cb,
1925 * _clutter_actor_rerealize:
1926 * @self: A #ClutterActor
1927 * @callback: Function to call while unrealized
1928 * @data: data for callback
1930 * If an actor is already unrealized, this just calls the callback.
1932 * If it is realized, it unrealizes temporarily, calls the callback,
1933 * and then re-realizes the actor.
1935 * As a side effect, leaves all children of the actor unrealized if
1936 * the actor was realized but not showing. This is because when we
1937 * unrealize the actor temporarily we must unrealize its children
1938 * (e.g. children of a stage can't be realized if stage window is
1939 * gone). And we aren't clever enough to save the realization state of
1940 * all children. In most cases this should not matter, because
1941 * the children will automatically realize when they next become mapped.
1944 _clutter_actor_rerealize (ClutterActor *self,
1945 ClutterCallback callback,
1948 gboolean was_mapped;
1949 gboolean was_showing;
1950 gboolean was_realized;
1952 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1954 #ifdef CLUTTER_ENABLE_DEBUG
1955 clutter_actor_verify_map_state (self);
1958 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1959 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1960 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1962 /* Must be unmapped to unrealize. Note we only have to hide this
1963 * actor if it was mapped (if all parents were showing). If actor
1964 * is merely visible (but not mapped), then that's fine, we can
1968 clutter_actor_hide (self);
1970 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1972 /* unrealize self and all children */
1973 clutter_actor_unrealize_not_hiding (self);
1975 if (callback != NULL)
1977 (* callback) (self, data);
1981 clutter_actor_show (self); /* will realize only if mapping implies it */
1982 else if (was_realized)
1983 clutter_actor_realize (self); /* realize self and all parents */
1987 clutter_actor_real_pick (ClutterActor *self,
1988 const ClutterColor *color)
1990 /* the default implementation is just to paint a rectangle
1991 * with the same size of the actor using the passed color
1993 if (clutter_actor_should_pick_paint (self))
1995 ClutterActorBox box = { 0, };
1996 float width, height;
1998 clutter_actor_get_allocation_box (self, &box);
2000 width = box.x2 - box.x1;
2001 height = box.y2 - box.y1;
2003 cogl_set_source_color4ub (color->red,
2008 cogl_rectangle (0, 0, width, height);
2011 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2012 * with existing container classes that override the pick() virtual
2013 * and chain up to the default implementation - otherwise we'll end up
2014 * painting our children twice.
2016 * this has to go away for 2.0; hopefully along the pick() itself.
2018 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2022 for (iter = self->priv->first_child;
2024 iter = iter->priv->next_sibling)
2025 clutter_actor_paint (iter);
2030 * clutter_actor_should_pick_paint:
2031 * @self: A #ClutterActor
2033 * Should be called inside the implementation of the
2034 * #ClutterActor::pick virtual function in order to check whether
2035 * the actor should paint itself in pick mode or not.
2037 * This function should never be called directly by applications.
2039 * Return value: %TRUE if the actor should paint its silhouette,
2043 clutter_actor_should_pick_paint (ClutterActor *self)
2045 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2047 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2048 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2049 CLUTTER_ACTOR_IS_REACTIVE (self)))
2056 clutter_actor_real_get_preferred_width (ClutterActor *self,
2058 gfloat *min_width_p,
2059 gfloat *natural_width_p)
2061 ClutterActorPrivate *priv = self->priv;
2063 if (priv->n_children != 0 &&
2064 priv->layout_manager != NULL)
2066 ClutterContainer *container = CLUTTER_CONTAINER (self);
2068 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2069 "for the preferred width",
2070 G_OBJECT_TYPE_NAME (priv->layout_manager),
2071 priv->layout_manager);
2073 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2082 /* Default implementation is always 0x0, usually an actor
2083 * using this default is relying on someone to set the
2086 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2091 if (natural_width_p)
2092 *natural_width_p = 0;
2096 clutter_actor_real_get_preferred_height (ClutterActor *self,
2098 gfloat *min_height_p,
2099 gfloat *natural_height_p)
2101 ClutterActorPrivate *priv = self->priv;
2103 if (priv->n_children != 0 &&
2104 priv->layout_manager != NULL)
2106 ClutterContainer *container = CLUTTER_CONTAINER (self);
2108 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2109 "for the preferred height",
2110 G_OBJECT_TYPE_NAME (priv->layout_manager),
2111 priv->layout_manager);
2113 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2121 /* Default implementation is always 0x0, usually an actor
2122 * using this default is relying on someone to set the
2125 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2130 if (natural_height_p)
2131 *natural_height_p = 0;
2135 clutter_actor_store_old_geometry (ClutterActor *self,
2136 ClutterActorBox *box)
2138 *box = self->priv->allocation;
2142 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2143 const ClutterActorBox *old)
2145 ClutterActorPrivate *priv = self->priv;
2146 GObject *obj = G_OBJECT (self);
2148 g_object_freeze_notify (obj);
2150 /* to avoid excessive requisition or allocation cycles we
2151 * use the cached values.
2153 * - if we don't have an allocation we assume that we need
2155 * - if we don't have a width or a height request we notify
2157 * - if we have a valid allocation then we check the old
2158 * bounding box with the current allocation and we notify
2161 if (priv->needs_allocation)
2163 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2164 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2165 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2166 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2168 else if (priv->needs_width_request || priv->needs_height_request)
2170 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2171 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2176 gfloat width, height;
2178 x = priv->allocation.x1;
2179 y = priv->allocation.y1;
2180 width = priv->allocation.x2 - priv->allocation.x1;
2181 height = priv->allocation.y2 - priv->allocation.y1;
2184 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2187 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2189 if (width != (old->x2 - old->x1))
2190 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2192 if (height != (old->y2 - old->y1))
2193 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2196 g_object_thaw_notify (obj);
2200 * clutter_actor_set_allocation_internal:
2201 * @self: a #ClutterActor
2202 * @box: a #ClutterActorBox
2203 * @flags: allocation flags
2205 * Stores the allocation of @self.
2207 * This function only performs basic storage and property notification.
2209 * This function should be called by clutter_actor_set_allocation()
2210 * and by the default implementation of #ClutterActorClass.allocate().
2212 * Return value: %TRUE if the allocation of the #ClutterActor has been
2213 * changed, and %FALSE otherwise
2215 static inline gboolean
2216 clutter_actor_set_allocation_internal (ClutterActor *self,
2217 const ClutterActorBox *box,
2218 ClutterAllocationFlags flags)
2220 ClutterActorPrivate *priv = self->priv;
2222 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2223 gboolean flags_changed;
2225 ClutterActorBox old_alloc = { 0, };
2227 obj = G_OBJECT (self);
2229 g_object_freeze_notify (obj);
2231 clutter_actor_store_old_geometry (self, &old_alloc);
2233 x1_changed = priv->allocation.x1 != box->x1;
2234 y1_changed = priv->allocation.y1 != box->y1;
2235 x2_changed = priv->allocation.x2 != box->x2;
2236 y2_changed = priv->allocation.y2 != box->y2;
2238 flags_changed = priv->allocation_flags != flags;
2240 priv->allocation = *box;
2241 priv->allocation_flags = flags;
2243 /* allocation is authoritative */
2244 priv->needs_width_request = FALSE;
2245 priv->needs_height_request = FALSE;
2246 priv->needs_allocation = FALSE;
2248 if (x1_changed || y1_changed ||
2249 x2_changed || y2_changed ||
2252 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2253 _clutter_actor_get_debug_name (self));
2255 priv->transform_valid = FALSE;
2257 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2259 /* if the allocation changes, so does the content box */
2260 if (priv->content != NULL)
2262 priv->content_box_valid = FALSE;
2263 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2271 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2273 g_object_thaw_notify (obj);
2278 static void clutter_actor_real_allocate (ClutterActor *self,
2279 const ClutterActorBox *box,
2280 ClutterAllocationFlags flags);
2283 clutter_actor_maybe_layout_children (ClutterActor *self,
2284 const ClutterActorBox *allocation,
2285 ClutterAllocationFlags flags)
2287 ClutterActorPrivate *priv = self->priv;
2289 /* this is going to be a bit hard to follow, so let's put an explanation
2292 * we want ClutterActor to have a default layout manager if the actor was
2293 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2295 * we also want any subclass of ClutterActor that does not override the
2296 * ::allocate() virtual function to delegate to a layout manager.
2298 * finally, we want to allow people subclassing ClutterActor and overriding
2299 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2301 * on the other hand, we want existing actor subclasses overriding the
2302 * ::allocate() virtual function and chaining up to the parent's
2303 * implementation to continue working without allocating their children
2304 * twice, or without entering an allocation loop.
2306 * for the first two points, we check if the class of the actor is
2307 * overridding the ::allocate() virtual function; if it isn't, then we
2308 * follow through with checking whether we have children and a layout
2309 * manager, and eventually calling clutter_layout_manager_allocate().
2311 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2312 * allocation flags that we got passed, and if it is present, we continue
2313 * with the check above.
2315 * if neither of these two checks yields a positive result, we just
2316 * assume that the ::allocate() virtual function that resulted in this
2317 * function being called will also allocate the children of the actor.
2320 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2323 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2329 if (priv->n_children != 0 &&
2330 priv->layout_manager != NULL)
2332 ClutterContainer *container = CLUTTER_CONTAINER (self);
2333 ClutterAllocationFlags children_flags;
2334 ClutterActorBox children_box;
2336 /* normalize the box passed to the layout manager */
2337 children_box.x1 = children_box.y1 = 0.f;
2338 children_box.x2 = (allocation->x2 - allocation->x1);
2339 children_box.y2 = (allocation->y2 - allocation->y1);
2341 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2342 * the actor's children, since it refers only to the current
2343 * actor's allocation.
2345 children_flags = flags;
2346 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2348 CLUTTER_NOTE (LAYOUT,
2349 "Allocating %d children of %s "
2350 "at { %.2f, %.2f - %.2f x %.2f } "
2353 _clutter_actor_get_debug_name (self),
2356 (allocation->x2 - allocation->x1),
2357 (allocation->y2 - allocation->y1),
2358 G_OBJECT_TYPE_NAME (priv->layout_manager));
2360 clutter_layout_manager_allocate (priv->layout_manager,
2368 clutter_actor_real_allocate (ClutterActor *self,
2369 const ClutterActorBox *box,
2370 ClutterAllocationFlags flags)
2372 ClutterActorPrivate *priv = self->priv;
2375 g_object_freeze_notify (G_OBJECT (self));
2377 changed = clutter_actor_set_allocation_internal (self, box, flags);
2379 /* we allocate our children before we notify changes in our geometry,
2380 * so that people connecting to properties will be able to get valid
2381 * data out of the sub-tree of the scene graph that has this actor at
2384 clutter_actor_maybe_layout_children (self, box, flags);
2388 ClutterActorBox signal_box = priv->allocation;
2389 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2391 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2396 g_object_thaw_notify (G_OBJECT (self));
2400 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2401 ClutterActor *origin)
2403 /* no point in queuing a redraw on a destroyed actor */
2404 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2407 /* NB: We can't bail out early here if the actor is hidden in case
2408 * the actor bas been cloned. In this case the clone will need to
2409 * receive the signal so it can queue its own redraw.
2412 /* calls klass->queue_redraw in default handler */
2413 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2417 clutter_actor_real_queue_redraw (ClutterActor *self,
2418 ClutterActor *origin)
2420 ClutterActor *parent;
2422 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2423 _clutter_actor_get_debug_name (self),
2424 origin != NULL ? _clutter_actor_get_debug_name (origin)
2427 /* no point in queuing a redraw on a destroyed actor */
2428 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2431 /* If the queue redraw is coming from a child then the actor has
2432 become dirty and any queued effect is no longer valid */
2435 self->priv->is_dirty = TRUE;
2436 self->priv->effect_to_redraw = NULL;
2439 /* If the actor isn't visible, we still had to emit the signal
2440 * to allow for a ClutterClone, but the appearance of the parent
2441 * won't change so we don't have to propagate up the hierarchy.
2443 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2446 /* Although we could determine here that a full stage redraw
2447 * has already been queued and immediately bail out, we actually
2448 * guarantee that we will propagate a queue-redraw signal to our
2449 * parent at least once so that it's possible to implement a
2450 * container that tracks which of its children have queued a
2453 if (self->priv->propagated_one_redraw)
2455 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2456 if (stage != NULL &&
2457 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2461 self->priv->propagated_one_redraw = TRUE;
2463 /* notify parents, if they are all visible eventually we'll
2464 * queue redraw on the stage, which queues the redraw idle.
2466 parent = clutter_actor_get_parent (self);
2469 /* this will go up recursively */
2470 _clutter_actor_signal_queue_redraw (parent, origin);
2475 clutter_actor_real_queue_relayout (ClutterActor *self)
2477 ClutterActorPrivate *priv = self->priv;
2479 /* no point in queueing a redraw on a destroyed actor */
2480 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2483 priv->needs_width_request = TRUE;
2484 priv->needs_height_request = TRUE;
2485 priv->needs_allocation = TRUE;
2487 /* reset the cached size requests */
2488 memset (priv->width_requests, 0,
2489 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2490 memset (priv->height_requests, 0,
2491 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2493 /* We need to go all the way up the hierarchy */
2494 if (priv->parent != NULL)
2495 _clutter_actor_queue_only_relayout (priv->parent);
2499 * clutter_actor_apply_relative_transform_to_point:
2500 * @self: A #ClutterActor
2501 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2502 * default #ClutterStage
2503 * @point: A point as #ClutterVertex
2504 * @vertex: (out caller-allocates): The translated #ClutterVertex
2506 * Transforms @point in coordinates relative to the actor into
2507 * ancestor-relative coordinates using the relevant transform
2508 * stack (i.e. scale, rotation, etc).
2510 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2511 * this case, the coordinates returned will be the coordinates on
2512 * the stage before the projection is applied. This is different from
2513 * the behaviour of clutter_actor_apply_transform_to_point().
2518 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2519 ClutterActor *ancestor,
2520 const ClutterVertex *point,
2521 ClutterVertex *vertex)
2526 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2527 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2528 g_return_if_fail (point != NULL);
2529 g_return_if_fail (vertex != NULL);
2534 if (ancestor == NULL)
2535 ancestor = _clutter_actor_get_stage_internal (self);
2537 if (ancestor == NULL)
2543 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2544 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2548 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2549 const ClutterVertex *vertices_in,
2550 ClutterVertex *vertices_out,
2553 ClutterActor *stage;
2554 CoglMatrix modelview;
2555 CoglMatrix projection;
2558 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2560 stage = _clutter_actor_get_stage_internal (self);
2562 /* We really can't do anything meaningful in this case so don't try
2563 * to do any transform */
2567 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2568 * that gets us to stage coordinates, we want to go all the way to eye
2570 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2572 /* Fetch the projection and viewport */
2573 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2574 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2580 _clutter_util_fully_transform_vertices (&modelview,
2591 * clutter_actor_apply_transform_to_point:
2592 * @self: A #ClutterActor
2593 * @point: A point as #ClutterVertex
2594 * @vertex: (out caller-allocates): The translated #ClutterVertex
2596 * Transforms @point in coordinates relative to the actor
2597 * into screen-relative coordinates with the current actor
2598 * transformation (i.e. scale, rotation, etc)
2603 clutter_actor_apply_transform_to_point (ClutterActor *self,
2604 const ClutterVertex *point,
2605 ClutterVertex *vertex)
2607 g_return_if_fail (point != NULL);
2608 g_return_if_fail (vertex != NULL);
2609 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2613 * _clutter_actor_get_relative_transformation_matrix:
2614 * @self: The actor whose coordinate space you want to transform from.
2615 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2616 * or %NULL if you want to transform all the way to eye coordinates.
2617 * @matrix: A #CoglMatrix to store the transformation
2619 * This gets a transformation @matrix that will transform coordinates from the
2620 * coordinate space of @self into the coordinate space of @ancestor.
2622 * For example if you need a matrix that can transform the local actor
2623 * coordinates of @self into stage coordinates you would pass the actor's stage
2624 * pointer as the @ancestor.
2626 * If you pass %NULL then the transformation will take you all the way through
2627 * to eye coordinates. This can be useful if you want to extract the entire
2628 * modelview transform that Clutter applies before applying the projection
2629 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2630 * using cogl_set_modelview_matrix() for example then you would want a matrix
2631 * that transforms into eye coordinates.
2633 * <note><para>This function explicitly initializes the given @matrix. If you just
2634 * want clutter to multiply a relative transformation with an existing matrix
2635 * you can use clutter_actor_apply_relative_transformation_matrix()
2636 * instead.</para></note>
2639 /* XXX: We should consider caching the stage relative modelview along with
2640 * the actor itself */
2642 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2643 ClutterActor *ancestor,
2646 cogl_matrix_init_identity (matrix);
2648 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2651 /* Project the given @box into stage window coordinates, writing the
2652 * transformed vertices to @verts[]. */
2654 _clutter_actor_transform_and_project_box (ClutterActor *self,
2655 const ClutterActorBox *box,
2656 ClutterVertex verts[])
2658 ClutterVertex box_vertices[4];
2660 box_vertices[0].x = box->x1;
2661 box_vertices[0].y = box->y1;
2662 box_vertices[0].z = 0;
2663 box_vertices[1].x = box->x2;
2664 box_vertices[1].y = box->y1;
2665 box_vertices[1].z = 0;
2666 box_vertices[2].x = box->x1;
2667 box_vertices[2].y = box->y2;
2668 box_vertices[2].z = 0;
2669 box_vertices[3].x = box->x2;
2670 box_vertices[3].y = box->y2;
2671 box_vertices[3].z = 0;
2674 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2678 * clutter_actor_get_allocation_vertices:
2679 * @self: A #ClutterActor
2680 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2681 * against, or %NULL to use the #ClutterStage
2682 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2683 * location for an array of 4 #ClutterVertex in which to store the result
2685 * Calculates the transformed coordinates of the four corners of the
2686 * actor in the plane of @ancestor. The returned vertices relate to
2687 * the #ClutterActorBox coordinates as follows:
2689 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2690 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2691 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2692 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2695 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2696 * this case, the coordinates returned will be the coordinates on
2697 * the stage before the projection is applied. This is different from
2698 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2703 clutter_actor_get_allocation_vertices (ClutterActor *self,
2704 ClutterActor *ancestor,
2705 ClutterVertex verts[])
2707 ClutterActorPrivate *priv;
2708 ClutterActorBox box;
2709 ClutterVertex vertices[4];
2710 CoglMatrix modelview;
2712 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2713 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2715 if (ancestor == NULL)
2716 ancestor = _clutter_actor_get_stage_internal (self);
2718 /* Fallback to a NOP transform if the actor isn't parented under a
2720 if (ancestor == NULL)
2725 /* if the actor needs to be allocated we force a relayout, so that
2726 * we will have valid values to use in the transformations */
2727 if (priv->needs_allocation)
2729 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2731 _clutter_stage_maybe_relayout (stage);
2734 box.x1 = box.y1 = 0;
2735 /* The result isn't really meaningful in this case but at
2736 * least try to do something *vaguely* reasonable... */
2737 clutter_actor_get_size (self, &box.x2, &box.y2);
2741 clutter_actor_get_allocation_box (self, &box);
2743 vertices[0].x = box.x1;
2744 vertices[0].y = box.y1;
2746 vertices[1].x = box.x2;
2747 vertices[1].y = box.y1;
2749 vertices[2].x = box.x1;
2750 vertices[2].y = box.y2;
2752 vertices[3].x = box.x2;
2753 vertices[3].y = box.y2;
2756 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2759 cogl_matrix_transform_points (&modelview,
2761 sizeof (ClutterVertex),
2763 sizeof (ClutterVertex),
2769 * clutter_actor_get_abs_allocation_vertices:
2770 * @self: A #ClutterActor
2771 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2772 * of 4 #ClutterVertex where to store the result.
2774 * Calculates the transformed screen coordinates of the four corners of
2775 * the actor; the returned vertices relate to the #ClutterActorBox
2776 * coordinates as follows:
2778 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2779 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2780 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2781 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2787 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2788 ClutterVertex verts[])
2790 ClutterActorPrivate *priv;
2791 ClutterActorBox actor_space_allocation;
2793 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2797 /* if the actor needs to be allocated we force a relayout, so that
2798 * the actor allocation box will be valid for
2799 * _clutter_actor_transform_and_project_box()
2801 if (priv->needs_allocation)
2803 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2804 /* There's nothing meaningful we can do now */
2808 _clutter_stage_maybe_relayout (stage);
2811 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2812 * own coordinate space... */
2813 actor_space_allocation.x1 = 0;
2814 actor_space_allocation.y1 = 0;
2815 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2816 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2817 _clutter_actor_transform_and_project_box (self,
2818 &actor_space_allocation,
2823 clutter_actor_real_apply_transform (ClutterActor *self,
2826 ClutterActorPrivate *priv = self->priv;
2828 if (!priv->transform_valid)
2830 CoglMatrix *transform = &priv->transform;
2831 const ClutterTransformInfo *info;
2833 info = _clutter_actor_get_transform_info_or_defaults (self);
2835 cogl_matrix_init_identity (transform);
2837 cogl_matrix_translate (transform,
2838 priv->allocation.x1,
2839 priv->allocation.y1,
2843 cogl_matrix_translate (transform, 0, 0, info->depth);
2846 * because the rotation involves translations, we must scale
2847 * before applying the rotations (if we apply the scale after
2848 * the rotations, the translations included in the rotation are
2849 * not scaled and so the entire object will move on the screen
2850 * as a result of rotating it).
2852 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2854 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2855 &info->scale_center,
2856 cogl_matrix_scale (transform,
2863 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2865 cogl_matrix_rotate (transform,
2870 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2872 cogl_matrix_rotate (transform,
2877 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2879 cogl_matrix_rotate (transform,
2883 if (!clutter_anchor_coord_is_zero (&info->anchor))
2887 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2888 cogl_matrix_translate (transform, -x, -y, -z);
2891 priv->transform_valid = TRUE;
2894 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2897 /* Applies the transforms associated with this actor to the given
2900 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2903 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2907 * clutter_actor_apply_relative_transformation_matrix:
2908 * @self: The actor whose coordinate space you want to transform from.
2909 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2910 * or %NULL if you want to transform all the way to eye coordinates.
2911 * @matrix: A #CoglMatrix to apply the transformation too.
2913 * This multiplies a transform with @matrix that will transform coordinates
2914 * from the coordinate space of @self into the coordinate space of @ancestor.
2916 * For example if you need a matrix that can transform the local actor
2917 * coordinates of @self into stage coordinates you would pass the actor's stage
2918 * pointer as the @ancestor.
2920 * If you pass %NULL then the transformation will take you all the way through
2921 * to eye coordinates. This can be useful if you want to extract the entire
2922 * modelview transform that Clutter applies before applying the projection
2923 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2924 * using cogl_set_modelview_matrix() for example then you would want a matrix
2925 * that transforms into eye coordinates.
2927 * <note>This function doesn't initialize the given @matrix, it simply
2928 * multiplies the requested transformation matrix with the existing contents of
2929 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2930 * before calling this function, or you can use
2931 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2934 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2935 ClutterActor *ancestor,
2938 ClutterActor *parent;
2940 /* Note we terminate before ever calling stage->apply_transform()
2941 * since that would conceptually be relative to the underlying
2942 * window OpenGL coordinates so we'd need a special @ancestor
2943 * value to represent the fake parent of the stage. */
2944 if (self == ancestor)
2947 parent = clutter_actor_get_parent (self);
2950 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2953 _clutter_actor_apply_modelview_transform (self, matrix);
2957 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2958 ClutterPaintVolume *pv,
2960 const CoglColor *color)
2962 static CoglPipeline *outline = NULL;
2963 CoglPrimitive *prim;
2964 ClutterVertex line_ends[12 * 2];
2967 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2968 /* XXX: at some point we'll query this from the stage but we can't
2969 * do that until the osx backend uses Cogl natively. */
2970 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2972 if (outline == NULL)
2973 outline = cogl_pipeline_new (ctx);
2975 _clutter_paint_volume_complete (pv);
2977 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2980 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2981 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2982 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2983 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2988 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2989 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2990 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2991 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2993 /* Lines connecting front face to back face */
2994 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2995 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2996 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2997 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3000 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3002 (CoglVertexP3 *)line_ends);
3004 cogl_pipeline_set_color (outline, color);
3005 cogl_framebuffer_draw_primitive (fb, outline, prim);
3006 cogl_object_unref (prim);
3010 PangoLayout *layout;
3011 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3012 pango_layout_set_text (layout, label, -1);
3013 cogl_pango_render_layout (layout,
3018 g_object_unref (layout);
3023 _clutter_actor_draw_paint_volume (ClutterActor *self)
3025 ClutterPaintVolume *pv;
3028 pv = _clutter_actor_get_paint_volume_mutable (self);
3031 gfloat width, height;
3032 ClutterPaintVolume fake_pv;
3034 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3035 _clutter_paint_volume_init_static (&fake_pv, stage);
3037 clutter_actor_get_size (self, &width, &height);
3038 clutter_paint_volume_set_width (&fake_pv, width);
3039 clutter_paint_volume_set_height (&fake_pv, height);
3041 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3042 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3043 _clutter_actor_get_debug_name (self),
3046 clutter_paint_volume_free (&fake_pv);
3050 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3051 _clutter_actor_draw_paint_volume_full (self, pv,
3052 _clutter_actor_get_debug_name (self),
3058 _clutter_actor_paint_cull_result (ClutterActor *self,
3060 ClutterCullResult result)
3062 ClutterPaintVolume *pv;
3067 if (result == CLUTTER_CULL_RESULT_IN)
3068 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3069 else if (result == CLUTTER_CULL_RESULT_OUT)
3070 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3072 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3075 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3077 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3078 _clutter_actor_draw_paint_volume_full (self, pv,
3079 _clutter_actor_get_debug_name (self),
3083 PangoLayout *layout;
3085 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3086 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3087 cogl_set_source_color (&color);
3089 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3090 pango_layout_set_text (layout, label, -1);
3091 cogl_pango_render_layout (layout,
3097 g_object_unref (layout);
3101 static int clone_paint_level = 0;
3104 _clutter_actor_push_clone_paint (void)
3106 clone_paint_level++;
3110 _clutter_actor_pop_clone_paint (void)
3112 clone_paint_level--;
3116 in_clone_paint (void)
3118 return clone_paint_level > 0;
3121 /* Returns TRUE if the actor can be ignored */
3122 /* FIXME: we should return a ClutterCullResult, and
3123 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3124 * means there's no point in trying to cull descendants of the current
3127 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3129 ClutterActorPrivate *priv = self->priv;
3130 ClutterActor *stage;
3131 const ClutterPlane *stage_clip;
3133 if (!priv->last_paint_volume_valid)
3135 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3136 "->last_paint_volume_valid == FALSE",
3137 _clutter_actor_get_debug_name (self));
3141 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3144 stage = _clutter_actor_get_stage_internal (self);
3145 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3146 if (G_UNLIKELY (!stage_clip))
3148 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3149 "No stage clip set",
3150 _clutter_actor_get_debug_name (self));
3154 if (cogl_get_draw_framebuffer () !=
3155 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3157 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3158 "Current framebuffer doesn't correspond to stage",
3159 _clutter_actor_get_debug_name (self));
3164 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3169 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3171 ClutterActorPrivate *priv = self->priv;
3172 const ClutterPaintVolume *pv;
3174 if (priv->last_paint_volume_valid)
3176 clutter_paint_volume_free (&priv->last_paint_volume);
3177 priv->last_paint_volume_valid = FALSE;
3180 pv = clutter_actor_get_paint_volume (self);
3183 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3184 "Actor failed to report a paint volume",
3185 _clutter_actor_get_debug_name (self));
3189 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3191 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3192 NULL); /* eye coordinates */
3194 priv->last_paint_volume_valid = TRUE;
3197 static inline gboolean
3198 actor_has_shader_data (ClutterActor *self)
3200 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3204 _clutter_actor_get_pick_id (ClutterActor *self)
3206 if (self->priv->pick_id < 0)
3209 return self->priv->pick_id;
3212 /* This is the same as clutter_actor_add_effect except that it doesn't
3213 queue a redraw and it doesn't notify on the effect property */
3215 _clutter_actor_add_effect_internal (ClutterActor *self,
3216 ClutterEffect *effect)
3218 ClutterActorPrivate *priv = self->priv;
3220 if (priv->effects == NULL)
3222 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3223 priv->effects->actor = self;
3226 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3229 /* This is the same as clutter_actor_remove_effect except that it doesn't
3230 queue a redraw and it doesn't notify on the effect property */
3232 _clutter_actor_remove_effect_internal (ClutterActor *self,
3233 ClutterEffect *effect)
3235 ClutterActorPrivate *priv = self->priv;
3237 if (priv->effects == NULL)
3240 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3242 if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3243 g_clear_object (&priv->effects);
3247 needs_flatten_effect (ClutterActor *self)
3249 ClutterActorPrivate *priv = self->priv;
3251 if (G_UNLIKELY (clutter_paint_debug_flags &
3252 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3255 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3257 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3259 if (clutter_actor_get_paint_opacity (self) < 255 &&
3260 clutter_actor_has_overlaps (self))
3268 add_or_remove_flatten_effect (ClutterActor *self)
3270 ClutterActorPrivate *priv = self->priv;
3272 /* Add or remove the flatten effect depending on the
3273 offscreen-redirect property. */
3274 if (needs_flatten_effect (self))
3276 if (priv->flatten_effect == NULL)
3278 ClutterActorMeta *actor_meta;
3281 priv->flatten_effect = _clutter_flatten_effect_new ();
3282 /* Keep a reference to the effect so that we can queue
3284 g_object_ref_sink (priv->flatten_effect);
3286 /* Set the priority of the effect to high so that it will
3287 always be applied to the actor first. It uses an internal
3288 priority so that it won't be visible to applications */
3289 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3290 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3291 _clutter_actor_meta_set_priority (actor_meta, priority);
3293 /* This will add the effect without queueing a redraw */
3294 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3299 if (priv->flatten_effect != NULL)
3301 /* Destroy the effect so that it will lose its fbo cache of
3303 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3304 g_clear_object (&priv->flatten_effect);
3310 clutter_actor_real_paint (ClutterActor *actor)
3312 ClutterActorPrivate *priv = actor->priv;
3315 for (iter = priv->first_child;
3317 iter = iter->priv->next_sibling)
3319 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3320 _clutter_actor_get_debug_name (iter),
3321 _clutter_actor_get_debug_name (actor),
3322 iter->priv->allocation.x1,
3323 iter->priv->allocation.y1,
3324 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3325 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3327 clutter_actor_paint (iter);
3332 clutter_actor_paint_node (ClutterActor *actor,
3333 ClutterPaintNode *root)
3335 ClutterActorPrivate *priv = actor->priv;
3340 if (priv->bg_color_set &&
3341 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3343 ClutterPaintNode *node;
3344 ClutterColor bg_color;
3345 ClutterActorBox box;
3349 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3350 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3352 bg_color = priv->bg_color;
3353 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3354 * priv->bg_color.alpha
3357 node = clutter_color_node_new (&bg_color);
3358 clutter_paint_node_set_name (node, "backgroundColor");
3359 clutter_paint_node_add_rectangle (node, &box);
3360 clutter_paint_node_add_child (root, node);
3361 clutter_paint_node_unref (node);
3364 if (priv->content != NULL)
3365 _clutter_content_paint_content (priv->content, actor, root);
3367 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3368 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3370 if (clutter_paint_node_get_n_children (root) == 0)
3373 #ifdef CLUTTER_ENABLE_DEBUG
3374 if (CLUTTER_HAS_DEBUG (PAINT))
3376 /* dump the tree only if we have one */
3377 _clutter_paint_node_dump_tree (root);
3379 #endif /* CLUTTER_ENABLE_DEBUG */
3381 _clutter_paint_node_paint (root);
3384 /* XXX: Uncomment this when we disable emitting the paint signal */
3385 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3392 * clutter_actor_paint:
3393 * @self: A #ClutterActor
3395 * Renders the actor to display.
3397 * This function should not be called directly by applications.
3398 * Call clutter_actor_queue_redraw() to queue paints, instead.
3400 * This function is context-aware, and will either cause a
3401 * regular paint or a pick paint.
3403 * This function will emit the #ClutterActor::paint signal or
3404 * the #ClutterActor::pick signal, depending on the context.
3406 * This function does not paint the actor if the actor is set to 0,
3407 * unless it is performing a pick paint.
3410 clutter_actor_paint (ClutterActor *self)
3412 ClutterActorPrivate *priv;
3413 ClutterPickMode pick_mode;
3414 gboolean clip_set = FALSE;
3415 gboolean shader_applied = FALSE;
3417 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3418 "Actor real-paint counter",
3419 "Increments each time any actor is painted",
3420 0 /* no application private data */);
3421 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3422 "Actor pick-paint counter",
3423 "Increments each time any actor is painted "
3425 0 /* no application private data */);
3427 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3429 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3434 pick_mode = _clutter_context_get_pick_mode ();
3436 if (pick_mode == CLUTTER_PICK_NONE)
3437 priv->propagated_one_redraw = FALSE;
3439 /* It's an important optimization that we consider painting of
3440 * actors with 0 opacity to be a NOP... */
3441 if (pick_mode == CLUTTER_PICK_NONE &&
3442 /* ignore top-levels, since they might be transparent */
3443 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3444 /* Use the override opacity if its been set */
3445 ((priv->opacity_override >= 0) ?
3446 priv->opacity_override : priv->opacity) == 0)
3449 /* if we aren't paintable (not in a toplevel with all
3450 * parents paintable) then do nothing.
3452 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3455 /* mark that we are in the paint process */
3456 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3460 if (priv->enable_model_view_transform)
3464 /* XXX: It could be better to cache the modelview with the actor
3465 * instead of progressively building up the transformations on
3466 * the matrix stack every time we paint. */
3467 cogl_get_modelview_matrix (&matrix);
3468 _clutter_actor_apply_modelview_transform (self, &matrix);
3470 #ifdef CLUTTER_ENABLE_DEBUG
3471 /* Catch when out-of-band transforms have been made by actors not as part
3472 * of an apply_transform vfunc... */
3473 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3475 CoglMatrix expected_matrix;
3477 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3480 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3482 GString *buf = g_string_sized_new (1024);
3483 ClutterActor *parent;
3486 while (parent != NULL)
3488 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3490 if (parent->priv->parent != NULL)
3491 g_string_append (buf, "->");
3493 parent = parent->priv->parent;
3496 g_warning ("Unexpected transform found when painting actor "
3497 "\"%s\". This will be caused by one of the actor's "
3498 "ancestors (%s) using the Cogl API directly to transform "
3499 "children instead of using ::apply_transform().",
3500 _clutter_actor_get_debug_name (self),
3503 g_string_free (buf, TRUE);
3506 #endif /* CLUTTER_ENABLE_DEBUG */
3508 cogl_set_modelview_matrix (&matrix);
3513 cogl_clip_push_rectangle (priv->clip.x,
3515 priv->clip.x + priv->clip.width,
3516 priv->clip.y + priv->clip.height);
3519 else if (priv->clip_to_allocation)
3521 gfloat width, height;
3523 width = priv->allocation.x2 - priv->allocation.x1;
3524 height = priv->allocation.y2 - priv->allocation.y1;
3526 cogl_clip_push_rectangle (0, 0, width, height);
3530 if (pick_mode == CLUTTER_PICK_NONE)
3532 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3534 /* We check whether we need to add the flatten effect before
3535 each paint so that we can avoid having a mechanism for
3536 applications to notify when the value of the
3537 has_overlaps virtual changes. */
3538 add_or_remove_flatten_effect (self);
3541 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3543 /* We save the current paint volume so that the next time the
3544 * actor queues a redraw we can constrain the redraw to just
3545 * cover the union of the new bounding box and the old.
3547 * We also fetch the current paint volume to perform culling so
3548 * we can avoid painting actors outside the current clip region.
3550 * If we are painting inside a clone, we should neither update
3551 * the paint volume or use it to cull painting, since the paint
3552 * box represents the location of the source actor on the
3555 * XXX: We are starting to do a lot of vertex transforms on
3556 * the CPU in a typical paint, so at some point we should
3557 * audit these and consider caching some things.
3559 * NB: We don't perform culling while picking at this point because
3560 * clutter-stage.c doesn't setup the clipping planes appropriately.
3562 * NB: We don't want to update the last-paint-volume during picking
3563 * because the last-paint-volume is used to determine the old screen
3564 * space location of an actor that has moved so we can know the
3565 * minimal region to redraw to clear an old view of the actor. If we
3566 * update this during picking then by the time we come around to
3567 * paint then the last-paint-volume would likely represent the new
3568 * actor position not the old.
3570 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3573 /* annoyingly gcc warns if uninitialized even though
3574 * the initialization is redundant :-( */
3575 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3577 if (G_LIKELY ((clutter_paint_debug_flags &
3578 (CLUTTER_DEBUG_DISABLE_CULLING |
3579 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3580 (CLUTTER_DEBUG_DISABLE_CULLING |
3581 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3582 _clutter_actor_update_last_paint_volume (self);
3584 success = cull_actor (self, &result);
3586 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3587 _clutter_actor_paint_cull_result (self, success, result);
3588 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3592 if (priv->effects == NULL)
3594 if (pick_mode == CLUTTER_PICK_NONE &&
3595 actor_has_shader_data (self))
3597 _clutter_actor_shader_pre_paint (self, FALSE);
3598 shader_applied = TRUE;
3601 priv->next_effect_to_paint = NULL;
3604 priv->next_effect_to_paint =
3605 _clutter_meta_group_peek_metas (priv->effects);
3607 clutter_actor_continue_paint (self);
3610 _clutter_actor_shader_post_paint (self);
3612 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3613 pick_mode == CLUTTER_PICK_NONE))
3614 _clutter_actor_draw_paint_volume (self);
3617 /* If we make it here then the actor has run through a complete
3618 paint run including all the effects so it's no longer dirty */
3619 if (pick_mode == CLUTTER_PICK_NONE)
3620 priv->is_dirty = FALSE;
3627 /* paint sequence complete */
3628 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3632 * clutter_actor_continue_paint:
3633 * @self: A #ClutterActor
3635 * Run the next stage of the paint sequence. This function should only
3636 * be called within the implementation of the ‘run’ virtual of a
3637 * #ClutterEffect. It will cause the run method of the next effect to
3638 * be applied, or it will paint the actual actor if the current effect
3639 * is the last effect in the chain.
3644 clutter_actor_continue_paint (ClutterActor *self)
3646 ClutterActorPrivate *priv;
3648 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3649 /* This should only be called from with in the ‘run’ implementation
3650 of a ClutterEffect */
3651 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3655 /* Skip any effects that are disabled */
3656 while (priv->next_effect_to_paint &&
3657 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3658 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3660 /* If this has come from the last effect then we'll just paint the
3662 if (priv->next_effect_to_paint == NULL)
3664 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3666 ClutterPaintNode *dummy;
3668 /* XXX - this will go away in 2.0, when we can get rid of this
3669 * stuff and switch to a pure retained render tree of PaintNodes
3670 * for the entire frame, starting from the Stage; the paint()
3671 * virtual function can then be called directly.
3673 dummy = _clutter_dummy_node_new (self);
3674 clutter_paint_node_set_name (dummy, "Root");
3676 /* XXX - for 1.12, we use the return value of paint_node() to
3677 * decide whether we should emit the ::paint signal.
3679 clutter_actor_paint_node (self, dummy);
3680 clutter_paint_node_unref (dummy);
3682 g_signal_emit (self, actor_signals[PAINT], 0);
3686 ClutterColor col = { 0, };
3688 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3690 /* Actor will then paint silhouette of itself in supplied
3691 * color. See clutter_stage_get_actor_at_pos() for where
3692 * picking is enabled.
3694 g_signal_emit (self, actor_signals[PICK], 0, &col);
3699 ClutterEffect *old_current_effect;
3700 ClutterEffectPaintFlags run_flags = 0;
3702 /* Cache the current effect so that we can put it back before
3704 old_current_effect = priv->current_effect;
3706 priv->current_effect = priv->next_effect_to_paint->data;
3707 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3709 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3713 /* If there's an effect queued with this redraw then all
3714 effects up to that one will be considered dirty. It
3715 is expected the queued effect will paint the cached
3716 image and not call clutter_actor_continue_paint again
3717 (although it should work ok if it does) */
3718 if (priv->effect_to_redraw == NULL ||
3719 priv->current_effect != priv->effect_to_redraw)
3720 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3723 _clutter_effect_paint (priv->current_effect, run_flags);
3727 /* We can't determine when an actor has been modified since
3728 its last pick so lets just assume it has always been
3730 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3732 _clutter_effect_pick (priv->current_effect, run_flags);
3735 priv->current_effect = old_current_effect;
3739 static ClutterActorTraverseVisitFlags
3740 invalidate_queue_redraw_entry (ClutterActor *self,
3744 ClutterActorPrivate *priv = self->priv;
3746 if (priv->queue_redraw_entry != NULL)
3748 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3749 priv->queue_redraw_entry = NULL;
3752 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3756 remove_child (ClutterActor *self,
3757 ClutterActor *child)
3759 ClutterActor *prev_sibling, *next_sibling;
3761 prev_sibling = child->priv->prev_sibling;
3762 next_sibling = child->priv->next_sibling;
3764 if (prev_sibling != NULL)
3765 prev_sibling->priv->next_sibling = next_sibling;
3767 if (next_sibling != NULL)
3768 next_sibling->priv->prev_sibling = prev_sibling;
3770 if (self->priv->first_child == child)
3771 self->priv->first_child = next_sibling;
3773 if (self->priv->last_child == child)
3774 self->priv->last_child = prev_sibling;
3776 child->priv->parent = NULL;
3777 child->priv->prev_sibling = NULL;
3778 child->priv->next_sibling = NULL;
3782 REMOVE_CHILD_DESTROY_META = 1 << 0,
3783 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3784 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3785 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3786 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3787 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3789 /* default flags for public API */
3790 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3791 REMOVE_CHILD_EMIT_PARENT_SET |
3792 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3793 REMOVE_CHILD_CHECK_STATE |
3794 REMOVE_CHILD_FLUSH_QUEUE |
3795 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3797 /* flags for legacy/deprecated API */
3798 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3799 REMOVE_CHILD_FLUSH_QUEUE |
3800 REMOVE_CHILD_EMIT_PARENT_SET |
3801 REMOVE_CHILD_NOTIFY_FIRST_LAST
3802 } ClutterActorRemoveChildFlags;
3805 * clutter_actor_remove_child_internal:
3806 * @self: a #ClutterActor
3807 * @child: the child of @self that has to be removed
3808 * @flags: control the removal operations
3810 * Removes @child from the list of children of @self.
3813 clutter_actor_remove_child_internal (ClutterActor *self,
3814 ClutterActor *child,
3815 ClutterActorRemoveChildFlags flags)
3817 ClutterActor *old_first, *old_last;
3818 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3819 gboolean flush_queue;
3820 gboolean notify_first_last;
3821 gboolean was_mapped;
3823 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3824 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3825 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3826 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3827 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3828 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3830 g_object_freeze_notify (G_OBJECT (self));
3833 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3837 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3839 /* we need to unrealize *before* we set parent_actor to NULL,
3840 * because in an unrealize method actors are dissociating from the
3841 * stage, which means they need to be able to
3842 * clutter_actor_get_stage().
3844 * yhis should unmap and unrealize, unless we're reparenting.
3846 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3853 /* We take this opportunity to invalidate any queue redraw entry
3854 * associated with the actor and descendants since we won't be able to
3855 * determine the appropriate stage after this.
3857 * we do this after we updated the mapped state because actors might
3858 * end up queueing redraws inside their mapped/unmapped virtual
3859 * functions, and if we invalidate the redraw entry we could end up
3860 * with an inconsistent state and weird memory corruption. see
3863 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3864 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3866 _clutter_actor_traverse (child,
3868 invalidate_queue_redraw_entry,
3873 old_first = self->priv->first_child;
3874 old_last = self->priv->last_child;
3876 remove_child (self, child);
3878 self->priv->n_children -= 1;
3880 self->priv->age += 1;
3882 /* clutter_actor_reparent() will emit ::parent-set for us */
3883 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3884 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3886 /* if the child was mapped then we need to relayout ourselves to account
3887 * for the removed child
3890 clutter_actor_queue_relayout (self);
3892 /* we need to emit the signal before dropping the reference */
3893 if (emit_actor_removed)
3894 g_signal_emit_by_name (self, "actor-removed", child);
3896 if (notify_first_last)
3898 if (old_first != self->priv->first_child)
3899 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3901 if (old_last != self->priv->last_child)
3902 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3905 g_object_thaw_notify (G_OBJECT (self));
3907 /* remove the reference we acquired in clutter_actor_add_child() */
3908 g_object_unref (child);
3911 static const ClutterTransformInfo default_transform_info = {
3912 0.0, { 0, }, /* rotation-x */
3913 0.0, { 0, }, /* rotation-y */
3914 0.0, { 0, }, /* rotation-z */
3916 1.0, 1.0, { 0, }, /* scale */
3918 { 0, }, /* anchor */
3924 * _clutter_actor_get_transform_info_or_defaults:
3925 * @self: a #ClutterActor
3927 * Retrieves the ClutterTransformInfo structure associated to an actor.
3929 * If the actor does not have a ClutterTransformInfo structure associated
3930 * to it, then the default structure will be returned.
3932 * This function should only be used for getters.
3934 * Return value: a const pointer to the ClutterTransformInfo structure
3936 const ClutterTransformInfo *
3937 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3939 ClutterTransformInfo *info;
3941 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3945 return &default_transform_info;
3949 clutter_transform_info_free (gpointer data)
3952 g_slice_free (ClutterTransformInfo, data);
3956 * _clutter_actor_get_transform_info:
3957 * @self: a #ClutterActor
3959 * Retrieves a pointer to the ClutterTransformInfo structure.
3961 * If the actor does not have a ClutterTransformInfo associated to it, one
3962 * will be created and initialized to the default values.
3964 * This function should be used for setters.
3966 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3969 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3972 ClutterTransformInfo *
3973 _clutter_actor_get_transform_info (ClutterActor *self)
3975 ClutterTransformInfo *info;
3977 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3980 info = g_slice_new (ClutterTransformInfo);
3982 *info = default_transform_info;
3984 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3986 clutter_transform_info_free);
3993 * clutter_actor_set_rotation_angle_internal:
3994 * @self: a #ClutterActor
3995 * @axis: the axis of the angle to change
3996 * @angle: the angle of rotation
3998 * Sets the rotation angle on the given axis without affecting the
3999 * rotation center point.
4002 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4003 ClutterRotateAxis axis,
4006 GObject *obj = G_OBJECT (self);
4007 ClutterTransformInfo *info;
4009 info = _clutter_actor_get_transform_info (self);
4011 g_object_freeze_notify (obj);
4015 case CLUTTER_X_AXIS:
4016 info->rx_angle = angle;
4017 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4020 case CLUTTER_Y_AXIS:
4021 info->ry_angle = angle;
4022 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4025 case CLUTTER_Z_AXIS:
4026 info->rz_angle = angle;
4027 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4031 self->priv->transform_valid = FALSE;
4033 g_object_thaw_notify (obj);
4035 clutter_actor_queue_redraw (self);
4039 clutter_actor_set_rotation_angle (ClutterActor *self,
4040 ClutterRotateAxis axis,
4043 const ClutterTransformInfo *info;
4044 const double *cur_angle_p = NULL;
4045 GParamSpec *pspec = NULL;
4047 info = _clutter_actor_get_transform_info_or_defaults (self);
4051 case CLUTTER_X_AXIS:
4052 cur_angle_p = &info->rx_angle;
4053 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4056 case CLUTTER_Y_AXIS:
4057 cur_angle_p = &info->ry_angle;
4058 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4061 case CLUTTER_Z_AXIS:
4062 cur_angle_p = &info->rz_angle;
4063 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4067 g_assert (pspec != NULL);
4068 g_assert (cur_angle_p != NULL);
4070 if (_clutter_actor_get_transition (self, pspec) == NULL)
4071 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4073 _clutter_actor_update_transition (self, pspec, angle);
4075 clutter_actor_queue_redraw (self);
4079 * clutter_actor_set_rotation_center_internal:
4080 * @self: a #ClutterActor
4081 * @axis: the axis of the center to change
4082 * @center: the coordinates of the rotation center
4084 * Sets the rotation center on the given axis without affecting the
4088 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4089 ClutterRotateAxis axis,
4090 const ClutterVertex *center)
4092 GObject *obj = G_OBJECT (self);
4093 ClutterTransformInfo *info;
4094 ClutterVertex v = { 0, 0, 0 };
4096 info = _clutter_actor_get_transform_info (self);
4101 g_object_freeze_notify (obj);
4105 case CLUTTER_X_AXIS:
4106 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4107 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4110 case CLUTTER_Y_AXIS:
4111 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4112 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4115 case CLUTTER_Z_AXIS:
4116 /* if the previously set rotation center was fractional, then
4117 * setting explicit coordinates will have to notify the
4118 * :rotation-center-z-gravity property as well
4120 if (info->rz_center.is_fractional)
4121 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4123 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4124 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4128 self->priv->transform_valid = FALSE;
4130 g_object_thaw_notify (obj);
4132 clutter_actor_queue_redraw (self);
4136 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4140 GObject *obj = G_OBJECT (self);
4141 ClutterTransformInfo *info;
4143 info = _clutter_actor_get_transform_info (self);
4145 if (pspec == obj_props[PROP_SCALE_X])
4146 info->scale_x = factor;
4148 info->scale_y = factor;
4150 self->priv->transform_valid = FALSE;
4151 clutter_actor_queue_redraw (self);
4152 g_object_notify_by_pspec (obj, pspec);
4156 clutter_actor_set_scale_factor (ClutterActor *self,
4157 ClutterRotateAxis axis,
4160 const ClutterTransformInfo *info;
4161 const double *scale_p = NULL;
4162 GParamSpec *pspec = NULL;
4164 info = _clutter_actor_get_transform_info_or_defaults (self);
4168 case CLUTTER_X_AXIS:
4169 pspec = obj_props[PROP_SCALE_X];
4170 scale_p = &info->scale_x;
4173 case CLUTTER_Y_AXIS:
4174 pspec = obj_props[PROP_SCALE_Y];
4175 scale_p = &info->scale_y;
4178 case CLUTTER_Z_AXIS:
4182 g_assert (pspec != NULL);
4183 g_assert (scale_p != NULL);
4185 if (_clutter_actor_get_transition (self, pspec) == NULL)
4186 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4188 _clutter_actor_update_transition (self, pspec, factor);
4190 clutter_actor_queue_redraw (self);
4194 clutter_actor_set_scale_center (ClutterActor *self,
4195 ClutterRotateAxis axis,
4198 GObject *obj = G_OBJECT (self);
4199 ClutterTransformInfo *info;
4200 gfloat center_x, center_y;
4202 info = _clutter_actor_get_transform_info (self);
4204 g_object_freeze_notify (obj);
4206 /* get the current scale center coordinates */
4207 clutter_anchor_coord_get_units (self, &info->scale_center,
4212 /* we need to notify this too, because setting explicit coordinates will
4213 * change the gravity as a side effect
4215 if (info->scale_center.is_fractional)
4216 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4220 case CLUTTER_X_AXIS:
4221 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4222 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4225 case CLUTTER_Y_AXIS:
4226 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4227 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4231 g_assert_not_reached ();
4234 self->priv->transform_valid = FALSE;
4236 clutter_actor_queue_redraw (self);
4238 g_object_thaw_notify (obj);
4242 clutter_actor_set_scale_gravity (ClutterActor *self,
4243 ClutterGravity gravity)
4245 ClutterTransformInfo *info;
4248 info = _clutter_actor_get_transform_info (self);
4249 obj = G_OBJECT (self);
4251 if (gravity == CLUTTER_GRAVITY_NONE)
4252 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4254 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4256 self->priv->transform_valid = FALSE;
4258 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4259 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4260 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4262 clutter_actor_queue_redraw (self);
4266 clutter_actor_set_anchor_coord (ClutterActor *self,
4267 ClutterRotateAxis axis,
4270 GObject *obj = G_OBJECT (self);
4271 ClutterTransformInfo *info;
4272 gfloat anchor_x, anchor_y;
4274 info = _clutter_actor_get_transform_info (self);
4276 g_object_freeze_notify (obj);
4278 clutter_anchor_coord_get_units (self, &info->anchor,
4283 if (info->anchor.is_fractional)
4284 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4288 case CLUTTER_X_AXIS:
4289 clutter_anchor_coord_set_units (&info->anchor,
4293 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4296 case CLUTTER_Y_AXIS:
4297 clutter_anchor_coord_set_units (&info->anchor,
4301 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4305 g_assert_not_reached ();
4308 self->priv->transform_valid = FALSE;
4310 clutter_actor_queue_redraw (self);
4312 g_object_thaw_notify (obj);
4316 clutter_actor_set_property (GObject *object,
4318 const GValue *value,
4321 ClutterActor *actor = CLUTTER_ACTOR (object);
4322 ClutterActorPrivate *priv = actor->priv;
4327 clutter_actor_set_x (actor, g_value_get_float (value));
4331 clutter_actor_set_y (actor, g_value_get_float (value));
4335 clutter_actor_set_width (actor, g_value_get_float (value));
4339 clutter_actor_set_height (actor, g_value_get_float (value));
4343 clutter_actor_set_x (actor, g_value_get_float (value));
4347 clutter_actor_set_y (actor, g_value_get_float (value));
4350 case PROP_FIXED_POSITION_SET:
4351 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4354 case PROP_MIN_WIDTH:
4355 clutter_actor_set_min_width (actor, g_value_get_float (value));
4358 case PROP_MIN_HEIGHT:
4359 clutter_actor_set_min_height (actor, g_value_get_float (value));
4362 case PROP_NATURAL_WIDTH:
4363 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4366 case PROP_NATURAL_HEIGHT:
4367 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4370 case PROP_MIN_WIDTH_SET:
4371 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4374 case PROP_MIN_HEIGHT_SET:
4375 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4378 case PROP_NATURAL_WIDTH_SET:
4379 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4382 case PROP_NATURAL_HEIGHT_SET:
4383 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4386 case PROP_REQUEST_MODE:
4387 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4391 clutter_actor_set_depth (actor, g_value_get_float (value));
4395 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4398 case PROP_OFFSCREEN_REDIRECT:
4399 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4403 clutter_actor_set_name (actor, g_value_get_string (value));
4407 if (g_value_get_boolean (value) == TRUE)
4408 clutter_actor_show (actor);
4410 clutter_actor_hide (actor);
4414 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4415 g_value_get_double (value));
4419 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4420 g_value_get_double (value));
4423 case PROP_SCALE_CENTER_X:
4424 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4425 g_value_get_float (value));
4428 case PROP_SCALE_CENTER_Y:
4429 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4430 g_value_get_float (value));
4433 case PROP_SCALE_GRAVITY:
4434 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4439 const ClutterGeometry *geom = g_value_get_boxed (value);
4441 clutter_actor_set_clip (actor,
4443 geom->width, geom->height);
4447 case PROP_CLIP_TO_ALLOCATION:
4448 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4452 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4455 case PROP_ROTATION_ANGLE_X:
4456 clutter_actor_set_rotation_angle (actor,
4458 g_value_get_double (value));
4461 case PROP_ROTATION_ANGLE_Y:
4462 clutter_actor_set_rotation_angle (actor,
4464 g_value_get_double (value));
4467 case PROP_ROTATION_ANGLE_Z:
4468 clutter_actor_set_rotation_angle (actor,
4470 g_value_get_double (value));
4473 case PROP_ROTATION_CENTER_X:
4474 clutter_actor_set_rotation_center_internal (actor,
4476 g_value_get_boxed (value));
4479 case PROP_ROTATION_CENTER_Y:
4480 clutter_actor_set_rotation_center_internal (actor,
4482 g_value_get_boxed (value));
4485 case PROP_ROTATION_CENTER_Z:
4486 clutter_actor_set_rotation_center_internal (actor,
4488 g_value_get_boxed (value));
4491 case PROP_ROTATION_CENTER_Z_GRAVITY:
4493 const ClutterTransformInfo *info;
4495 info = _clutter_actor_get_transform_info_or_defaults (actor);
4496 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4497 g_value_get_enum (value));
4502 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4503 g_value_get_float (value));
4507 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4508 g_value_get_float (value));
4511 case PROP_ANCHOR_GRAVITY:
4512 clutter_actor_set_anchor_point_from_gravity (actor,
4513 g_value_get_enum (value));
4516 case PROP_SHOW_ON_SET_PARENT:
4517 priv->show_on_set_parent = g_value_get_boolean (value);
4520 case PROP_TEXT_DIRECTION:
4521 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4525 clutter_actor_add_action (actor, g_value_get_object (value));
4528 case PROP_CONSTRAINTS:
4529 clutter_actor_add_constraint (actor, g_value_get_object (value));
4533 clutter_actor_add_effect (actor, g_value_get_object (value));
4536 case PROP_LAYOUT_MANAGER:
4537 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4541 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4545 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4548 case PROP_MARGIN_TOP:
4549 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4552 case PROP_MARGIN_BOTTOM:
4553 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4556 case PROP_MARGIN_LEFT:
4557 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4560 case PROP_MARGIN_RIGHT:
4561 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4564 case PROP_BACKGROUND_COLOR:
4565 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4569 clutter_actor_set_content (actor, g_value_get_object (value));
4572 case PROP_CONTENT_GRAVITY:
4573 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4576 case PROP_MINIFICATION_FILTER:
4577 clutter_actor_set_content_scaling_filters (actor,
4578 g_value_get_enum (value),
4579 actor->priv->mag_filter);
4582 case PROP_MAGNIFICATION_FILTER:
4583 clutter_actor_set_content_scaling_filters (actor,
4584 actor->priv->min_filter,
4585 g_value_get_enum (value));
4589 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4595 clutter_actor_get_property (GObject *object,
4600 ClutterActor *actor = CLUTTER_ACTOR (object);
4601 ClutterActorPrivate *priv = actor->priv;
4606 g_value_set_float (value, clutter_actor_get_x (actor));
4610 g_value_set_float (value, clutter_actor_get_y (actor));
4614 g_value_set_float (value, clutter_actor_get_width (actor));
4618 g_value_set_float (value, clutter_actor_get_height (actor));
4623 const ClutterLayoutInfo *info;
4625 info = _clutter_actor_get_layout_info_or_defaults (actor);
4626 g_value_set_float (value, info->fixed_x);
4632 const ClutterLayoutInfo *info;
4634 info = _clutter_actor_get_layout_info_or_defaults (actor);
4635 g_value_set_float (value, info->fixed_y);
4639 case PROP_FIXED_POSITION_SET:
4640 g_value_set_boolean (value, priv->position_set);
4643 case PROP_MIN_WIDTH:
4645 const ClutterLayoutInfo *info;
4647 info = _clutter_actor_get_layout_info_or_defaults (actor);
4648 g_value_set_float (value, info->min_width);
4652 case PROP_MIN_HEIGHT:
4654 const ClutterLayoutInfo *info;
4656 info = _clutter_actor_get_layout_info_or_defaults (actor);
4657 g_value_set_float (value, info->min_height);
4661 case PROP_NATURAL_WIDTH:
4663 const ClutterLayoutInfo *info;
4665 info = _clutter_actor_get_layout_info_or_defaults (actor);
4666 g_value_set_float (value, info->natural_width);
4670 case PROP_NATURAL_HEIGHT:
4672 const ClutterLayoutInfo *info;
4674 info = _clutter_actor_get_layout_info_or_defaults (actor);
4675 g_value_set_float (value, info->natural_height);
4679 case PROP_MIN_WIDTH_SET:
4680 g_value_set_boolean (value, priv->min_width_set);
4683 case PROP_MIN_HEIGHT_SET:
4684 g_value_set_boolean (value, priv->min_height_set);
4687 case PROP_NATURAL_WIDTH_SET:
4688 g_value_set_boolean (value, priv->natural_width_set);
4691 case PROP_NATURAL_HEIGHT_SET:
4692 g_value_set_boolean (value, priv->natural_height_set);
4695 case PROP_REQUEST_MODE:
4696 g_value_set_enum (value, priv->request_mode);
4699 case PROP_ALLOCATION:
4700 g_value_set_boxed (value, &priv->allocation);
4704 g_value_set_float (value, clutter_actor_get_depth (actor));
4708 g_value_set_uint (value, priv->opacity);
4711 case PROP_OFFSCREEN_REDIRECT:
4712 g_value_set_enum (value, priv->offscreen_redirect);
4716 g_value_set_string (value, priv->name);
4720 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4724 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4728 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4732 g_value_set_boolean (value, priv->has_clip);
4737 ClutterGeometry clip;
4739 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4740 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4741 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4742 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4744 g_value_set_boxed (value, &clip);
4748 case PROP_CLIP_TO_ALLOCATION:
4749 g_value_set_boolean (value, priv->clip_to_allocation);
4754 const ClutterTransformInfo *info;
4756 info = _clutter_actor_get_transform_info_or_defaults (actor);
4757 g_value_set_double (value, info->scale_x);
4763 const ClutterTransformInfo *info;
4765 info = _clutter_actor_get_transform_info_or_defaults (actor);
4766 g_value_set_double (value, info->scale_y);
4770 case PROP_SCALE_CENTER_X:
4774 clutter_actor_get_scale_center (actor, ¢er, NULL);
4776 g_value_set_float (value, center);
4780 case PROP_SCALE_CENTER_Y:
4784 clutter_actor_get_scale_center (actor, NULL, ¢er);
4786 g_value_set_float (value, center);
4790 case PROP_SCALE_GRAVITY:
4791 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4795 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4798 case PROP_ROTATION_ANGLE_X:
4800 const ClutterTransformInfo *info;
4802 info = _clutter_actor_get_transform_info_or_defaults (actor);
4803 g_value_set_double (value, info->rx_angle);
4807 case PROP_ROTATION_ANGLE_Y:
4809 const ClutterTransformInfo *info;
4811 info = _clutter_actor_get_transform_info_or_defaults (actor);
4812 g_value_set_double (value, info->ry_angle);
4816 case PROP_ROTATION_ANGLE_Z:
4818 const ClutterTransformInfo *info;
4820 info = _clutter_actor_get_transform_info_or_defaults (actor);
4821 g_value_set_double (value, info->rz_angle);
4825 case PROP_ROTATION_CENTER_X:
4827 ClutterVertex center;
4829 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4834 g_value_set_boxed (value, ¢er);
4838 case PROP_ROTATION_CENTER_Y:
4840 ClutterVertex center;
4842 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4847 g_value_set_boxed (value, ¢er);
4851 case PROP_ROTATION_CENTER_Z:
4853 ClutterVertex center;
4855 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4860 g_value_set_boxed (value, ¢er);
4864 case PROP_ROTATION_CENTER_Z_GRAVITY:
4865 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4870 const ClutterTransformInfo *info;
4873 info = _clutter_actor_get_transform_info_or_defaults (actor);
4874 clutter_anchor_coord_get_units (actor, &info->anchor,
4878 g_value_set_float (value, anchor_x);
4884 const ClutterTransformInfo *info;
4887 info = _clutter_actor_get_transform_info_or_defaults (actor);
4888 clutter_anchor_coord_get_units (actor, &info->anchor,
4892 g_value_set_float (value, anchor_y);
4896 case PROP_ANCHOR_GRAVITY:
4897 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4900 case PROP_SHOW_ON_SET_PARENT:
4901 g_value_set_boolean (value, priv->show_on_set_parent);
4904 case PROP_TEXT_DIRECTION:
4905 g_value_set_enum (value, priv->text_direction);
4908 case PROP_HAS_POINTER:
4909 g_value_set_boolean (value, priv->has_pointer);
4912 case PROP_LAYOUT_MANAGER:
4913 g_value_set_object (value, priv->layout_manager);
4918 const ClutterLayoutInfo *info;
4920 info = _clutter_actor_get_layout_info_or_defaults (actor);
4921 g_value_set_enum (value, info->x_align);
4927 const ClutterLayoutInfo *info;
4929 info = _clutter_actor_get_layout_info_or_defaults (actor);
4930 g_value_set_enum (value, info->y_align);
4934 case PROP_MARGIN_TOP:
4936 const ClutterLayoutInfo *info;
4938 info = _clutter_actor_get_layout_info_or_defaults (actor);
4939 g_value_set_float (value, info->margin.top);
4943 case PROP_MARGIN_BOTTOM:
4945 const ClutterLayoutInfo *info;
4947 info = _clutter_actor_get_layout_info_or_defaults (actor);
4948 g_value_set_float (value, info->margin.bottom);
4952 case PROP_MARGIN_LEFT:
4954 const ClutterLayoutInfo *info;
4956 info = _clutter_actor_get_layout_info_or_defaults (actor);
4957 g_value_set_float (value, info->margin.left);
4961 case PROP_MARGIN_RIGHT:
4963 const ClutterLayoutInfo *info;
4965 info = _clutter_actor_get_layout_info_or_defaults (actor);
4966 g_value_set_float (value, info->margin.right);
4970 case PROP_BACKGROUND_COLOR_SET:
4971 g_value_set_boolean (value, priv->bg_color_set);
4974 case PROP_BACKGROUND_COLOR:
4975 g_value_set_boxed (value, &priv->bg_color);
4978 case PROP_FIRST_CHILD:
4979 g_value_set_object (value, priv->first_child);
4982 case PROP_LAST_CHILD:
4983 g_value_set_object (value, priv->last_child);
4987 g_value_set_object (value, priv->content);
4990 case PROP_CONTENT_GRAVITY:
4991 g_value_set_enum (value, priv->content_gravity);
4994 case PROP_CONTENT_BOX:
4996 ClutterActorBox box = { 0, };
4998 clutter_actor_get_content_box (actor, &box);
4999 g_value_set_boxed (value, &box);
5003 case PROP_MINIFICATION_FILTER:
5004 g_value_set_enum (value, priv->min_filter);
5007 case PROP_MAGNIFICATION_FILTER:
5008 g_value_set_enum (value, priv->mag_filter);
5012 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5018 clutter_actor_dispose (GObject *object)
5020 ClutterActor *self = CLUTTER_ACTOR (object);
5021 ClutterActorPrivate *priv = self->priv;
5023 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5025 g_type_name (G_OBJECT_TYPE (self)),
5028 g_signal_emit (self, actor_signals[DESTROY], 0);
5030 /* avoid recursing when called from clutter_actor_destroy() */
5031 if (priv->parent != NULL)
5033 ClutterActor *parent = priv->parent;
5035 /* go through the Container implementation unless this
5036 * is an internal child and has been marked as such.
5038 * removing the actor from its parent will reset the
5039 * realized and mapped states.
5041 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5042 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5044 clutter_actor_remove_child_internal (parent, self,
5045 REMOVE_CHILD_LEGACY_FLAGS);
5048 /* parent must be gone at this point */
5049 g_assert (priv->parent == NULL);
5051 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5053 /* can't be mapped or realized with no parent */
5054 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5055 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5058 g_clear_object (&priv->pango_context);
5059 g_clear_object (&priv->actions);
5060 g_clear_object (&priv->constraints);
5061 g_clear_object (&priv->effects);
5062 g_clear_object (&priv->flatten_effect);
5064 if (priv->layout_manager != NULL)
5066 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5067 g_clear_object (&priv->layout_manager);
5070 if (priv->content != NULL)
5072 _clutter_content_detached (priv->content, self);
5073 g_clear_object (&priv->content);
5076 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5080 clutter_actor_finalize (GObject *object)
5082 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5084 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5085 priv->name != NULL ? priv->name : "<none>",
5087 g_type_name (G_OBJECT_TYPE (object)));
5089 _clutter_context_release_id (priv->id);
5091 g_free (priv->name);
5093 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5098 * clutter_actor_get_accessible:
5099 * @self: a #ClutterActor
5101 * Returns the accessible object that describes the actor to an
5102 * assistive technology.
5104 * If no class-specific #AtkObject implementation is available for the
5105 * actor instance in question, it will inherit an #AtkObject
5106 * implementation from the first ancestor class for which such an
5107 * implementation is defined.
5109 * The documentation of the <ulink
5110 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5111 * library contains more information about accessible objects and
5114 * Returns: (transfer none): the #AtkObject associated with @actor
5117 clutter_actor_get_accessible (ClutterActor *self)
5119 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5121 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5125 clutter_actor_real_get_accessible (ClutterActor *actor)
5127 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5131 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5133 AtkObject *accessible;
5135 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5136 if (accessible != NULL)
5137 g_object_ref (accessible);
5143 atk_implementor_iface_init (AtkImplementorIface *iface)
5145 iface->ref_accessible = _clutter_actor_ref_accessible;
5149 clutter_actor_update_default_paint_volume (ClutterActor *self,
5150 ClutterPaintVolume *volume)
5152 ClutterActorPrivate *priv = self->priv;
5153 gboolean res = TRUE;
5155 /* we start from the allocation */
5156 clutter_paint_volume_set_width (volume,
5157 priv->allocation.x2 - priv->allocation.x1);
5158 clutter_paint_volume_set_height (volume,
5159 priv->allocation.y2 - priv->allocation.y1);
5161 /* if the actor has a clip set then we have a pretty definite
5162 * size for the paint volume: the actor cannot possibly paint
5163 * outside the clip region.
5165 if (priv->clip_to_allocation)
5167 /* the allocation has already been set, so we just flip the
5174 ClutterActor *child;
5176 if (priv->has_clip &&
5177 priv->clip.width >= 0 &&
5178 priv->clip.height >= 0)
5180 ClutterVertex origin;
5182 origin.x = priv->clip.x;
5183 origin.y = priv->clip.y;
5186 clutter_paint_volume_set_origin (volume, &origin);
5187 clutter_paint_volume_set_width (volume, priv->clip.width);
5188 clutter_paint_volume_set_height (volume, priv->clip.height);
5193 /* if we don't have children we just bail out here... */
5194 if (priv->n_children == 0)
5197 /* ...but if we have children then we ask for their paint volume in
5198 * our coordinates. if any of our children replies that it doesn't
5199 * have a paint volume, we bail out
5201 for (child = priv->first_child;
5203 child = child->priv->next_sibling)
5205 const ClutterPaintVolume *child_volume;
5207 if (!CLUTTER_ACTOR_IS_MAPPED (child))
5210 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5211 if (child_volume == NULL)
5217 clutter_paint_volume_union (volume, child_volume);
5227 clutter_actor_real_get_paint_volume (ClutterActor *self,
5228 ClutterPaintVolume *volume)
5230 ClutterActorClass *klass;
5233 klass = CLUTTER_ACTOR_GET_CLASS (self);
5235 /* XXX - this thoroughly sucks, but we don't want to penalize users
5236 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5237 * redraw. This should go away in 2.0.
5239 if (klass->paint == clutter_actor_real_paint &&
5240 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5246 /* this is the default return value: we cannot know if a class
5247 * is going to paint outside its allocation, so we take the
5248 * conservative approach.
5253 /* update_default_paint_volume() should only fail if one of the children
5254 * reported an invalid, or no, paint volume
5256 if (!clutter_actor_update_default_paint_volume (self, volume))
5263 * clutter_actor_get_default_paint_volume:
5264 * @self: a #ClutterActor
5266 * Retrieves the default paint volume for @self.
5268 * This function provides the same #ClutterPaintVolume that would be
5269 * computed by the default implementation inside #ClutterActor of the
5270 * #ClutterActorClass.get_paint_volume() virtual function.
5272 * This function should only be used by #ClutterActor subclasses that
5273 * cannot chain up to the parent implementation when computing their
5276 * Return value: (transfer none): a pointer to the default
5277 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5278 * the actor could not compute a valid paint volume. The returned value
5279 * is not guaranteed to be stable across multiple frames, so if you
5280 * want to retain it, you will need to copy it using
5281 * clutter_paint_volume_copy().
5285 const ClutterPaintVolume *
5286 clutter_actor_get_default_paint_volume (ClutterActor *self)
5288 ClutterPaintVolume volume;
5289 ClutterPaintVolume *res;
5291 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5294 _clutter_paint_volume_init_static (&volume, self);
5295 if (clutter_actor_update_default_paint_volume (self, &volume))
5297 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5301 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5302 _clutter_paint_volume_copy_static (&volume, res);
5306 clutter_paint_volume_free (&volume);
5312 clutter_actor_real_has_overlaps (ClutterActor *self)
5314 /* By default we'll assume that all actors need an offscreen redirect to get
5315 * the correct opacity. Actors such as ClutterTexture that would never need
5316 * an offscreen redirect can override this to return FALSE. */
5321 clutter_actor_real_destroy (ClutterActor *actor)
5323 ClutterActorIter iter;
5325 g_object_freeze_notify (G_OBJECT (actor));
5327 clutter_actor_iter_init (&iter, actor);
5328 while (clutter_actor_iter_next (&iter, NULL))
5329 clutter_actor_iter_destroy (&iter);
5331 g_object_thaw_notify (G_OBJECT (actor));
5335 clutter_actor_constructor (GType gtype,
5337 GObjectConstructParam *props)
5339 GObjectClass *gobject_class;
5343 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5344 retval = gobject_class->constructor (gtype, n_props, props);
5345 self = CLUTTER_ACTOR (retval);
5347 if (self->priv->layout_manager == NULL)
5349 ClutterLayoutManager *default_layout;
5351 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5353 default_layout = clutter_fixed_layout_new ();
5354 clutter_actor_set_layout_manager (self, default_layout);
5361 clutter_actor_class_init (ClutterActorClass *klass)
5363 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5365 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5366 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5367 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5368 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5370 object_class->constructor = clutter_actor_constructor;
5371 object_class->set_property = clutter_actor_set_property;
5372 object_class->get_property = clutter_actor_get_property;
5373 object_class->dispose = clutter_actor_dispose;
5374 object_class->finalize = clutter_actor_finalize;
5376 klass->show = clutter_actor_real_show;
5377 klass->show_all = clutter_actor_show;
5378 klass->hide = clutter_actor_real_hide;
5379 klass->hide_all = clutter_actor_hide;
5380 klass->map = clutter_actor_real_map;
5381 klass->unmap = clutter_actor_real_unmap;
5382 klass->unrealize = clutter_actor_real_unrealize;
5383 klass->pick = clutter_actor_real_pick;
5384 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5385 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5386 klass->allocate = clutter_actor_real_allocate;
5387 klass->queue_redraw = clutter_actor_real_queue_redraw;
5388 klass->queue_relayout = clutter_actor_real_queue_relayout;
5389 klass->apply_transform = clutter_actor_real_apply_transform;
5390 klass->get_accessible = clutter_actor_real_get_accessible;
5391 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5392 klass->has_overlaps = clutter_actor_real_has_overlaps;
5393 klass->paint = clutter_actor_real_paint;
5394 klass->destroy = clutter_actor_real_destroy;
5396 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5401 * X coordinate of the actor in pixels. If written, forces a fixed
5402 * position for the actor. If read, returns the fixed position if any,
5403 * otherwise the allocation if available, otherwise 0.
5405 * The #ClutterActor:x property is animatable.
5408 g_param_spec_float ("x",
5410 P_("X coordinate of the actor"),
5411 -G_MAXFLOAT, G_MAXFLOAT,
5414 G_PARAM_STATIC_STRINGS |
5415 CLUTTER_PARAM_ANIMATABLE);
5420 * Y coordinate of the actor in pixels. If written, forces a fixed
5421 * position for the actor. If read, returns the fixed position if
5422 * any, otherwise the allocation if available, otherwise 0.
5424 * The #ClutterActor:y property is animatable.
5427 g_param_spec_float ("y",
5429 P_("Y coordinate of the actor"),
5430 -G_MAXFLOAT, G_MAXFLOAT,
5433 G_PARAM_STATIC_STRINGS |
5434 CLUTTER_PARAM_ANIMATABLE);
5437 * ClutterActor:width:
5439 * Width of the actor (in pixels). If written, forces the minimum and
5440 * natural size request of the actor to the given width. If read, returns
5441 * the allocated width if available, otherwise the width request.
5443 * The #ClutterActor:width property is animatable.
5445 obj_props[PROP_WIDTH] =
5446 g_param_spec_float ("width",
5448 P_("Width of the actor"),
5452 G_PARAM_STATIC_STRINGS |
5453 CLUTTER_PARAM_ANIMATABLE);
5456 * ClutterActor:height:
5458 * Height of the actor (in pixels). If written, forces the minimum and
5459 * natural size request of the actor to the given height. If read, returns
5460 * the allocated height if available, otherwise the height request.
5462 * The #ClutterActor:height property is animatable.
5464 obj_props[PROP_HEIGHT] =
5465 g_param_spec_float ("height",
5467 P_("Height of the actor"),
5471 G_PARAM_STATIC_STRINGS |
5472 CLUTTER_PARAM_ANIMATABLE);
5475 * ClutterActor:fixed-x:
5477 * The fixed X position of the actor in pixels.
5479 * Writing this property sets #ClutterActor:fixed-position-set
5480 * property as well, as a side effect
5484 obj_props[PROP_FIXED_X] =
5485 g_param_spec_float ("fixed-x",
5487 P_("Forced X position of the actor"),
5488 -G_MAXFLOAT, G_MAXFLOAT,
5490 CLUTTER_PARAM_READWRITE);
5493 * ClutterActor:fixed-y:
5495 * The fixed Y position of the actor in pixels.
5497 * Writing this property sets the #ClutterActor:fixed-position-set
5498 * property as well, as a side effect
5502 obj_props[PROP_FIXED_Y] =
5503 g_param_spec_float ("fixed-y",
5505 P_("Forced Y position of the actor"),
5506 -G_MAXFLOAT, G_MAXFLOAT,
5508 CLUTTER_PARAM_READWRITE);
5511 * ClutterActor:fixed-position-set:
5513 * This flag controls whether the #ClutterActor:fixed-x and
5514 * #ClutterActor:fixed-y properties are used
5518 obj_props[PROP_FIXED_POSITION_SET] =
5519 g_param_spec_boolean ("fixed-position-set",
5520 P_("Fixed position set"),
5521 P_("Whether to use fixed positioning for the actor"),
5523 CLUTTER_PARAM_READWRITE);
5526 * ClutterActor:min-width:
5528 * A forced minimum width request for the actor, in pixels
5530 * Writing this property sets the #ClutterActor:min-width-set property
5531 * as well, as a side effect.
5533 *This property overrides the usual width request of the actor.
5537 obj_props[PROP_MIN_WIDTH] =
5538 g_param_spec_float ("min-width",
5540 P_("Forced minimum width request for the actor"),
5543 CLUTTER_PARAM_READWRITE);
5546 * ClutterActor:min-height:
5548 * A forced minimum height request for the actor, in pixels
5550 * Writing this property sets the #ClutterActor:min-height-set property
5551 * as well, as a side effect. This property overrides the usual height
5552 * request of the actor.
5556 obj_props[PROP_MIN_HEIGHT] =
5557 g_param_spec_float ("min-height",
5559 P_("Forced minimum height request for the actor"),
5562 CLUTTER_PARAM_READWRITE);
5565 * ClutterActor:natural-width:
5567 * A forced natural width request for the actor, in pixels
5569 * Writing this property sets the #ClutterActor:natural-width-set
5570 * property as well, as a side effect. This property overrides the
5571 * usual width request of the actor
5575 obj_props[PROP_NATURAL_WIDTH] =
5576 g_param_spec_float ("natural-width",
5577 P_("Natural Width"),
5578 P_("Forced natural width request for the actor"),
5581 CLUTTER_PARAM_READWRITE);
5584 * ClutterActor:natural-height:
5586 * A forced natural height request for the actor, in pixels
5588 * Writing this property sets the #ClutterActor:natural-height-set
5589 * property as well, as a side effect. This property overrides the
5590 * usual height request of the actor
5594 obj_props[PROP_NATURAL_HEIGHT] =
5595 g_param_spec_float ("natural-height",
5596 P_("Natural Height"),
5597 P_("Forced natural height request for the actor"),
5600 CLUTTER_PARAM_READWRITE);
5603 * ClutterActor:min-width-set:
5605 * This flag controls whether the #ClutterActor:min-width property
5610 obj_props[PROP_MIN_WIDTH_SET] =
5611 g_param_spec_boolean ("min-width-set",
5612 P_("Minimum width set"),
5613 P_("Whether to use the min-width property"),
5615 CLUTTER_PARAM_READWRITE);
5618 * ClutterActor:min-height-set:
5620 * This flag controls whether the #ClutterActor:min-height property
5625 obj_props[PROP_MIN_HEIGHT_SET] =
5626 g_param_spec_boolean ("min-height-set",
5627 P_("Minimum height set"),
5628 P_("Whether to use the min-height property"),
5630 CLUTTER_PARAM_READWRITE);
5633 * ClutterActor:natural-width-set:
5635 * This flag controls whether the #ClutterActor:natural-width property
5640 obj_props[PROP_NATURAL_WIDTH_SET] =
5641 g_param_spec_boolean ("natural-width-set",
5642 P_("Natural width set"),
5643 P_("Whether to use the natural-width property"),
5645 CLUTTER_PARAM_READWRITE);
5648 * ClutterActor:natural-height-set:
5650 * This flag controls whether the #ClutterActor:natural-height property
5655 obj_props[PROP_NATURAL_HEIGHT_SET] =
5656 g_param_spec_boolean ("natural-height-set",
5657 P_("Natural height set"),
5658 P_("Whether to use the natural-height property"),
5660 CLUTTER_PARAM_READWRITE);
5663 * ClutterActor:allocation:
5665 * The allocation for the actor, in pixels
5667 * This is property is read-only, but you might monitor it to know when an
5668 * actor moves or resizes
5672 obj_props[PROP_ALLOCATION] =
5673 g_param_spec_boxed ("allocation",
5675 P_("The actor's allocation"),
5676 CLUTTER_TYPE_ACTOR_BOX,
5677 CLUTTER_PARAM_READABLE);
5680 * ClutterActor:request-mode:
5682 * Request mode for the #ClutterActor. The request mode determines the
5683 * type of geometry management used by the actor, either height for width
5684 * (the default) or width for height.
5686 * For actors implementing height for width, the parent container should get
5687 * the preferred width first, and then the preferred height for that width.
5689 * For actors implementing width for height, the parent container should get
5690 * the preferred height first, and then the preferred width for that height.
5695 * ClutterRequestMode mode;
5696 * gfloat natural_width, min_width;
5697 * gfloat natural_height, min_height;
5699 * mode = clutter_actor_get_request_mode (child);
5700 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5702 * clutter_actor_get_preferred_width (child, -1,
5704 * &natural_width);
5705 * clutter_actor_get_preferred_height (child, natural_width,
5707 * &natural_height);
5711 * clutter_actor_get_preferred_height (child, -1,
5713 * &natural_height);
5714 * clutter_actor_get_preferred_width (child, natural_height,
5716 * &natural_width);
5720 * will retrieve the minimum and natural width and height depending on the
5721 * preferred request mode of the #ClutterActor "child".
5723 * The clutter_actor_get_preferred_size() function will implement this
5728 obj_props[PROP_REQUEST_MODE] =
5729 g_param_spec_enum ("request-mode",
5731 P_("The actor's request mode"),
5732 CLUTTER_TYPE_REQUEST_MODE,
5733 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5734 CLUTTER_PARAM_READWRITE);
5737 * ClutterActor:depth:
5739 * The position of the actor on the Z axis.
5741 * The #ClutterActor:depth property is relative to the parent's
5744 * The #ClutterActor:depth property is animatable.
5748 obj_props[PROP_DEPTH] =
5749 g_param_spec_float ("depth",
5751 P_("Position on the Z axis"),
5752 -G_MAXFLOAT, G_MAXFLOAT,
5755 G_PARAM_STATIC_STRINGS |
5756 CLUTTER_PARAM_ANIMATABLE);
5759 * ClutterActor:opacity:
5761 * Opacity of an actor, between 0 (fully transparent) and
5762 * 255 (fully opaque)
5764 * The #ClutterActor:opacity property is animatable.
5766 obj_props[PROP_OPACITY] =
5767 g_param_spec_uint ("opacity",
5769 P_("Opacity of an actor"),
5773 G_PARAM_STATIC_STRINGS |
5774 CLUTTER_PARAM_ANIMATABLE);
5777 * ClutterActor:offscreen-redirect:
5779 * Determines the conditions in which the actor will be redirected
5780 * to an offscreen framebuffer while being painted. For example this
5781 * can be used to cache an actor in a framebuffer or for improved
5782 * handling of transparent actors. See
5783 * clutter_actor_set_offscreen_redirect() for details.
5787 obj_props[PROP_OFFSCREEN_REDIRECT] =
5788 g_param_spec_flags ("offscreen-redirect",
5789 P_("Offscreen redirect"),
5790 P_("Flags controlling when to flatten the actor into a single image"),
5791 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5793 CLUTTER_PARAM_READWRITE);
5796 * ClutterActor:visible:
5798 * Whether the actor is set to be visible or not
5800 * See also #ClutterActor:mapped
5802 obj_props[PROP_VISIBLE] =
5803 g_param_spec_boolean ("visible",
5805 P_("Whether the actor is visible or not"),
5807 CLUTTER_PARAM_READWRITE);
5810 * ClutterActor:mapped:
5812 * Whether the actor is mapped (will be painted when the stage
5813 * to which it belongs is mapped)
5817 obj_props[PROP_MAPPED] =
5818 g_param_spec_boolean ("mapped",
5820 P_("Whether the actor will be painted"),
5822 CLUTTER_PARAM_READABLE);
5825 * ClutterActor:realized:
5827 * Whether the actor has been realized
5831 obj_props[PROP_REALIZED] =
5832 g_param_spec_boolean ("realized",
5834 P_("Whether the actor has been realized"),
5836 CLUTTER_PARAM_READABLE);
5839 * ClutterActor:reactive:
5841 * Whether the actor is reactive to events or not
5843 * Only reactive actors will emit event-related signals
5847 obj_props[PROP_REACTIVE] =
5848 g_param_spec_boolean ("reactive",
5850 P_("Whether the actor is reactive to events"),
5852 CLUTTER_PARAM_READWRITE);
5855 * ClutterActor:has-clip:
5857 * Whether the actor has the #ClutterActor:clip property set or not
5859 obj_props[PROP_HAS_CLIP] =
5860 g_param_spec_boolean ("has-clip",
5862 P_("Whether the actor has a clip set"),
5864 CLUTTER_PARAM_READABLE);
5867 * ClutterActor:clip:
5869 * The clip region for the actor, in actor-relative coordinates
5871 * Every part of the actor outside the clip region will not be
5874 obj_props[PROP_CLIP] =
5875 g_param_spec_boxed ("clip",
5877 P_("The clip region for the actor"),
5878 CLUTTER_TYPE_GEOMETRY,
5879 CLUTTER_PARAM_READWRITE);
5882 * ClutterActor:name:
5884 * The name of the actor
5888 obj_props[PROP_NAME] =
5889 g_param_spec_string ("name",
5891 P_("Name of the actor"),
5893 CLUTTER_PARAM_READWRITE);
5896 * ClutterActor:scale-x:
5898 * The horizontal scale of the actor.
5900 * The #ClutterActor:scale-x property is animatable.
5904 obj_props[PROP_SCALE_X] =
5905 g_param_spec_double ("scale-x",
5907 P_("Scale factor on the X axis"),
5911 G_PARAM_STATIC_STRINGS |
5912 CLUTTER_PARAM_ANIMATABLE);
5915 * ClutterActor:scale-y:
5917 * The vertical scale of the actor.
5919 * The #ClutterActor:scale-y property is animatable.
5923 obj_props[PROP_SCALE_Y] =
5924 g_param_spec_double ("scale-y",
5926 P_("Scale factor on the Y axis"),
5930 G_PARAM_STATIC_STRINGS |
5931 CLUTTER_PARAM_ANIMATABLE);
5934 * ClutterActor:scale-center-x:
5936 * The horizontal center point for scaling
5940 obj_props[PROP_SCALE_CENTER_X] =
5941 g_param_spec_float ("scale-center-x",
5942 P_("Scale Center X"),
5943 P_("Horizontal scale center"),
5944 -G_MAXFLOAT, G_MAXFLOAT,
5946 CLUTTER_PARAM_READWRITE);
5949 * ClutterActor:scale-center-y:
5951 * The vertical center point for scaling
5955 obj_props[PROP_SCALE_CENTER_Y] =
5956 g_param_spec_float ("scale-center-y",
5957 P_("Scale Center Y"),
5958 P_("Vertical scale center"),
5959 -G_MAXFLOAT, G_MAXFLOAT,
5961 CLUTTER_PARAM_READWRITE);
5964 * ClutterActor:scale-gravity:
5966 * The center point for scaling expressed as a #ClutterGravity
5970 obj_props[PROP_SCALE_GRAVITY] =
5971 g_param_spec_enum ("scale-gravity",
5972 P_("Scale Gravity"),
5973 P_("The center of scaling"),
5974 CLUTTER_TYPE_GRAVITY,
5975 CLUTTER_GRAVITY_NONE,
5976 CLUTTER_PARAM_READWRITE);
5979 * ClutterActor:rotation-angle-x:
5981 * The rotation angle on the X axis.
5983 * The #ClutterActor:rotation-angle-x property is animatable.
5987 obj_props[PROP_ROTATION_ANGLE_X] =
5988 g_param_spec_double ("rotation-angle-x",
5989 P_("Rotation Angle X"),
5990 P_("The rotation angle on the X axis"),
5991 -G_MAXDOUBLE, G_MAXDOUBLE,
5994 G_PARAM_STATIC_STRINGS |
5995 CLUTTER_PARAM_ANIMATABLE);
5998 * ClutterActor:rotation-angle-y:
6000 * The rotation angle on the Y axis
6002 * The #ClutterActor:rotation-angle-y property is animatable.
6006 obj_props[PROP_ROTATION_ANGLE_Y] =
6007 g_param_spec_double ("rotation-angle-y",
6008 P_("Rotation Angle Y"),
6009 P_("The rotation angle on the Y axis"),
6010 -G_MAXDOUBLE, G_MAXDOUBLE,
6013 G_PARAM_STATIC_STRINGS |
6014 CLUTTER_PARAM_ANIMATABLE);
6017 * ClutterActor:rotation-angle-z:
6019 * The rotation angle on the Z axis
6021 * The #ClutterActor:rotation-angle-z property is animatable.
6025 obj_props[PROP_ROTATION_ANGLE_Z] =
6026 g_param_spec_double ("rotation-angle-z",
6027 P_("Rotation Angle Z"),
6028 P_("The rotation angle on the Z axis"),
6029 -G_MAXDOUBLE, G_MAXDOUBLE,
6032 G_PARAM_STATIC_STRINGS |
6033 CLUTTER_PARAM_ANIMATABLE);
6036 * ClutterActor:rotation-center-x:
6038 * The rotation center on the X axis.
6042 obj_props[PROP_ROTATION_CENTER_X] =
6043 g_param_spec_boxed ("rotation-center-x",
6044 P_("Rotation Center X"),
6045 P_("The rotation center on the X axis"),
6046 CLUTTER_TYPE_VERTEX,
6047 CLUTTER_PARAM_READWRITE);
6050 * ClutterActor:rotation-center-y:
6052 * The rotation center on the Y axis.
6056 obj_props[PROP_ROTATION_CENTER_Y] =
6057 g_param_spec_boxed ("rotation-center-y",
6058 P_("Rotation Center Y"),
6059 P_("The rotation center on the Y axis"),
6060 CLUTTER_TYPE_VERTEX,
6061 CLUTTER_PARAM_READWRITE);
6064 * ClutterActor:rotation-center-z:
6066 * The rotation center on the Z axis.
6070 obj_props[PROP_ROTATION_CENTER_Z] =
6071 g_param_spec_boxed ("rotation-center-z",
6072 P_("Rotation Center Z"),
6073 P_("The rotation center on the Z axis"),
6074 CLUTTER_TYPE_VERTEX,
6075 CLUTTER_PARAM_READWRITE);
6078 * ClutterActor:rotation-center-z-gravity:
6080 * The rotation center on the Z axis expressed as a #ClutterGravity.
6084 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6085 g_param_spec_enum ("rotation-center-z-gravity",
6086 P_("Rotation Center Z Gravity"),
6087 P_("Center point for rotation around the Z axis"),
6088 CLUTTER_TYPE_GRAVITY,
6089 CLUTTER_GRAVITY_NONE,
6090 CLUTTER_PARAM_READWRITE);
6093 * ClutterActor:anchor-x:
6095 * The X coordinate of an actor's anchor point, relative to
6096 * the actor coordinate space, in pixels
6100 obj_props[PROP_ANCHOR_X] =
6101 g_param_spec_float ("anchor-x",
6103 P_("X coordinate of the anchor point"),
6104 -G_MAXFLOAT, G_MAXFLOAT,
6106 CLUTTER_PARAM_READWRITE);
6109 * ClutterActor:anchor-y:
6111 * The Y coordinate of an actor's anchor point, relative to
6112 * the actor coordinate space, in pixels
6116 obj_props[PROP_ANCHOR_Y] =
6117 g_param_spec_float ("anchor-y",
6119 P_("Y coordinate of the anchor point"),
6120 -G_MAXFLOAT, G_MAXFLOAT,
6122 CLUTTER_PARAM_READWRITE);
6125 * ClutterActor:anchor-gravity:
6127 * The anchor point expressed as a #ClutterGravity
6131 obj_props[PROP_ANCHOR_GRAVITY] =
6132 g_param_spec_enum ("anchor-gravity",
6133 P_("Anchor Gravity"),
6134 P_("The anchor point as a ClutterGravity"),
6135 CLUTTER_TYPE_GRAVITY,
6136 CLUTTER_GRAVITY_NONE,
6137 CLUTTER_PARAM_READWRITE);
6140 * ClutterActor:show-on-set-parent:
6142 * If %TRUE, the actor is automatically shown when parented.
6144 * Calling clutter_actor_hide() on an actor which has not been
6145 * parented will set this property to %FALSE as a side effect.
6149 obj_props[PROP_SHOW_ON_SET_PARENT] =
6150 g_param_spec_boolean ("show-on-set-parent",
6151 P_("Show on set parent"),
6152 P_("Whether the actor is shown when parented"),
6154 CLUTTER_PARAM_READWRITE);
6157 * ClutterActor:clip-to-allocation:
6159 * Whether the clip region should track the allocated area
6162 * This property is ignored if a clip area has been explicitly
6163 * set using clutter_actor_set_clip().
6167 obj_props[PROP_CLIP_TO_ALLOCATION] =
6168 g_param_spec_boolean ("clip-to-allocation",
6169 P_("Clip to Allocation"),
6170 P_("Sets the clip region to track the actor's allocation"),
6172 CLUTTER_PARAM_READWRITE);
6175 * ClutterActor:text-direction:
6177 * The direction of the text inside a #ClutterActor.
6181 obj_props[PROP_TEXT_DIRECTION] =
6182 g_param_spec_enum ("text-direction",
6183 P_("Text Direction"),
6184 P_("Direction of the text"),
6185 CLUTTER_TYPE_TEXT_DIRECTION,
6186 CLUTTER_TEXT_DIRECTION_LTR,
6187 CLUTTER_PARAM_READWRITE);
6190 * ClutterActor:has-pointer:
6192 * Whether the actor contains the pointer of a #ClutterInputDevice
6197 obj_props[PROP_HAS_POINTER] =
6198 g_param_spec_boolean ("has-pointer",
6200 P_("Whether the actor contains the pointer of an input device"),
6202 CLUTTER_PARAM_READABLE);
6205 * ClutterActor:actions:
6207 * Adds a #ClutterAction to the actor
6211 obj_props[PROP_ACTIONS] =
6212 g_param_spec_object ("actions",
6214 P_("Adds an action to the actor"),
6215 CLUTTER_TYPE_ACTION,
6216 CLUTTER_PARAM_WRITABLE);
6219 * ClutterActor:constraints:
6221 * Adds a #ClutterConstraint to the actor
6225 obj_props[PROP_CONSTRAINTS] =
6226 g_param_spec_object ("constraints",
6228 P_("Adds a constraint to the actor"),
6229 CLUTTER_TYPE_CONSTRAINT,
6230 CLUTTER_PARAM_WRITABLE);
6233 * ClutterActor:effect:
6235 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6239 obj_props[PROP_EFFECT] =
6240 g_param_spec_object ("effect",
6242 P_("Add an effect to be applied on the actor"),
6243 CLUTTER_TYPE_EFFECT,
6244 CLUTTER_PARAM_WRITABLE);
6247 * ClutterActor:layout-manager:
6249 * A delegate object for controlling the layout of the children of
6254 obj_props[PROP_LAYOUT_MANAGER] =
6255 g_param_spec_object ("layout-manager",
6256 P_("Layout Manager"),
6257 P_("The object controlling the layout of an actor's children"),
6258 CLUTTER_TYPE_LAYOUT_MANAGER,
6259 CLUTTER_PARAM_READWRITE);
6263 * ClutterActor:x-align:
6265 * The alignment of an actor on the X axis, if the actor has been given
6266 * extra space for its allocation.
6270 obj_props[PROP_X_ALIGN] =
6271 g_param_spec_enum ("x-align",
6273 P_("The alignment of the actor on the X axis within its allocation"),
6274 CLUTTER_TYPE_ACTOR_ALIGN,
6275 CLUTTER_ACTOR_ALIGN_FILL,
6276 CLUTTER_PARAM_READWRITE);
6279 * ClutterActor:y-align:
6281 * The alignment of an actor on the Y axis, if the actor has been given
6282 * extra space for its allocation.
6286 obj_props[PROP_Y_ALIGN] =
6287 g_param_spec_enum ("y-align",
6289 P_("The alignment of the actor on the Y axis within its allocation"),
6290 CLUTTER_TYPE_ACTOR_ALIGN,
6291 CLUTTER_ACTOR_ALIGN_FILL,
6292 CLUTTER_PARAM_READWRITE);
6295 * ClutterActor:margin-top:
6297 * The margin (in pixels) from the top of the actor.
6299 * This property adds a margin to the actor's preferred size; the margin
6300 * will be automatically taken into account when allocating the actor.
6304 obj_props[PROP_MARGIN_TOP] =
6305 g_param_spec_float ("margin-top",
6307 P_("Extra space at the top"),
6310 CLUTTER_PARAM_READWRITE);
6313 * ClutterActor:margin-bottom:
6315 * The margin (in pixels) from the bottom of the actor.
6317 * This property adds a margin to the actor's preferred size; the margin
6318 * will be automatically taken into account when allocating the actor.
6322 obj_props[PROP_MARGIN_BOTTOM] =
6323 g_param_spec_float ("margin-bottom",
6324 P_("Margin Bottom"),
6325 P_("Extra space at the bottom"),
6328 CLUTTER_PARAM_READWRITE);
6331 * ClutterActor:margin-left:
6333 * The margin (in pixels) from the left of the actor.
6335 * This property adds a margin to the actor's preferred size; the margin
6336 * will be automatically taken into account when allocating the actor.
6340 obj_props[PROP_MARGIN_LEFT] =
6341 g_param_spec_float ("margin-left",
6343 P_("Extra space at the left"),
6346 CLUTTER_PARAM_READWRITE);
6349 * ClutterActor:margin-right:
6351 * The margin (in pixels) from the right of the actor.
6353 * This property adds a margin to the actor's preferred size; the margin
6354 * will be automatically taken into account when allocating the actor.
6358 obj_props[PROP_MARGIN_RIGHT] =
6359 g_param_spec_float ("margin-right",
6361 P_("Extra space at the right"),
6364 CLUTTER_PARAM_READWRITE);
6367 * ClutterActor:background-color-set:
6369 * Whether the #ClutterActor:background-color property has been set.
6373 obj_props[PROP_BACKGROUND_COLOR_SET] =
6374 g_param_spec_boolean ("background-color-set",
6375 P_("Background Color Set"),
6376 P_("Whether the background color is set"),
6378 CLUTTER_PARAM_READABLE);
6381 * ClutterActor:background-color:
6383 * Paints a solid fill of the actor's allocation using the specified
6386 * The #ClutterActor:background-color property is animatable.
6390 obj_props[PROP_BACKGROUND_COLOR] =
6391 clutter_param_spec_color ("background-color",
6392 P_("Background color"),
6393 P_("The actor's background color"),
6394 CLUTTER_COLOR_Transparent,
6396 G_PARAM_STATIC_STRINGS |
6397 CLUTTER_PARAM_ANIMATABLE);
6400 * ClutterActor:first-child:
6402 * The actor's first child.
6406 obj_props[PROP_FIRST_CHILD] =
6407 g_param_spec_object ("first-child",
6409 P_("The actor's first child"),
6411 CLUTTER_PARAM_READABLE);
6414 * ClutterActor:last-child:
6416 * The actor's last child.
6420 obj_props[PROP_LAST_CHILD] =
6421 g_param_spec_object ("last-child",
6423 P_("The actor's last child"),
6425 CLUTTER_PARAM_READABLE);
6428 * ClutterActor:content:
6430 * The #ClutterContent implementation that controls the content
6435 obj_props[PROP_CONTENT] =
6436 g_param_spec_object ("content",
6438 P_("Delegate object for painting the actor's content"),
6439 CLUTTER_TYPE_CONTENT,
6440 CLUTTER_PARAM_READWRITE);
6443 * ClutterActor:content-gravity:
6445 * The alignment that should be honoured by the #ClutterContent
6446 * set with the #ClutterActor:content property.
6448 * Changing the value of this property will change the bounding box of
6449 * the content; you can use the #ClutterActor:content-box property to
6450 * get the position and size of the content within the actor's
6453 * This property is meaningful only for #ClutterContent implementations
6454 * that have a preferred size, and if the preferred size is smaller than
6455 * the actor's allocation.
6457 * The #ClutterActor:content-gravity property is animatable.
6461 obj_props[PROP_CONTENT_GRAVITY] =
6462 g_param_spec_enum ("content-gravity",
6463 P_("Content Gravity"),
6464 P_("Alignment of the actor's content"),
6465 CLUTTER_TYPE_CONTENT_GRAVITY,
6466 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6467 CLUTTER_PARAM_READWRITE);
6470 * ClutterActor:content-box:
6472 * The bounding box for the #ClutterContent used by the actor.
6474 * The value of this property is controlled by the #ClutterActor:allocation
6475 * and #ClutterActor:content-gravity properties of #ClutterActor.
6477 * The bounding box for the content is guaranteed to never exceed the
6478 * allocation's of the actor.
6482 obj_props[PROP_CONTENT_BOX] =
6483 g_param_spec_boxed ("content-box",
6485 P_("The bounding box of the actor's content"),
6486 CLUTTER_TYPE_ACTOR_BOX,
6488 G_PARAM_STATIC_STRINGS |
6489 CLUTTER_PARAM_ANIMATABLE);
6491 obj_props[PROP_MINIFICATION_FILTER] =
6492 g_param_spec_enum ("minification-filter",
6493 P_("Minification Filter"),
6494 P_("The filter used when reducing the size of the content"),
6495 CLUTTER_TYPE_SCALING_FILTER,
6496 CLUTTER_SCALING_FILTER_LINEAR,
6497 CLUTTER_PARAM_READWRITE);
6499 obj_props[PROP_MAGNIFICATION_FILTER] =
6500 g_param_spec_enum ("magnification-filter",
6501 P_("Magnification Filter"),
6502 P_("The filter used when increasing the size of the content"),
6503 CLUTTER_TYPE_SCALING_FILTER,
6504 CLUTTER_SCALING_FILTER_LINEAR,
6505 CLUTTER_PARAM_READWRITE);
6507 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6510 * ClutterActor::destroy:
6511 * @actor: the #ClutterActor which emitted the signal
6513 * The ::destroy signal notifies that all references held on the
6514 * actor which emitted it should be released.
6516 * The ::destroy signal should be used by all holders of a reference
6519 * This signal might result in the finalization of the #ClutterActor
6520 * if all references are released.
6522 * Composite actors and actors implementing the #ClutterContainer
6523 * interface should override the default implementation of the
6524 * class handler of this signal and call clutter_actor_destroy() on
6525 * their children. When overriding the default class handler, it is
6526 * required to chain up to the parent's implementation.
6530 actor_signals[DESTROY] =
6531 g_signal_new (I_("destroy"),
6532 G_TYPE_FROM_CLASS (object_class),
6533 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6534 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6536 _clutter_marshal_VOID__VOID,
6539 * ClutterActor::show:
6540 * @actor: the object which received the signal
6542 * The ::show signal is emitted when an actor is visible and
6543 * rendered on the stage.
6547 actor_signals[SHOW] =
6548 g_signal_new (I_("show"),
6549 G_TYPE_FROM_CLASS (object_class),
6551 G_STRUCT_OFFSET (ClutterActorClass, show),
6553 _clutter_marshal_VOID__VOID,
6556 * ClutterActor::hide:
6557 * @actor: the object which received the signal
6559 * The ::hide signal is emitted when an actor is no longer rendered
6564 actor_signals[HIDE] =
6565 g_signal_new (I_("hide"),
6566 G_TYPE_FROM_CLASS (object_class),
6568 G_STRUCT_OFFSET (ClutterActorClass, hide),
6570 _clutter_marshal_VOID__VOID,
6573 * ClutterActor::parent-set:
6574 * @actor: the object which received the signal
6575 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6577 * This signal is emitted when the parent of the actor changes.
6581 actor_signals[PARENT_SET] =
6582 g_signal_new (I_("parent-set"),
6583 G_TYPE_FROM_CLASS (object_class),
6585 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6587 _clutter_marshal_VOID__OBJECT,
6589 CLUTTER_TYPE_ACTOR);
6592 * ClutterActor::queue-redraw:
6593 * @actor: the actor we're bubbling the redraw request through
6594 * @origin: the actor which initiated the redraw request
6596 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6597 * is called on @origin.
6599 * The default implementation for #ClutterActor chains up to the
6600 * parent actor and queues a redraw on the parent, thus "bubbling"
6601 * the redraw queue up through the actor graph. The default
6602 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6603 * in a main loop idle handler.
6605 * Note that the @origin actor may be the stage, or a container; it
6606 * does not have to be a leaf node in the actor graph.
6608 * Toolkits embedding a #ClutterStage which require a redraw and
6609 * relayout cycle can stop the emission of this signal using the
6610 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6615 * on_redraw_complete (gpointer data)
6617 * ClutterStage *stage = data;
6619 * /* execute the Clutter drawing pipeline */
6620 * clutter_stage_ensure_redraw (stage);
6624 * on_stage_queue_redraw (ClutterStage *stage)
6626 * /* this prevents the default handler to run */
6627 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6629 * /* queue a redraw with the host toolkit and call
6630 * * a function when the redraw has been completed
6632 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6636 * <note><para>This signal is emitted before the Clutter paint
6637 * pipeline is executed. If you want to know when the pipeline has
6638 * been completed you should connect to the ::paint signal on the
6639 * Stage with g_signal_connect_after().</para></note>
6643 actor_signals[QUEUE_REDRAW] =
6644 g_signal_new (I_("queue-redraw"),
6645 G_TYPE_FROM_CLASS (object_class),
6648 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6650 _clutter_marshal_VOID__OBJECT,
6652 CLUTTER_TYPE_ACTOR);
6655 * ClutterActor::queue-relayout
6656 * @actor: the actor being queued for relayout
6658 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6659 * is called on an actor.
6661 * The default implementation for #ClutterActor chains up to the
6662 * parent actor and queues a relayout on the parent, thus "bubbling"
6663 * the relayout queue up through the actor graph.
6665 * The main purpose of this signal is to allow relayout to be propagated
6666 * properly in the procense of #ClutterClone actors. Applications will
6667 * not normally need to connect to this signal.
6671 actor_signals[QUEUE_RELAYOUT] =
6672 g_signal_new (I_("queue-relayout"),
6673 G_TYPE_FROM_CLASS (object_class),
6676 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6678 _clutter_marshal_VOID__VOID,
6682 * ClutterActor::event:
6683 * @actor: the actor which received the event
6684 * @event: a #ClutterEvent
6686 * The ::event signal is emitted each time an event is received
6687 * by the @actor. This signal will be emitted on every actor,
6688 * following the hierarchy chain, until it reaches the top-level
6689 * container (the #ClutterStage).
6691 * Return value: %TRUE if the event has been handled by the actor,
6692 * or %FALSE to continue the emission.
6696 actor_signals[EVENT] =
6697 g_signal_new (I_("event"),
6698 G_TYPE_FROM_CLASS (object_class),
6700 G_STRUCT_OFFSET (ClutterActorClass, event),
6701 _clutter_boolean_handled_accumulator, NULL,
6702 _clutter_marshal_BOOLEAN__BOXED,
6704 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6706 * ClutterActor::button-press-event:
6707 * @actor: the actor which received the event
6708 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6710 * The ::button-press-event signal is emitted each time a mouse button
6711 * is pressed on @actor.
6713 * Return value: %TRUE if the event has been handled by the actor,
6714 * or %FALSE to continue the emission.
6718 actor_signals[BUTTON_PRESS_EVENT] =
6719 g_signal_new (I_("button-press-event"),
6720 G_TYPE_FROM_CLASS (object_class),
6722 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6723 _clutter_boolean_handled_accumulator, NULL,
6724 _clutter_marshal_BOOLEAN__BOXED,
6726 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6728 * ClutterActor::button-release-event:
6729 * @actor: the actor which received the event
6730 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6732 * The ::button-release-event signal is emitted each time a mouse button
6733 * is released on @actor.
6735 * Return value: %TRUE if the event has been handled by the actor,
6736 * or %FALSE to continue the emission.
6740 actor_signals[BUTTON_RELEASE_EVENT] =
6741 g_signal_new (I_("button-release-event"),
6742 G_TYPE_FROM_CLASS (object_class),
6744 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6745 _clutter_boolean_handled_accumulator, NULL,
6746 _clutter_marshal_BOOLEAN__BOXED,
6748 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6750 * ClutterActor::scroll-event:
6751 * @actor: the actor which received the event
6752 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6754 * The ::scroll-event signal is emitted each time the mouse is
6755 * scrolled on @actor
6757 * Return value: %TRUE if the event has been handled by the actor,
6758 * or %FALSE to continue the emission.
6762 actor_signals[SCROLL_EVENT] =
6763 g_signal_new (I_("scroll-event"),
6764 G_TYPE_FROM_CLASS (object_class),
6766 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6767 _clutter_boolean_handled_accumulator, NULL,
6768 _clutter_marshal_BOOLEAN__BOXED,
6770 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6772 * ClutterActor::key-press-event:
6773 * @actor: the actor which received the event
6774 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6776 * The ::key-press-event signal is emitted each time a keyboard button
6777 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6779 * Return value: %TRUE if the event has been handled by the actor,
6780 * or %FALSE to continue the emission.
6784 actor_signals[KEY_PRESS_EVENT] =
6785 g_signal_new (I_("key-press-event"),
6786 G_TYPE_FROM_CLASS (object_class),
6788 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6789 _clutter_boolean_handled_accumulator, NULL,
6790 _clutter_marshal_BOOLEAN__BOXED,
6792 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6794 * ClutterActor::key-release-event:
6795 * @actor: the actor which received the event
6796 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6798 * The ::key-release-event signal is emitted each time a keyboard button
6799 * is released while @actor has key focus (see
6800 * clutter_stage_set_key_focus()).
6802 * Return value: %TRUE if the event has been handled by the actor,
6803 * or %FALSE to continue the emission.
6807 actor_signals[KEY_RELEASE_EVENT] =
6808 g_signal_new (I_("key-release-event"),
6809 G_TYPE_FROM_CLASS (object_class),
6811 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6812 _clutter_boolean_handled_accumulator, NULL,
6813 _clutter_marshal_BOOLEAN__BOXED,
6815 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6817 * ClutterActor::motion-event:
6818 * @actor: the actor which received the event
6819 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6821 * The ::motion-event signal is emitted each time the mouse pointer is
6822 * moved over @actor.
6824 * Return value: %TRUE if the event has been handled by the actor,
6825 * or %FALSE to continue the emission.
6829 actor_signals[MOTION_EVENT] =
6830 g_signal_new (I_("motion-event"),
6831 G_TYPE_FROM_CLASS (object_class),
6833 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6834 _clutter_boolean_handled_accumulator, NULL,
6835 _clutter_marshal_BOOLEAN__BOXED,
6837 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6840 * ClutterActor::key-focus-in:
6841 * @actor: the actor which now has key focus
6843 * The ::key-focus-in signal is emitted when @actor receives key focus.
6847 actor_signals[KEY_FOCUS_IN] =
6848 g_signal_new (I_("key-focus-in"),
6849 G_TYPE_FROM_CLASS (object_class),
6851 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6853 _clutter_marshal_VOID__VOID,
6857 * ClutterActor::key-focus-out:
6858 * @actor: the actor which now has key focus
6860 * The ::key-focus-out signal is emitted when @actor loses key focus.
6864 actor_signals[KEY_FOCUS_OUT] =
6865 g_signal_new (I_("key-focus-out"),
6866 G_TYPE_FROM_CLASS (object_class),
6868 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6870 _clutter_marshal_VOID__VOID,
6874 * ClutterActor::enter-event:
6875 * @actor: the actor which the pointer has entered.
6876 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6878 * The ::enter-event signal is emitted when the pointer enters the @actor
6880 * Return value: %TRUE if the event has been handled by the actor,
6881 * or %FALSE to continue the emission.
6885 actor_signals[ENTER_EVENT] =
6886 g_signal_new (I_("enter-event"),
6887 G_TYPE_FROM_CLASS (object_class),
6889 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6890 _clutter_boolean_handled_accumulator, NULL,
6891 _clutter_marshal_BOOLEAN__BOXED,
6893 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6896 * ClutterActor::leave-event:
6897 * @actor: the actor which the pointer has left
6898 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6900 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6902 * Return value: %TRUE if the event has been handled by the actor,
6903 * or %FALSE to continue the emission.
6907 actor_signals[LEAVE_EVENT] =
6908 g_signal_new (I_("leave-event"),
6909 G_TYPE_FROM_CLASS (object_class),
6911 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6912 _clutter_boolean_handled_accumulator, NULL,
6913 _clutter_marshal_BOOLEAN__BOXED,
6915 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6918 * ClutterActor::captured-event:
6919 * @actor: the actor which received the signal
6920 * @event: a #ClutterEvent
6922 * The ::captured-event signal is emitted when an event is captured
6923 * by Clutter. This signal will be emitted starting from the top-level
6924 * container (the #ClutterStage) to the actor which received the event
6925 * going down the hierarchy. This signal can be used to intercept every
6926 * event before the specialized events (like
6927 * ClutterActor::button-press-event or ::key-released-event) are
6930 * Return value: %TRUE if the event has been handled by the actor,
6931 * or %FALSE to continue the emission.
6935 actor_signals[CAPTURED_EVENT] =
6936 g_signal_new (I_("captured-event"),
6937 G_TYPE_FROM_CLASS (object_class),
6939 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6940 _clutter_boolean_handled_accumulator, NULL,
6941 _clutter_marshal_BOOLEAN__BOXED,
6943 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6946 * ClutterActor::paint:
6947 * @actor: the #ClutterActor that received the signal
6949 * The ::paint signal is emitted each time an actor is being painted.
6951 * Subclasses of #ClutterActor should override the class signal handler
6952 * and paint themselves in that function.
6954 * It is possible to connect a handler to the ::paint signal in order
6955 * to set up some custom aspect of a paint.
6959 actor_signals[PAINT] =
6960 g_signal_new (I_("paint"),
6961 G_TYPE_FROM_CLASS (object_class),
6964 G_STRUCT_OFFSET (ClutterActorClass, paint),
6966 _clutter_marshal_VOID__VOID,
6969 * ClutterActor::realize:
6970 * @actor: the #ClutterActor that received the signal
6972 * The ::realize signal is emitted each time an actor is being
6977 actor_signals[REALIZE] =
6978 g_signal_new (I_("realize"),
6979 G_TYPE_FROM_CLASS (object_class),
6981 G_STRUCT_OFFSET (ClutterActorClass, realize),
6983 _clutter_marshal_VOID__VOID,
6986 * ClutterActor::unrealize:
6987 * @actor: the #ClutterActor that received the signal
6989 * The ::unrealize signal is emitted each time an actor is being
6994 actor_signals[UNREALIZE] =
6995 g_signal_new (I_("unrealize"),
6996 G_TYPE_FROM_CLASS (object_class),
6998 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7000 _clutter_marshal_VOID__VOID,
7004 * ClutterActor::pick:
7005 * @actor: the #ClutterActor that received the signal
7006 * @color: the #ClutterColor to be used when picking
7008 * The ::pick signal is emitted each time an actor is being painted
7009 * in "pick mode". The pick mode is used to identify the actor during
7010 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7011 * The actor should paint its shape using the passed @pick_color.
7013 * Subclasses of #ClutterActor should override the class signal handler
7014 * and paint themselves in that function.
7016 * It is possible to connect a handler to the ::pick signal in order
7017 * to set up some custom aspect of a paint in pick mode.
7021 actor_signals[PICK] =
7022 g_signal_new (I_("pick"),
7023 G_TYPE_FROM_CLASS (object_class),
7025 G_STRUCT_OFFSET (ClutterActorClass, pick),
7027 _clutter_marshal_VOID__BOXED,
7029 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7032 * ClutterActor::allocation-changed:
7033 * @actor: the #ClutterActor that emitted the signal
7034 * @box: a #ClutterActorBox with the new allocation
7035 * @flags: #ClutterAllocationFlags for the allocation
7037 * The ::allocation-changed signal is emitted when the
7038 * #ClutterActor:allocation property changes. Usually, application
7039 * code should just use the notifications for the :allocation property
7040 * but if you want to track the allocation flags as well, for instance
7041 * to know whether the absolute origin of @actor changed, then you might
7042 * want use this signal instead.
7046 actor_signals[ALLOCATION_CHANGED] =
7047 g_signal_new (I_("allocation-changed"),
7048 G_TYPE_FROM_CLASS (object_class),
7052 _clutter_marshal_VOID__BOXED_FLAGS,
7054 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7055 CLUTTER_TYPE_ALLOCATION_FLAGS);
7058 * ClutterActor::transitions-completed:
7059 * @actor: a #ClutterActor
7061 * The ::transitions-completed signal is emitted once all transitions
7062 * involving @actor are complete.
7066 actor_signals[TRANSITIONS_COMPLETED] =
7067 g_signal_new (I_("transitions-completed"),
7068 G_TYPE_FROM_CLASS (object_class),
7072 _clutter_marshal_VOID__VOID,
7077 clutter_actor_init (ClutterActor *self)
7079 ClutterActorPrivate *priv;
7081 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7083 priv->id = _clutter_context_acquire_id (self);
7086 priv->opacity = 0xff;
7087 priv->show_on_set_parent = TRUE;
7089 priv->needs_width_request = TRUE;
7090 priv->needs_height_request = TRUE;
7091 priv->needs_allocation = TRUE;
7093 priv->cached_width_age = 1;
7094 priv->cached_height_age = 1;
7096 priv->opacity_override = -1;
7097 priv->enable_model_view_transform = TRUE;
7099 /* Initialize an empty paint volume to start with */
7100 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7101 priv->last_paint_volume_valid = TRUE;
7103 priv->transform_valid = FALSE;
7105 /* the default is to stretch the content, to match the
7106 * current behaviour of basically all actors. also, it's
7107 * the easiest thing to compute.
7109 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7110 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7111 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7115 * clutter_actor_new:
7117 * Creates a new #ClutterActor.
7119 * A newly created actor has a floating reference, which will be sunk
7120 * when it is added to another actor.
7122 * Return value: (transfer full): the newly created #ClutterActor
7127 clutter_actor_new (void)
7129 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7133 * clutter_actor_destroy:
7134 * @self: a #ClutterActor
7136 * Destroys an actor. When an actor is destroyed, it will break any
7137 * references it holds to other objects. If the actor is inside a
7138 * container, the actor will be removed.
7140 * When you destroy a container, its children will be destroyed as well.
7142 * Note: you cannot destroy the #ClutterStage returned by
7143 * clutter_stage_get_default().
7146 clutter_actor_destroy (ClutterActor *self)
7148 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7150 g_object_ref (self);
7152 /* avoid recursion while destroying */
7153 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7155 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7157 g_object_run_dispose (G_OBJECT (self));
7159 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7162 g_object_unref (self);
7166 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7167 ClutterPaintVolume *clip)
7169 ClutterActorPrivate *priv = self->priv;
7170 ClutterPaintVolume *pv;
7173 /* Remove queue entry early in the process, otherwise a new
7174 queue_redraw() during signal handling could put back this
7175 object in the stage redraw list (but the entry is freed as
7176 soon as we return from this function, causing a segfault
7179 priv->queue_redraw_entry = NULL;
7181 /* If we've been explicitly passed a clip volume then there's
7182 * nothing more to calculate, but otherwise the only thing we know
7183 * is that the change is constrained to the given actor.
7185 * The idea is that if we know the paint volume for where the actor
7186 * was last drawn (in eye coordinates) and we also have the paint
7187 * volume for where it will be drawn next (in actor coordinates)
7188 * then if we queue a redraw for both these volumes that will cover
7189 * everything that needs to be redrawn to clear the old view and
7190 * show the latest view of the actor.
7192 * Don't clip this redraw if we don't know what position we had for
7193 * the previous redraw since we don't know where to set the clip so
7194 * it will clear the actor as it is currently.
7198 _clutter_actor_set_queue_redraw_clip (self, clip);
7201 else if (G_LIKELY (priv->last_paint_volume_valid))
7203 pv = _clutter_actor_get_paint_volume_mutable (self);
7206 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7208 /* make sure we redraw the actors old position... */
7209 _clutter_actor_set_queue_redraw_clip (stage,
7210 &priv->last_paint_volume);
7211 _clutter_actor_signal_queue_redraw (stage, stage);
7212 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7214 /* XXX: Ideally the redraw signal would take a clip volume
7215 * argument, but that would be an ABI break. Until we can
7216 * break the ABI we pass the argument out-of-band
7219 /* setup the clip for the actors new position... */
7220 _clutter_actor_set_queue_redraw_clip (self, pv);
7229 _clutter_actor_signal_queue_redraw (self, self);
7231 /* Just in case anyone is manually firing redraw signals without
7232 * using the public queue_redraw() API we are careful to ensure that
7233 * our out-of-band clip member is cleared before returning...
7235 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7237 if (G_LIKELY (clipped))
7238 _clutter_actor_set_queue_redraw_clip (self, NULL);
7242 _clutter_actor_get_allocation_clip (ClutterActor *self,
7243 ClutterActorBox *clip)
7245 ClutterActorBox allocation;
7247 /* XXX: we don't care if we get an out of date allocation here
7248 * because clutter_actor_queue_redraw_with_clip knows to ignore
7249 * the clip if the actor's allocation is invalid.
7251 * This is noted because clutter_actor_get_allocation_box does some
7252 * unnecessary work to support buggy code with a comment suggesting
7253 * that it could be changed later which would be good for this use
7256 clutter_actor_get_allocation_box (self, &allocation);
7258 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7259 * actor's own coordinate space but the allocation is in parent
7263 clip->x2 = allocation.x2 - allocation.x1;
7264 clip->y2 = allocation.y2 - allocation.y1;
7268 _clutter_actor_queue_redraw_full (ClutterActor *self,
7269 ClutterRedrawFlags flags,
7270 ClutterPaintVolume *volume,
7271 ClutterEffect *effect)
7273 ClutterActorPrivate *priv = self->priv;
7274 ClutterPaintVolume allocation_pv;
7275 ClutterPaintVolume *pv;
7276 gboolean should_free_pv;
7277 ClutterActor *stage;
7279 /* Here's an outline of the actor queue redraw mechanism:
7281 * The process starts in one of the following two functions which
7282 * are wrappers for this function:
7283 * clutter_actor_queue_redraw
7284 * _clutter_actor_queue_redraw_with_clip
7286 * additionally, an effect can queue a redraw by wrapping this
7287 * function in clutter_effect_queue_rerun
7289 * This functions queues an entry in a list associated with the
7290 * stage which is a list of actors that queued a redraw while
7291 * updating the timelines, performing layouting and processing other
7292 * mainloop sources before the next paint starts.
7294 * We aim to minimize the processing done at this point because
7295 * there is a good chance other events will happen while updating
7296 * the scenegraph that would invalidate any expensive work we might
7297 * otherwise try to do here. For example we don't try and resolve
7298 * the screen space bounding box of an actor at this stage so as to
7299 * minimize how much of the screen redraw because it's possible
7300 * something else will happen which will force a full redraw anyway.
7302 * When all updates are complete and we come to paint the stage then
7303 * we iterate this list and actually emit the "queue-redraw" signals
7304 * for each of the listed actors which will bubble up to the stage
7305 * for each actor and at that point we will transform the actors
7306 * paint volume into screen coordinates to determine the clip region
7307 * for what needs to be redrawn in the next paint.
7309 * Besides minimizing redundant work another reason for this
7310 * deferred design is that it's more likely we will be able to
7311 * determine the paint volume of an actor once we've finished
7312 * updating the scenegraph because its allocation should be up to
7313 * date. NB: If we can't determine an actors paint volume then we
7314 * can't automatically queue a clipped redraw which can make a big
7315 * difference to performance.
7317 * So the control flow goes like this:
7318 * One of clutter_actor_queue_redraw,
7319 * _clutter_actor_queue_redraw_with_clip
7320 * or clutter_effect_queue_rerun
7322 * then control moves to:
7323 * _clutter_stage_queue_actor_redraw
7325 * later during _clutter_stage_do_update, once relayouting is done
7326 * and the scenegraph has been updated we will call:
7327 * _clutter_stage_finish_queue_redraws
7329 * _clutter_stage_finish_queue_redraws will call
7330 * _clutter_actor_finish_queue_redraw for each listed actor.
7331 * Note: actors *are* allowed to queue further redraws during this
7332 * process (considering clone actors or texture_new_from_actor which
7333 * respond to their source queueing a redraw by queuing a redraw
7334 * themselves). We repeat the process until the list is empty.
7336 * This will result in the "queue-redraw" signal being fired for
7337 * each actor which will pass control to the default signal handler:
7338 * clutter_actor_real_queue_redraw
7340 * This will bubble up to the stages handler:
7341 * clutter_stage_real_queue_redraw
7343 * clutter_stage_real_queue_redraw will transform the actors paint
7344 * volume into screen space and add it as a clip region for the next
7348 /* ignore queueing a redraw for actors being destroyed */
7349 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7352 stage = _clutter_actor_get_stage_internal (self);
7354 /* Ignore queueing a redraw for actors not descended from a stage */
7358 /* ignore queueing a redraw on stages that are being destroyed */
7359 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7362 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7364 ClutterActorBox allocation_clip;
7365 ClutterVertex origin;
7367 /* If the actor doesn't have a valid allocation then we will
7368 * queue a full stage redraw. */
7369 if (priv->needs_allocation)
7371 /* NB: NULL denotes an undefined clip which will result in a
7373 _clutter_actor_set_queue_redraw_clip (self, NULL);
7374 _clutter_actor_signal_queue_redraw (self, self);
7378 _clutter_paint_volume_init_static (&allocation_pv, self);
7379 pv = &allocation_pv;
7381 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7383 origin.x = allocation_clip.x1;
7384 origin.y = allocation_clip.y1;
7386 clutter_paint_volume_set_origin (pv, &origin);
7387 clutter_paint_volume_set_width (pv,
7388 allocation_clip.x2 - allocation_clip.x1);
7389 clutter_paint_volume_set_height (pv,
7390 allocation_clip.y2 -
7391 allocation_clip.y1);
7392 should_free_pv = TRUE;
7397 should_free_pv = FALSE;
7400 self->priv->queue_redraw_entry =
7401 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7402 priv->queue_redraw_entry,
7407 clutter_paint_volume_free (pv);
7409 /* If this is the first redraw queued then we can directly use the
7411 if (!priv->is_dirty)
7412 priv->effect_to_redraw = effect;
7413 /* Otherwise we need to merge it with the existing effect parameter */
7414 else if (effect != NULL)
7416 /* If there's already an effect then we need to use whichever is
7417 later in the chain of actors. Otherwise a full redraw has
7418 already been queued on the actor so we need to ignore the
7420 if (priv->effect_to_redraw != NULL)
7422 if (priv->effects == NULL)
7423 g_warning ("Redraw queued with an effect that is "
7424 "not applied to the actor");
7429 for (l = _clutter_meta_group_peek_metas (priv->effects);
7433 if (l->data == priv->effect_to_redraw ||
7435 priv->effect_to_redraw = l->data;
7442 /* If no effect is specified then we need to redraw the whole
7444 priv->effect_to_redraw = NULL;
7447 priv->is_dirty = TRUE;
7451 * clutter_actor_queue_redraw:
7452 * @self: A #ClutterActor
7454 * Queues up a redraw of an actor and any children. The redraw occurs
7455 * once the main loop becomes idle (after the current batch of events
7456 * has been processed, roughly).
7458 * Applications rarely need to call this, as redraws are handled
7459 * automatically by modification functions.
7461 * This function will not do anything if @self is not visible, or
7462 * if the actor is inside an invisible part of the scenegraph.
7464 * Also be aware that painting is a NOP for actors with an opacity of
7467 * When you are implementing a custom actor you must queue a redraw
7468 * whenever some private state changes that will affect painting or
7469 * picking of your actor.
7472 clutter_actor_queue_redraw (ClutterActor *self)
7474 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7476 _clutter_actor_queue_redraw_full (self,
7478 NULL, /* clip volume */
7483 * _clutter_actor_queue_redraw_with_clip:
7484 * @self: A #ClutterActor
7485 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7486 * this queue redraw.
7487 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7488 * redrawn or %NULL if you are just using a @flag to state your
7491 * Queues up a clipped redraw of an actor and any children. The redraw
7492 * occurs once the main loop becomes idle (after the current batch of
7493 * events has been processed, roughly).
7495 * If no flags are given the clip volume is defined by @volume
7496 * specified in actor coordinates and tells Clutter that only content
7497 * within this volume has been changed so Clutter can optionally
7498 * optimize the redraw.
7500 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7501 * should be %NULL and this tells Clutter to use the actor's current
7502 * allocation as a clip box. This flag can only be used for 2D actors,
7503 * because any actor with depth may be projected outside its
7506 * Applications rarely need to call this, as redraws are handled
7507 * automatically by modification functions.
7509 * This function will not do anything if @self is not visible, or if
7510 * the actor is inside an invisible part of the scenegraph.
7512 * Also be aware that painting is a NOP for actors with an opacity of
7515 * When you are implementing a custom actor you must queue a redraw
7516 * whenever some private state changes that will affect painting or
7517 * picking of your actor.
7520 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7521 ClutterRedrawFlags flags,
7522 ClutterPaintVolume *volume)
7524 _clutter_actor_queue_redraw_full (self,
7526 volume, /* clip volume */
7531 _clutter_actor_queue_only_relayout (ClutterActor *self)
7533 ClutterActorPrivate *priv = self->priv;
7535 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7538 if (priv->needs_width_request &&
7539 priv->needs_height_request &&
7540 priv->needs_allocation)
7541 return; /* save some cpu cycles */
7543 #if CLUTTER_ENABLE_DEBUG
7544 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7546 g_warning ("The actor '%s' is currently inside an allocation "
7547 "cycle; calling clutter_actor_queue_relayout() is "
7549 _clutter_actor_get_debug_name (self));
7551 #endif /* CLUTTER_ENABLE_DEBUG */
7553 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7557 * clutter_actor_queue_redraw_with_clip:
7558 * @self: a #ClutterActor
7559 * @clip: (allow-none): a rectangular clip region, or %NULL
7561 * Queues a redraw on @self limited to a specific, actor-relative
7564 * If @clip is %NULL this function is equivalent to
7565 * clutter_actor_queue_redraw().
7570 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7571 const cairo_rectangle_int_t *clip)
7573 ClutterPaintVolume volume;
7574 ClutterVertex origin;
7576 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7580 clutter_actor_queue_redraw (self);
7584 _clutter_paint_volume_init_static (&volume, self);
7590 clutter_paint_volume_set_origin (&volume, &origin);
7591 clutter_paint_volume_set_width (&volume, clip->width);
7592 clutter_paint_volume_set_height (&volume, clip->height);
7594 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7596 clutter_paint_volume_free (&volume);
7600 * clutter_actor_queue_relayout:
7601 * @self: A #ClutterActor
7603 * Indicates that the actor's size request or other layout-affecting
7604 * properties may have changed. This function is used inside #ClutterActor
7605 * subclass implementations, not by applications directly.
7607 * Queueing a new layout automatically queues a redraw as well.
7612 clutter_actor_queue_relayout (ClutterActor *self)
7614 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7616 _clutter_actor_queue_only_relayout (self);
7617 clutter_actor_queue_redraw (self);
7621 * clutter_actor_get_preferred_size:
7622 * @self: a #ClutterActor
7623 * @min_width_p: (out) (allow-none): return location for the minimum
7625 * @min_height_p: (out) (allow-none): return location for the minimum
7627 * @natural_width_p: (out) (allow-none): return location for the natural
7629 * @natural_height_p: (out) (allow-none): return location for the natural
7632 * Computes the preferred minimum and natural size of an actor, taking into
7633 * account the actor's geometry management (either height-for-width
7634 * or width-for-height).
7636 * The width and height used to compute the preferred height and preferred
7637 * width are the actor's natural ones.
7639 * If you need to control the height for the preferred width, or the width for
7640 * the preferred height, you should use clutter_actor_get_preferred_width()
7641 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7642 * geometry management using the #ClutterActor:request-mode property.
7647 clutter_actor_get_preferred_size (ClutterActor *self,
7648 gfloat *min_width_p,
7649 gfloat *min_height_p,
7650 gfloat *natural_width_p,
7651 gfloat *natural_height_p)
7653 ClutterActorPrivate *priv;
7654 gfloat min_width, min_height;
7655 gfloat natural_width, natural_height;
7657 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7661 min_width = min_height = 0;
7662 natural_width = natural_height = 0;
7664 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7666 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7667 clutter_actor_get_preferred_width (self, -1,
7670 clutter_actor_get_preferred_height (self, natural_width,
7676 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7677 clutter_actor_get_preferred_height (self, -1,
7680 clutter_actor_get_preferred_width (self, natural_height,
7686 *min_width_p = min_width;
7689 *min_height_p = min_height;
7691 if (natural_width_p)
7692 *natural_width_p = natural_width;
7694 if (natural_height_p)
7695 *natural_height_p = natural_height;
7700 * @align: a #ClutterActorAlign
7701 * @direction: a #ClutterTextDirection
7703 * Retrieves the correct alignment depending on the text direction
7705 * Return value: the effective alignment
7707 static ClutterActorAlign
7708 effective_align (ClutterActorAlign align,
7709 ClutterTextDirection direction)
7711 ClutterActorAlign res;
7715 case CLUTTER_ACTOR_ALIGN_START:
7716 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7717 ? CLUTTER_ACTOR_ALIGN_END
7718 : CLUTTER_ACTOR_ALIGN_START;
7721 case CLUTTER_ACTOR_ALIGN_END:
7722 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7723 ? CLUTTER_ACTOR_ALIGN_START
7724 : CLUTTER_ACTOR_ALIGN_END;
7736 adjust_for_margin (float margin_start,
7738 float *minimum_size,
7739 float *natural_size,
7740 float *allocated_start,
7741 float *allocated_end)
7743 *minimum_size -= (margin_start + margin_end);
7744 *natural_size -= (margin_start + margin_end);
7745 *allocated_start += margin_start;
7746 *allocated_end -= margin_end;
7750 adjust_for_alignment (ClutterActorAlign alignment,
7752 float *allocated_start,
7753 float *allocated_end)
7755 float allocated_size = *allocated_end - *allocated_start;
7759 case CLUTTER_ACTOR_ALIGN_FILL:
7763 case CLUTTER_ACTOR_ALIGN_START:
7765 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7768 case CLUTTER_ACTOR_ALIGN_END:
7769 if (allocated_size > natural_size)
7771 *allocated_start += (allocated_size - natural_size);
7772 *allocated_end = *allocated_start + natural_size;
7776 case CLUTTER_ACTOR_ALIGN_CENTER:
7777 if (allocated_size > natural_size)
7779 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7780 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7787 * clutter_actor_adjust_width:
7788 * @self: a #ClutterActor
7789 * @minimum_width: (inout): the actor's preferred minimum width, which
7790 * will be adjusted depending on the margin
7791 * @natural_width: (inout): the actor's preferred natural width, which
7792 * will be adjusted depending on the margin
7793 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7794 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7796 * Adjusts the preferred and allocated position and size of an actor,
7797 * depending on the margin and alignment properties.
7800 clutter_actor_adjust_width (ClutterActor *self,
7801 gfloat *minimum_width,
7802 gfloat *natural_width,
7803 gfloat *adjusted_x1,
7804 gfloat *adjusted_x2)
7806 ClutterTextDirection text_dir;
7807 const ClutterLayoutInfo *info;
7809 info = _clutter_actor_get_layout_info_or_defaults (self);
7810 text_dir = clutter_actor_get_text_direction (self);
7812 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7814 /* this will tweak natural_width to remove the margin, so that
7815 * adjust_for_alignment() will use the correct size
7817 adjust_for_margin (info->margin.left, info->margin.right,
7818 minimum_width, natural_width,
7819 adjusted_x1, adjusted_x2);
7821 adjust_for_alignment (effective_align (info->x_align, text_dir),
7823 adjusted_x1, adjusted_x2);
7827 * clutter_actor_adjust_height:
7828 * @self: a #ClutterActor
7829 * @minimum_height: (inout): the actor's preferred minimum height, which
7830 * will be adjusted depending on the margin
7831 * @natural_height: (inout): the actor's preferred natural height, which
7832 * will be adjusted depending on the margin
7833 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7834 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7836 * Adjusts the preferred and allocated position and size of an actor,
7837 * depending on the margin and alignment properties.
7840 clutter_actor_adjust_height (ClutterActor *self,
7841 gfloat *minimum_height,
7842 gfloat *natural_height,
7843 gfloat *adjusted_y1,
7844 gfloat *adjusted_y2)
7846 const ClutterLayoutInfo *info;
7848 info = _clutter_actor_get_layout_info_or_defaults (self);
7850 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7852 /* this will tweak natural_height to remove the margin, so that
7853 * adjust_for_alignment() will use the correct size
7855 adjust_for_margin (info->margin.top, info->margin.bottom,
7856 minimum_height, natural_height,
7860 /* we don't use effective_align() here, because text direction
7861 * only affects the horizontal axis
7863 adjust_for_alignment (info->y_align,
7870 /* looks for a cached size request for this for_size. If not
7871 * found, returns the oldest entry so it can be overwritten */
7873 _clutter_actor_get_cached_size_request (gfloat for_size,
7874 SizeRequest *cached_size_requests,
7875 SizeRequest **result)
7879 *result = &cached_size_requests[0];
7881 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7885 sr = &cached_size_requests[i];
7888 sr->for_size == for_size)
7890 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7894 else if (sr->age < (*result)->age)
7900 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7906 * clutter_actor_get_preferred_width:
7907 * @self: A #ClutterActor
7908 * @for_height: available height when computing the preferred width,
7909 * or a negative value to indicate that no height is defined
7910 * @min_width_p: (out) (allow-none): return location for minimum width,
7912 * @natural_width_p: (out) (allow-none): return location for the natural
7915 * Computes the requested minimum and natural widths for an actor,
7916 * optionally depending on the specified height, or if they are
7917 * already computed, returns the cached values.
7919 * An actor may not get its request - depending on the layout
7920 * manager that's in effect.
7922 * A request should not incorporate the actor's scale or anchor point;
7923 * those transformations do not affect layout, only rendering.
7928 clutter_actor_get_preferred_width (ClutterActor *self,
7930 gfloat *min_width_p,
7931 gfloat *natural_width_p)
7933 float request_min_width, request_natural_width;
7934 SizeRequest *cached_size_request;
7935 const ClutterLayoutInfo *info;
7936 ClutterActorPrivate *priv;
7937 gboolean found_in_cache;
7939 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7943 info = _clutter_actor_get_layout_info_or_defaults (self);
7945 /* we shortcircuit the case of a fixed size set using set_width() */
7946 if (priv->min_width_set && priv->natural_width_set)
7948 if (min_width_p != NULL)
7949 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7951 if (natural_width_p != NULL)
7952 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7957 /* the remaining cases are:
7959 * - either min_width or natural_width have been set
7960 * - neither min_width or natural_width have been set
7962 * in both cases, we go through the cache (and through the actor in case
7963 * of cache misses) and determine the authoritative value depending on
7967 if (!priv->needs_width_request)
7970 _clutter_actor_get_cached_size_request (for_height,
7971 priv->width_requests,
7972 &cached_size_request);
7976 /* if the actor needs a width request we use the first slot */
7977 found_in_cache = FALSE;
7978 cached_size_request = &priv->width_requests[0];
7981 if (!found_in_cache)
7983 gfloat minimum_width, natural_width;
7984 ClutterActorClass *klass;
7986 minimum_width = natural_width = 0;
7988 /* adjust for the margin */
7989 if (for_height >= 0)
7991 for_height -= (info->margin.top + info->margin.bottom);
7996 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7998 klass = CLUTTER_ACTOR_GET_CLASS (self);
7999 klass->get_preferred_width (self, for_height,
8003 /* adjust for the margin */
8004 minimum_width += (info->margin.left + info->margin.right);
8005 natural_width += (info->margin.left + info->margin.right);
8007 /* Due to accumulated float errors, it's better not to warn
8008 * on this, but just fix it.
8010 if (natural_width < minimum_width)
8011 natural_width = minimum_width;
8013 cached_size_request->min_size = minimum_width;
8014 cached_size_request->natural_size = natural_width;
8015 cached_size_request->for_size = for_height;
8016 cached_size_request->age = priv->cached_width_age;
8018 priv->cached_width_age += 1;
8019 priv->needs_width_request = FALSE;
8022 if (!priv->min_width_set)
8023 request_min_width = cached_size_request->min_size;
8025 request_min_width = info->min_width;
8027 if (!priv->natural_width_set)
8028 request_natural_width = cached_size_request->natural_size;
8030 request_natural_width = info->natural_width;
8033 *min_width_p = request_min_width;
8035 if (natural_width_p)
8036 *natural_width_p = request_natural_width;
8040 * clutter_actor_get_preferred_height:
8041 * @self: A #ClutterActor
8042 * @for_width: available width to assume in computing desired height,
8043 * or a negative value to indicate that no width is defined
8044 * @min_height_p: (out) (allow-none): return location for minimum height,
8046 * @natural_height_p: (out) (allow-none): return location for natural
8049 * Computes the requested minimum and natural heights for an actor,
8050 * or if they are already computed, returns the cached values.
8052 * An actor may not get its request - depending on the layout
8053 * manager that's in effect.
8055 * A request should not incorporate the actor's scale or anchor point;
8056 * those transformations do not affect layout, only rendering.
8061 clutter_actor_get_preferred_height (ClutterActor *self,
8063 gfloat *min_height_p,
8064 gfloat *natural_height_p)
8066 float request_min_height, request_natural_height;
8067 SizeRequest *cached_size_request;
8068 const ClutterLayoutInfo *info;
8069 ClutterActorPrivate *priv;
8070 gboolean found_in_cache;
8072 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8076 info = _clutter_actor_get_layout_info_or_defaults (self);
8078 /* we shortcircuit the case of a fixed size set using set_height() */
8079 if (priv->min_height_set && priv->natural_height_set)
8081 if (min_height_p != NULL)
8082 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8084 if (natural_height_p != NULL)
8085 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8090 /* the remaining cases are:
8092 * - either min_height or natural_height have been set
8093 * - neither min_height or natural_height have been set
8095 * in both cases, we go through the cache (and through the actor in case
8096 * of cache misses) and determine the authoritative value depending on
8100 if (!priv->needs_height_request)
8103 _clutter_actor_get_cached_size_request (for_width,
8104 priv->height_requests,
8105 &cached_size_request);
8109 found_in_cache = FALSE;
8110 cached_size_request = &priv->height_requests[0];
8113 if (!found_in_cache)
8115 gfloat minimum_height, natural_height;
8116 ClutterActorClass *klass;
8118 minimum_height = natural_height = 0;
8120 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8122 /* adjust for margin */
8125 for_width -= (info->margin.left + info->margin.right);
8130 klass = CLUTTER_ACTOR_GET_CLASS (self);
8131 klass->get_preferred_height (self, for_width,
8135 /* adjust for margin */
8136 minimum_height += (info->margin.top + info->margin.bottom);
8137 natural_height += (info->margin.top + info->margin.bottom);
8139 /* Due to accumulated float errors, it's better not to warn
8140 * on this, but just fix it.
8142 if (natural_height < minimum_height)
8143 natural_height = minimum_height;
8145 cached_size_request->min_size = minimum_height;
8146 cached_size_request->natural_size = natural_height;
8147 cached_size_request->for_size = for_width;
8148 cached_size_request->age = priv->cached_height_age;
8150 priv->cached_height_age += 1;
8151 priv->needs_height_request = FALSE;
8154 if (!priv->min_height_set)
8155 request_min_height = cached_size_request->min_size;
8157 request_min_height = info->min_height;
8159 if (!priv->natural_height_set)
8160 request_natural_height = cached_size_request->natural_size;
8162 request_natural_height = info->natural_height;
8165 *min_height_p = request_min_height;
8167 if (natural_height_p)
8168 *natural_height_p = request_natural_height;
8172 * clutter_actor_get_allocation_box:
8173 * @self: A #ClutterActor
8174 * @box: (out): the function fills this in with the actor's allocation
8176 * Gets the layout box an actor has been assigned. The allocation can
8177 * only be assumed valid inside a paint() method; anywhere else, it
8178 * may be out-of-date.
8180 * An allocation does not incorporate the actor's scale or anchor point;
8181 * those transformations do not affect layout, only rendering.
8183 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8184 * of functions inside the implementation of the get_preferred_width()
8185 * or get_preferred_height() virtual functions.</note>
8190 clutter_actor_get_allocation_box (ClutterActor *self,
8191 ClutterActorBox *box)
8193 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8195 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8196 * which limits calling get_allocation to inside paint() basically; or
8197 * we can 2) force a layout, which could be expensive if someone calls
8198 * get_allocation somewhere silly; or we can 3) just return the latest
8199 * value, allowing it to be out-of-date, and assume people know what
8202 * The least-surprises approach that keeps existing code working is
8203 * likely to be 2). People can end up doing some inefficient things,
8204 * though, and in general code that requires 2) is probably broken.
8207 /* this implements 2) */
8208 if (G_UNLIKELY (self->priv->needs_allocation))
8210 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8212 /* do not queue a relayout on an unparented actor */
8214 _clutter_stage_maybe_relayout (stage);
8217 /* commenting out the code above and just keeping this assigment
8220 *box = self->priv->allocation;
8224 * clutter_actor_get_allocation_geometry:
8225 * @self: A #ClutterActor
8226 * @geom: (out): allocation geometry in pixels
8228 * Gets the layout box an actor has been assigned. The allocation can
8229 * only be assumed valid inside a paint() method; anywhere else, it
8230 * may be out-of-date.
8232 * An allocation does not incorporate the actor's scale or anchor point;
8233 * those transformations do not affect layout, only rendering.
8235 * The returned rectangle is in pixels.
8240 clutter_actor_get_allocation_geometry (ClutterActor *self,
8241 ClutterGeometry *geom)
8243 ClutterActorBox box;
8245 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8246 g_return_if_fail (geom != NULL);
8248 clutter_actor_get_allocation_box (self, &box);
8250 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8251 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8252 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8253 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8257 clutter_actor_update_constraints (ClutterActor *self,
8258 ClutterActorBox *allocation)
8260 ClutterActorPrivate *priv = self->priv;
8261 const GList *constraints, *l;
8263 if (priv->constraints == NULL)
8266 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8267 for (l = constraints; l != NULL; l = l->next)
8269 ClutterConstraint *constraint = l->data;
8270 ClutterActorMeta *meta = l->data;
8272 if (clutter_actor_meta_get_enabled (meta))
8274 _clutter_constraint_update_allocation (constraint,
8278 CLUTTER_NOTE (LAYOUT,
8279 "Allocation of '%s' after constraint '%s': "
8280 "{ %.2f, %.2f, %.2f, %.2f }",
8281 _clutter_actor_get_debug_name (self),
8282 _clutter_actor_meta_get_debug_name (meta),
8292 * clutter_actor_adjust_allocation:
8293 * @self: a #ClutterActor
8294 * @allocation: (inout): the allocation to adjust
8296 * Adjusts the passed allocation box taking into account the actor's
8297 * layout information, like alignment, expansion, and margin.
8300 clutter_actor_adjust_allocation (ClutterActor *self,
8301 ClutterActorBox *allocation)
8303 ClutterActorBox adj_allocation;
8304 float alloc_width, alloc_height;
8305 float min_width, min_height;
8306 float nat_width, nat_height;
8307 ClutterRequestMode req_mode;
8309 adj_allocation = *allocation;
8311 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8313 /* we want to hit the cache, so we use the public API */
8314 req_mode = clutter_actor_get_request_mode (self);
8316 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8318 clutter_actor_get_preferred_width (self, -1,
8321 clutter_actor_get_preferred_height (self, alloc_width,
8325 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8327 clutter_actor_get_preferred_height (self, -1,
8330 clutter_actor_get_preferred_height (self, alloc_height,
8335 #ifdef CLUTTER_ENABLE_DEBUG
8336 /* warn about underallocations */
8337 if (_clutter_diagnostic_enabled () &&
8338 (floorf (min_width - alloc_width) > 0 ||
8339 floorf (min_height - alloc_height) > 0))
8341 ClutterActor *parent = clutter_actor_get_parent (self);
8343 /* the only actors that are allowed to be underallocated are the Stage,
8344 * as it doesn't have an implicit size, and Actors that specifically
8345 * told us that they want to opt-out from layout control mechanisms
8346 * through the NO_LAYOUT escape hatch.
8348 if (parent != NULL &&
8349 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8351 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8352 "of %.2f x %.2f from its parent actor '%s', but its "
8353 "requested minimum size is of %.2f x %.2f",
8354 _clutter_actor_get_debug_name (self),
8355 alloc_width, alloc_height,
8356 _clutter_actor_get_debug_name (parent),
8357 min_width, min_height);
8362 clutter_actor_adjust_width (self,
8366 &adj_allocation.x2);
8368 clutter_actor_adjust_height (self,
8372 &adj_allocation.y2);
8374 /* we maintain the invariant that an allocation cannot be adjusted
8375 * to be outside the parent-given box
8377 if (adj_allocation.x1 < allocation->x1 ||
8378 adj_allocation.y1 < allocation->y1 ||
8379 adj_allocation.x2 > allocation->x2 ||
8380 adj_allocation.y2 > allocation->y2)
8382 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8383 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8384 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8385 _clutter_actor_get_debug_name (self),
8386 adj_allocation.x1, adj_allocation.y1,
8387 adj_allocation.x2 - adj_allocation.x1,
8388 adj_allocation.y2 - adj_allocation.y1,
8389 allocation->x1, allocation->y1,
8390 allocation->x2 - allocation->x1,
8391 allocation->y2 - allocation->y1);
8395 *allocation = adj_allocation;
8399 * clutter_actor_allocate:
8400 * @self: A #ClutterActor
8401 * @box: new allocation of the actor, in parent-relative coordinates
8402 * @flags: flags that control the allocation
8404 * Called by the parent of an actor to assign the actor its size.
8405 * Should never be called by applications (except when implementing
8406 * a container or layout manager).
8408 * Actors can know from their allocation box whether they have moved
8409 * with respect to their parent actor. The @flags parameter describes
8410 * additional information about the allocation, for instance whether
8411 * the parent has moved with respect to the stage, for example because
8412 * a grandparent's origin has moved.
8417 clutter_actor_allocate (ClutterActor *self,
8418 const ClutterActorBox *box,
8419 ClutterAllocationFlags flags)
8421 ClutterActorPrivate *priv;
8422 ClutterActorClass *klass;
8423 ClutterActorBox old_allocation, real_allocation;
8424 gboolean origin_changed, child_moved, size_changed;
8425 gboolean stage_allocation_changed;
8427 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8428 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8430 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8431 "which isn't a descendent of the stage!\n",
8432 self, _clutter_actor_get_debug_name (self));
8438 old_allocation = priv->allocation;
8439 real_allocation = *box;
8441 /* constraints are allowed to modify the allocation only here; we do
8442 * this prior to all the other checks so that we can bail out if the
8443 * allocation did not change
8445 clutter_actor_update_constraints (self, &real_allocation);
8447 /* adjust the allocation depending on the align/margin properties */
8448 clutter_actor_adjust_allocation (self, &real_allocation);
8450 if (real_allocation.x2 < real_allocation.x1 ||
8451 real_allocation.y2 < real_allocation.y1)
8453 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8454 _clutter_actor_get_debug_name (self),
8455 real_allocation.x2 - real_allocation.x1,
8456 real_allocation.y2 - real_allocation.y1);
8459 /* we allow 0-sized actors, but not negative-sized ones */
8460 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8461 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8463 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8465 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8466 real_allocation.y1 != old_allocation.y1);
8468 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8469 real_allocation.y2 != old_allocation.y2);
8471 if (origin_changed || child_moved || size_changed)
8472 stage_allocation_changed = TRUE;
8474 stage_allocation_changed = FALSE;
8476 /* If we get an allocation "out of the blue"
8477 * (we did not queue relayout), then we want to
8478 * ignore it. But if we have needs_allocation set,
8479 * we want to guarantee that allocate() virtual
8480 * method is always called, i.e. that queue_relayout()
8481 * always results in an allocate() invocation on
8484 * The optimization here is to avoid re-allocating
8485 * actors that did not queue relayout and were
8488 if (!priv->needs_allocation && !stage_allocation_changed)
8490 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8494 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8495 * clutter_actor_allocate(), it indicates whether the parent has its
8496 * absolute origin moved; when passed in to ClutterActor::allocate()
8497 * virtual method though, it indicates whether the child has its
8498 * absolute origin moved. So we set it when child_moved is TRUE
8501 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8503 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8505 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8506 _clutter_actor_get_debug_name (self));
8508 klass = CLUTTER_ACTOR_GET_CLASS (self);
8509 klass->allocate (self, &real_allocation, flags);
8511 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8513 if (stage_allocation_changed)
8514 clutter_actor_queue_redraw (self);
8518 * clutter_actor_set_allocation:
8519 * @self: a #ClutterActor
8520 * @box: a #ClutterActorBox
8521 * @flags: allocation flags
8523 * Stores the allocation of @self as defined by @box.
8525 * This function can only be called from within the implementation of
8526 * the #ClutterActorClass.allocate() virtual function.
8528 * The allocation should have been adjusted to take into account constraints,
8529 * alignment, and margin properties. If you are implementing a #ClutterActor
8530 * subclass that provides its own layout management policy for its children
8531 * instead of using a #ClutterLayoutManager delegate, you should not call
8532 * this function on the children of @self; instead, you should call
8533 * clutter_actor_allocate(), which will adjust the allocation box for
8536 * This function should only be used by subclasses of #ClutterActor
8537 * that wish to store their allocation but cannot chain up to the
8538 * parent's implementation; the default implementation of the
8539 * #ClutterActorClass.allocate() virtual function will call this
8542 * It is important to note that, while chaining up was the recommended
8543 * behaviour for #ClutterActor subclasses prior to the introduction of
8544 * this function, it is recommended to call clutter_actor_set_allocation()
8547 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8548 * to handle the allocation of its children, this function will call
8549 * the clutter_layout_manager_allocate() function only if the
8550 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8551 * expected that the subclass will call clutter_layout_manager_allocate()
8552 * by itself. For instance, the following code:
8556 * my_actor_allocate (ClutterActor *actor,
8557 * const ClutterActorBox *allocation,
8558 * ClutterAllocationFlags flags)
8560 * ClutterActorBox new_alloc;
8561 * ClutterAllocationFlags new_flags;
8563 * adjust_allocation (allocation, &new_alloc);
8565 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8567 * /* this will use the layout manager set on the actor */
8568 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8572 * is equivalent to this:
8576 * my_actor_allocate (ClutterActor *actor,
8577 * const ClutterActorBox *allocation,
8578 * ClutterAllocationFlags flags)
8580 * ClutterLayoutManager *layout;
8581 * ClutterActorBox new_alloc;
8583 * adjust_allocation (allocation, &new_alloc);
8585 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8587 * layout = clutter_actor_get_layout_manager (actor);
8588 * clutter_layout_manager_allocate (layout,
8589 * CLUTTER_CONTAINER (actor),
8598 clutter_actor_set_allocation (ClutterActor *self,
8599 const ClutterActorBox *box,
8600 ClutterAllocationFlags flags)
8602 ClutterActorPrivate *priv;
8605 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8606 g_return_if_fail (box != NULL);
8608 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8610 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8611 "can only be called from within the implementation of "
8612 "the ClutterActor::allocate() virtual function.");
8618 g_object_freeze_notify (G_OBJECT (self));
8620 changed = clutter_actor_set_allocation_internal (self, box, flags);
8622 /* we allocate our children before we notify changes in our geometry,
8623 * so that people connecting to properties will be able to get valid
8624 * data out of the sub-tree of the scene graph that has this actor at
8627 clutter_actor_maybe_layout_children (self, box, flags);
8631 ClutterActorBox signal_box = priv->allocation;
8632 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8634 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8639 g_object_thaw_notify (G_OBJECT (self));
8643 * clutter_actor_set_geometry:
8644 * @self: A #ClutterActor
8645 * @geometry: A #ClutterGeometry
8647 * Sets the actor's fixed position and forces its minimum and natural
8648 * size, in pixels. This means the untransformed actor will have the
8649 * given geometry. This is the same as calling clutter_actor_set_position()
8650 * and clutter_actor_set_size().
8652 * Deprecated: 1.10: Use clutter_actor_set_position() and
8653 * clutter_actor_set_size() instead.
8656 clutter_actor_set_geometry (ClutterActor *self,
8657 const ClutterGeometry *geometry)
8659 g_object_freeze_notify (G_OBJECT (self));
8661 clutter_actor_set_position (self, geometry->x, geometry->y);
8662 clutter_actor_set_size (self, geometry->width, geometry->height);
8664 g_object_thaw_notify (G_OBJECT (self));
8668 * clutter_actor_get_geometry:
8669 * @self: A #ClutterActor
8670 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8672 * Gets the size and position of an actor relative to its parent
8673 * actor. This is the same as calling clutter_actor_get_position() and
8674 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8675 * requested size and position if the actor's allocation is invalid.
8677 * Deprecated: 1.10: Use clutter_actor_get_position() and
8678 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8682 clutter_actor_get_geometry (ClutterActor *self,
8683 ClutterGeometry *geometry)
8685 gfloat x, y, width, height;
8687 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8688 g_return_if_fail (geometry != NULL);
8690 clutter_actor_get_position (self, &x, &y);
8691 clutter_actor_get_size (self, &width, &height);
8693 geometry->x = (int) x;
8694 geometry->y = (int) y;
8695 geometry->width = (int) width;
8696 geometry->height = (int) height;
8700 * clutter_actor_set_position:
8701 * @self: A #ClutterActor
8702 * @x: New left position of actor in pixels.
8703 * @y: New top position of actor in pixels.
8705 * Sets the actor's fixed position in pixels relative to any parent
8708 * If a layout manager is in use, this position will override the
8709 * layout manager and force a fixed position.
8712 clutter_actor_set_position (ClutterActor *self,
8716 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8718 g_object_freeze_notify (G_OBJECT (self));
8720 clutter_actor_set_x (self, x);
8721 clutter_actor_set_y (self, y);
8723 g_object_thaw_notify (G_OBJECT (self));
8727 * clutter_actor_get_fixed_position_set:
8728 * @self: A #ClutterActor
8730 * Checks whether an actor has a fixed position set (and will thus be
8731 * unaffected by any layout manager).
8733 * Return value: %TRUE if the fixed position is set on the actor
8738 clutter_actor_get_fixed_position_set (ClutterActor *self)
8740 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8742 return self->priv->position_set;
8746 * clutter_actor_set_fixed_position_set:
8747 * @self: A #ClutterActor
8748 * @is_set: whether to use fixed position
8750 * Sets whether an actor has a fixed position set (and will thus be
8751 * unaffected by any layout manager).
8756 clutter_actor_set_fixed_position_set (ClutterActor *self,
8759 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8761 if (self->priv->position_set == (is_set != FALSE))
8764 self->priv->position_set = is_set != FALSE;
8765 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8767 clutter_actor_queue_relayout (self);
8771 * clutter_actor_move_by:
8772 * @self: A #ClutterActor
8773 * @dx: Distance to move Actor on X axis.
8774 * @dy: Distance to move Actor on Y axis.
8776 * Moves an actor by the specified distance relative to its current
8777 * position in pixels.
8779 * This function modifies the fixed position of an actor and thus removes
8780 * it from any layout management. Another way to move an actor is with an
8781 * anchor point, see clutter_actor_set_anchor_point().
8786 clutter_actor_move_by (ClutterActor *self,
8790 const ClutterLayoutInfo *info;
8793 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8795 info = _clutter_actor_get_layout_info_or_defaults (self);
8799 clutter_actor_set_position (self, x + dx, y + dy);
8803 clutter_actor_set_min_width (ClutterActor *self,
8806 ClutterActorPrivate *priv = self->priv;
8807 ClutterActorBox old = { 0, };
8808 ClutterLayoutInfo *info;
8810 /* if we are setting the size on a top-level actor and the
8811 * backend only supports static top-levels (e.g. framebuffers)
8812 * then we ignore the passed value and we override it with
8813 * the stage implementation's preferred size.
8815 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8816 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8819 info = _clutter_actor_get_layout_info (self);
8821 if (priv->min_width_set && min_width == info->min_width)
8824 g_object_freeze_notify (G_OBJECT (self));
8826 clutter_actor_store_old_geometry (self, &old);
8828 info->min_width = min_width;
8829 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8830 clutter_actor_set_min_width_set (self, TRUE);
8832 clutter_actor_notify_if_geometry_changed (self, &old);
8834 g_object_thaw_notify (G_OBJECT (self));
8836 clutter_actor_queue_relayout (self);
8840 clutter_actor_set_min_height (ClutterActor *self,
8844 ClutterActorPrivate *priv = self->priv;
8845 ClutterActorBox old = { 0, };
8846 ClutterLayoutInfo *info;
8848 /* if we are setting the size on a top-level actor and the
8849 * backend only supports static top-levels (e.g. framebuffers)
8850 * then we ignore the passed value and we override it with
8851 * the stage implementation's preferred size.
8853 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8854 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8857 info = _clutter_actor_get_layout_info (self);
8859 if (priv->min_height_set && min_height == info->min_height)
8862 g_object_freeze_notify (G_OBJECT (self));
8864 clutter_actor_store_old_geometry (self, &old);
8866 info->min_height = min_height;
8867 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8868 clutter_actor_set_min_height_set (self, TRUE);
8870 clutter_actor_notify_if_geometry_changed (self, &old);
8872 g_object_thaw_notify (G_OBJECT (self));
8874 clutter_actor_queue_relayout (self);
8878 clutter_actor_set_natural_width (ClutterActor *self,
8879 gfloat natural_width)
8881 ClutterActorPrivate *priv = self->priv;
8882 ClutterActorBox old = { 0, };
8883 ClutterLayoutInfo *info;
8885 /* if we are setting the size on a top-level actor and the
8886 * backend only supports static top-levels (e.g. framebuffers)
8887 * then we ignore the passed value and we override it with
8888 * the stage implementation's preferred size.
8890 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8891 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8894 info = _clutter_actor_get_layout_info (self);
8896 if (priv->natural_width_set && natural_width == info->natural_width)
8899 g_object_freeze_notify (G_OBJECT (self));
8901 clutter_actor_store_old_geometry (self, &old);
8903 info->natural_width = natural_width;
8904 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8905 clutter_actor_set_natural_width_set (self, TRUE);
8907 clutter_actor_notify_if_geometry_changed (self, &old);
8909 g_object_thaw_notify (G_OBJECT (self));
8911 clutter_actor_queue_relayout (self);
8915 clutter_actor_set_natural_height (ClutterActor *self,
8916 gfloat natural_height)
8918 ClutterActorPrivate *priv = self->priv;
8919 ClutterActorBox old = { 0, };
8920 ClutterLayoutInfo *info;
8922 /* if we are setting the size on a top-level actor and the
8923 * backend only supports static top-levels (e.g. framebuffers)
8924 * then we ignore the passed value and we override it with
8925 * the stage implementation's preferred size.
8927 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8928 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8931 info = _clutter_actor_get_layout_info (self);
8933 if (priv->natural_height_set && natural_height == info->natural_height)
8936 g_object_freeze_notify (G_OBJECT (self));
8938 clutter_actor_store_old_geometry (self, &old);
8940 info->natural_height = natural_height;
8941 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8942 clutter_actor_set_natural_height_set (self, TRUE);
8944 clutter_actor_notify_if_geometry_changed (self, &old);
8946 g_object_thaw_notify (G_OBJECT (self));
8948 clutter_actor_queue_relayout (self);
8952 clutter_actor_set_min_width_set (ClutterActor *self,
8953 gboolean use_min_width)
8955 ClutterActorPrivate *priv = self->priv;
8956 ClutterActorBox old = { 0, };
8958 if (priv->min_width_set == (use_min_width != FALSE))
8961 clutter_actor_store_old_geometry (self, &old);
8963 priv->min_width_set = use_min_width != FALSE;
8964 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8966 clutter_actor_notify_if_geometry_changed (self, &old);
8968 clutter_actor_queue_relayout (self);
8972 clutter_actor_set_min_height_set (ClutterActor *self,
8973 gboolean use_min_height)
8975 ClutterActorPrivate *priv = self->priv;
8976 ClutterActorBox old = { 0, };
8978 if (priv->min_height_set == (use_min_height != FALSE))
8981 clutter_actor_store_old_geometry (self, &old);
8983 priv->min_height_set = use_min_height != FALSE;
8984 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8986 clutter_actor_notify_if_geometry_changed (self, &old);
8988 clutter_actor_queue_relayout (self);
8992 clutter_actor_set_natural_width_set (ClutterActor *self,
8993 gboolean use_natural_width)
8995 ClutterActorPrivate *priv = self->priv;
8996 ClutterActorBox old = { 0, };
8998 if (priv->natural_width_set == (use_natural_width != FALSE))
9001 clutter_actor_store_old_geometry (self, &old);
9003 priv->natural_width_set = use_natural_width != FALSE;
9004 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9006 clutter_actor_notify_if_geometry_changed (self, &old);
9008 clutter_actor_queue_relayout (self);
9012 clutter_actor_set_natural_height_set (ClutterActor *self,
9013 gboolean use_natural_height)
9015 ClutterActorPrivate *priv = self->priv;
9016 ClutterActorBox old = { 0, };
9018 if (priv->natural_height_set == (use_natural_height != FALSE))
9021 clutter_actor_store_old_geometry (self, &old);
9023 priv->natural_height_set = use_natural_height != FALSE;
9024 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9026 clutter_actor_notify_if_geometry_changed (self, &old);
9028 clutter_actor_queue_relayout (self);
9032 * clutter_actor_set_request_mode:
9033 * @self: a #ClutterActor
9034 * @mode: the request mode
9036 * Sets the geometry request mode of @self.
9038 * The @mode determines the order for invoking
9039 * clutter_actor_get_preferred_width() and
9040 * clutter_actor_get_preferred_height()
9045 clutter_actor_set_request_mode (ClutterActor *self,
9046 ClutterRequestMode mode)
9048 ClutterActorPrivate *priv;
9050 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9054 if (priv->request_mode == mode)
9057 priv->request_mode = mode;
9059 priv->needs_width_request = TRUE;
9060 priv->needs_height_request = TRUE;
9062 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9064 clutter_actor_queue_relayout (self);
9068 * clutter_actor_get_request_mode:
9069 * @self: a #ClutterActor
9071 * Retrieves the geometry request mode of @self
9073 * Return value: the request mode for the actor
9078 clutter_actor_get_request_mode (ClutterActor *self)
9080 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9081 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9083 return self->priv->request_mode;
9086 /* variant of set_width() without checks and without notification
9087 * freeze+thaw, for internal usage only
9090 clutter_actor_set_width_internal (ClutterActor *self,
9095 /* the Stage will use the :min-width to control the minimum
9096 * width to be resized to, so we should not be setting it
9097 * along with the :natural-width
9099 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9100 clutter_actor_set_min_width (self, width);
9102 clutter_actor_set_natural_width (self, width);
9106 /* we only unset the :natural-width for the Stage */
9107 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9108 clutter_actor_set_min_width_set (self, FALSE);
9110 clutter_actor_set_natural_width_set (self, FALSE);
9114 /* variant of set_height() without checks and without notification
9115 * freeze+thaw, for internal usage only
9118 clutter_actor_set_height_internal (ClutterActor *self,
9123 /* see the comment above in set_width_internal() */
9124 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9125 clutter_actor_set_min_height (self, height);
9127 clutter_actor_set_natural_height (self, height);
9131 /* see the comment above in set_width_internal() */
9132 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9133 clutter_actor_set_min_height_set (self, FALSE);
9135 clutter_actor_set_natural_height_set (self, FALSE);
9140 * clutter_actor_set_size:
9141 * @self: A #ClutterActor
9142 * @width: New width of actor in pixels, or -1
9143 * @height: New height of actor in pixels, or -1
9145 * Sets the actor's size request in pixels. This overrides any
9146 * "normal" size request the actor would have. For example
9147 * a text actor might normally request the size of the text;
9148 * this function would force a specific size instead.
9150 * If @width and/or @height are -1 the actor will use its
9151 * "normal" size request instead of overriding it, i.e.
9152 * you can "unset" the size with -1.
9154 * This function sets or unsets both the minimum and natural size.
9157 clutter_actor_set_size (ClutterActor *self,
9161 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9163 g_object_freeze_notify (G_OBJECT (self));
9165 clutter_actor_set_width (self, width);
9166 clutter_actor_set_height (self, height);
9168 g_object_thaw_notify (G_OBJECT (self));
9172 * clutter_actor_get_size:
9173 * @self: A #ClutterActor
9174 * @width: (out) (allow-none): return location for the width, or %NULL.
9175 * @height: (out) (allow-none): return location for the height, or %NULL.
9177 * This function tries to "do what you mean" and return
9178 * the size an actor will have. If the actor has a valid
9179 * allocation, the allocation will be returned; otherwise,
9180 * the actors natural size request will be returned.
9182 * If you care whether you get the request vs. the allocation, you
9183 * should probably call a different function like
9184 * clutter_actor_get_allocation_box() or
9185 * clutter_actor_get_preferred_width().
9190 clutter_actor_get_size (ClutterActor *self,
9194 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9197 *width = clutter_actor_get_width (self);
9200 *height = clutter_actor_get_height (self);
9204 * clutter_actor_get_position:
9205 * @self: a #ClutterActor
9206 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9207 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9209 * This function tries to "do what you mean" and tell you where the
9210 * actor is, prior to any transformations. Retrieves the fixed
9211 * position of an actor in pixels, if one has been set; otherwise, if
9212 * the allocation is valid, returns the actor's allocated position;
9213 * otherwise, returns 0,0.
9215 * The returned position is in pixels.
9220 clutter_actor_get_position (ClutterActor *self,
9224 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9227 *x = clutter_actor_get_x (self);
9230 *y = clutter_actor_get_y (self);
9234 * clutter_actor_get_transformed_position:
9235 * @self: A #ClutterActor
9236 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9237 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9239 * Gets the absolute position of an actor, in pixels relative to the stage.
9244 clutter_actor_get_transformed_position (ClutterActor *self,
9251 v1.x = v1.y = v1.z = 0;
9252 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9262 * clutter_actor_get_transformed_size:
9263 * @self: A #ClutterActor
9264 * @width: (out) (allow-none): return location for the width, or %NULL
9265 * @height: (out) (allow-none): return location for the height, or %NULL
9267 * Gets the absolute size of an actor in pixels, taking into account the
9270 * If the actor has a valid allocation, the allocated size will be used.
9271 * If the actor has not a valid allocation then the preferred size will
9272 * be transformed and returned.
9274 * If you want the transformed allocation, see
9275 * clutter_actor_get_abs_allocation_vertices() instead.
9277 * <note>When the actor (or one of its ancestors) is rotated around the
9278 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9279 * as a generic quadrangle; in that case this function returns the size
9280 * of the smallest rectangle that encapsulates the entire quad. Please
9281 * note that in this case no assumptions can be made about the relative
9282 * position of this envelope to the absolute position of the actor, as
9283 * returned by clutter_actor_get_transformed_position(); if you need this
9284 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9285 * to get the coords of the actual quadrangle.</note>
9290 clutter_actor_get_transformed_size (ClutterActor *self,
9294 ClutterActorPrivate *priv;
9296 gfloat x_min, x_max, y_min, y_max;
9299 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9303 /* if the actor hasn't been allocated yet, get the preferred
9304 * size and transform that
9306 if (priv->needs_allocation)
9308 gfloat natural_width, natural_height;
9309 ClutterActorBox box;
9311 /* Make a fake allocation to transform.
9313 * NB: _clutter_actor_transform_and_project_box expects a box in
9314 * the actor's coordinate space... */
9319 natural_width = natural_height = 0;
9320 clutter_actor_get_preferred_size (self, NULL, NULL,
9324 box.x2 = natural_width;
9325 box.y2 = natural_height;
9327 _clutter_actor_transform_and_project_box (self, &box, v);
9330 clutter_actor_get_abs_allocation_vertices (self, v);
9332 x_min = x_max = v[0].x;
9333 y_min = y_max = v[0].y;
9335 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9351 *width = x_max - x_min;
9354 *height = y_max - y_min;
9358 * clutter_actor_get_width:
9359 * @self: A #ClutterActor
9361 * Retrieves the width of a #ClutterActor.
9363 * If the actor has a valid allocation, this function will return the
9364 * width of the allocated area given to the actor.
9366 * If the actor does not have a valid allocation, this function will
9367 * return the actor's natural width, that is the preferred width of
9370 * If you care whether you get the preferred width or the width that
9371 * has been assigned to the actor, you should probably call a different
9372 * function like clutter_actor_get_allocation_box() to retrieve the
9373 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9376 * If an actor has a fixed width, for instance a width that has been
9377 * assigned using clutter_actor_set_width(), the width returned will
9378 * be the same value.
9380 * Return value: the width of the actor, in pixels
9383 clutter_actor_get_width (ClutterActor *self)
9385 ClutterActorPrivate *priv;
9387 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9391 if (priv->needs_allocation)
9393 gfloat natural_width = 0;
9395 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9396 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9399 gfloat natural_height = 0;
9401 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9402 clutter_actor_get_preferred_width (self, natural_height,
9407 return natural_width;
9410 return priv->allocation.x2 - priv->allocation.x1;
9414 * clutter_actor_get_height:
9415 * @self: A #ClutterActor
9417 * Retrieves the height of a #ClutterActor.
9419 * If the actor has a valid allocation, this function will return the
9420 * height of the allocated area given to the actor.
9422 * If the actor does not have a valid allocation, this function will
9423 * return the actor's natural height, that is the preferred height of
9426 * If you care whether you get the preferred height or the height that
9427 * has been assigned to the actor, you should probably call a different
9428 * function like clutter_actor_get_allocation_box() to retrieve the
9429 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9432 * If an actor has a fixed height, for instance a height that has been
9433 * assigned using clutter_actor_set_height(), the height returned will
9434 * be the same value.
9436 * Return value: the height of the actor, in pixels
9439 clutter_actor_get_height (ClutterActor *self)
9441 ClutterActorPrivate *priv;
9443 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9447 if (priv->needs_allocation)
9449 gfloat natural_height = 0;
9451 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9453 gfloat natural_width = 0;
9455 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9456 clutter_actor_get_preferred_height (self, natural_width,
9457 NULL, &natural_height);
9460 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9462 return natural_height;
9465 return priv->allocation.y2 - priv->allocation.y1;
9469 * clutter_actor_set_width:
9470 * @self: A #ClutterActor
9471 * @width: Requested new width for the actor, in pixels, or -1
9473 * Forces a width on an actor, causing the actor's preferred width
9474 * and height (if any) to be ignored.
9476 * If @width is -1 the actor will use its preferred width request
9477 * instead of overriding it, i.e. you can "unset" the width with -1.
9479 * This function sets both the minimum and natural size of the actor.
9484 clutter_actor_set_width (ClutterActor *self,
9487 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9489 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9493 /* minor optimization: if we don't have a duration
9494 * then we can skip the get_width() below, to avoid
9495 * the chance of going through get_preferred_width()
9496 * just to jump to a new desired width.
9498 if (clutter_actor_get_easing_duration (self) == 0)
9500 g_object_freeze_notify (G_OBJECT (self));
9502 clutter_actor_set_width_internal (self, width);
9504 g_object_thaw_notify (G_OBJECT (self));
9509 cur_size = clutter_actor_get_width (self);
9511 _clutter_actor_create_transition (self,
9512 obj_props[PROP_WIDTH],
9517 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9521 * clutter_actor_set_height:
9522 * @self: A #ClutterActor
9523 * @height: Requested new height for the actor, in pixels, or -1
9525 * Forces a height on an actor, causing the actor's preferred width
9526 * and height (if any) to be ignored.
9528 * If @height is -1 the actor will use its preferred height instead of
9529 * overriding it, i.e. you can "unset" the height with -1.
9531 * This function sets both the minimum and natural size of the actor.
9536 clutter_actor_set_height (ClutterActor *self,
9539 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9541 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9545 /* see the comment in clutter_actor_set_width() above */
9546 if (clutter_actor_get_easing_duration (self) == 0)
9548 g_object_freeze_notify (G_OBJECT (self));
9550 clutter_actor_set_height_internal (self, height);
9552 g_object_thaw_notify (G_OBJECT (self));
9557 cur_size = clutter_actor_get_height (self);
9559 _clutter_actor_create_transition (self,
9560 obj_props[PROP_HEIGHT],
9565 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9569 clutter_actor_set_x_internal (ClutterActor *self,
9572 ClutterActorPrivate *priv = self->priv;
9573 ClutterLayoutInfo *linfo;
9574 ClutterActorBox old = { 0, };
9576 linfo = _clutter_actor_get_layout_info (self);
9578 if (priv->position_set && linfo->fixed_x == x)
9581 clutter_actor_store_old_geometry (self, &old);
9584 clutter_actor_set_fixed_position_set (self, TRUE);
9586 clutter_actor_notify_if_geometry_changed (self, &old);
9588 clutter_actor_queue_relayout (self);
9592 clutter_actor_set_y_internal (ClutterActor *self,
9595 ClutterActorPrivate *priv = self->priv;
9596 ClutterLayoutInfo *linfo;
9597 ClutterActorBox old = { 0, };
9599 linfo = _clutter_actor_get_layout_info (self);
9601 if (priv->position_set && linfo->fixed_y == y)
9604 clutter_actor_store_old_geometry (self, &old);
9607 clutter_actor_set_fixed_position_set (self, TRUE);
9609 clutter_actor_notify_if_geometry_changed (self, &old);
9611 clutter_actor_queue_relayout (self);
9615 * clutter_actor_set_x:
9616 * @self: a #ClutterActor
9617 * @x: the actor's position on the X axis
9619 * Sets the actor's X coordinate, relative to its parent, in pixels.
9621 * Overrides any layout manager and forces a fixed position for
9624 * The #ClutterActor:x property is animatable.
9629 clutter_actor_set_x (ClutterActor *self,
9632 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9634 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9636 float cur_position = clutter_actor_get_x (self);
9638 _clutter_actor_create_transition (self, obj_props[PROP_X],
9643 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9647 * clutter_actor_set_y:
9648 * @self: a #ClutterActor
9649 * @y: the actor's position on the Y axis
9651 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9653 * Overrides any layout manager and forces a fixed position for
9656 * The #ClutterActor:y property is animatable.
9661 clutter_actor_set_y (ClutterActor *self,
9664 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9666 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9668 float cur_position = clutter_actor_get_y (self);
9670 _clutter_actor_create_transition (self, obj_props[PROP_Y],
9675 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9679 * clutter_actor_get_x:
9680 * @self: A #ClutterActor
9682 * Retrieves the X coordinate of a #ClutterActor.
9684 * This function tries to "do what you mean", by returning the
9685 * correct value depending on the actor's state.
9687 * If the actor has a valid allocation, this function will return
9688 * the X coordinate of the origin of the allocation box.
9690 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9691 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9692 * function will return that coordinate.
9694 * If both the allocation and a fixed position are missing, this function
9697 * Return value: the X coordinate, in pixels, ignoring any
9698 * transformation (i.e. scaling, rotation)
9701 clutter_actor_get_x (ClutterActor *self)
9703 ClutterActorPrivate *priv;
9705 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9709 if (priv->needs_allocation)
9711 if (priv->position_set)
9713 const ClutterLayoutInfo *info;
9715 info = _clutter_actor_get_layout_info_or_defaults (self);
9717 return info->fixed_x;
9723 return priv->allocation.x1;
9727 * clutter_actor_get_y:
9728 * @self: A #ClutterActor
9730 * Retrieves the Y coordinate of a #ClutterActor.
9732 * This function tries to "do what you mean", by returning the
9733 * correct value depending on the actor's state.
9735 * If the actor has a valid allocation, this function will return
9736 * the Y coordinate of the origin of the allocation box.
9738 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9739 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9740 * function will return that coordinate.
9742 * If both the allocation and a fixed position are missing, this function
9745 * Return value: the Y coordinate, in pixels, ignoring any
9746 * transformation (i.e. scaling, rotation)
9749 clutter_actor_get_y (ClutterActor *self)
9751 ClutterActorPrivate *priv;
9753 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9757 if (priv->needs_allocation)
9759 if (priv->position_set)
9761 const ClutterLayoutInfo *info;
9763 info = _clutter_actor_get_layout_info_or_defaults (self);
9765 return info->fixed_y;
9771 return priv->allocation.y1;
9775 * clutter_actor_set_scale:
9776 * @self: A #ClutterActor
9777 * @scale_x: double factor to scale actor by horizontally.
9778 * @scale_y: double factor to scale actor by vertically.
9780 * Scales an actor with the given factors. The scaling is relative to
9781 * the scale center and the anchor point. The scale center is
9782 * unchanged by this function and defaults to 0,0.
9784 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9790 clutter_actor_set_scale (ClutterActor *self,
9794 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9796 g_object_freeze_notify (G_OBJECT (self));
9798 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9799 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9801 g_object_thaw_notify (G_OBJECT (self));
9805 * clutter_actor_set_scale_full:
9806 * @self: A #ClutterActor
9807 * @scale_x: double factor to scale actor by horizontally.
9808 * @scale_y: double factor to scale actor by vertically.
9809 * @center_x: X coordinate of the center of the scale.
9810 * @center_y: Y coordinate of the center of the scale
9812 * Scales an actor with the given factors around the given center
9813 * point. The center point is specified in pixels relative to the
9814 * anchor point (usually the top left corner of the actor).
9816 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9822 clutter_actor_set_scale_full (ClutterActor *self,
9828 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9830 g_object_freeze_notify (G_OBJECT (self));
9832 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9833 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9834 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9835 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9837 g_object_thaw_notify (G_OBJECT (self));
9841 * clutter_actor_set_scale_with_gravity:
9842 * @self: A #ClutterActor
9843 * @scale_x: double factor to scale actor by horizontally.
9844 * @scale_y: double factor to scale actor by vertically.
9845 * @gravity: the location of the scale center expressed as a compass
9848 * Scales an actor with the given factors around the given
9849 * center point. The center point is specified as one of the compass
9850 * directions in #ClutterGravity. For example, setting it to north
9851 * will cause the top of the actor to remain unchanged and the rest of
9852 * the actor to expand left, right and downwards.
9854 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9860 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9863 ClutterGravity gravity)
9865 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9867 g_object_freeze_notify (G_OBJECT (self));
9869 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9870 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9871 clutter_actor_set_scale_gravity (self, gravity);
9873 g_object_thaw_notify (G_OBJECT (self));
9877 * clutter_actor_get_scale:
9878 * @self: A #ClutterActor
9879 * @scale_x: (out) (allow-none): Location to store horizonal
9880 * scale factor, or %NULL.
9881 * @scale_y: (out) (allow-none): Location to store vertical
9882 * scale factor, or %NULL.
9884 * Retrieves an actors scale factors.
9889 clutter_actor_get_scale (ClutterActor *self,
9893 const ClutterTransformInfo *info;
9895 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9897 info = _clutter_actor_get_transform_info_or_defaults (self);
9900 *scale_x = info->scale_x;
9903 *scale_y = info->scale_y;
9907 * clutter_actor_get_scale_center:
9908 * @self: A #ClutterActor
9909 * @center_x: (out) (allow-none): Location to store the X position
9910 * of the scale center, or %NULL.
9911 * @center_y: (out) (allow-none): Location to store the Y position
9912 * of the scale center, or %NULL.
9914 * Retrieves the scale center coordinate in pixels relative to the top
9915 * left corner of the actor. If the scale center was specified using a
9916 * #ClutterGravity this will calculate the pixel offset using the
9917 * current size of the actor.
9922 clutter_actor_get_scale_center (ClutterActor *self,
9926 const ClutterTransformInfo *info;
9928 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9930 info = _clutter_actor_get_transform_info_or_defaults (self);
9932 clutter_anchor_coord_get_units (self, &info->scale_center,
9939 * clutter_actor_get_scale_gravity:
9940 * @self: A #ClutterActor
9942 * Retrieves the scale center as a compass direction. If the scale
9943 * center was specified in pixels or units this will return
9944 * %CLUTTER_GRAVITY_NONE.
9946 * Return value: the scale gravity
9951 clutter_actor_get_scale_gravity (ClutterActor *self)
9953 const ClutterTransformInfo *info;
9955 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9957 info = _clutter_actor_get_transform_info_or_defaults (self);
9959 return clutter_anchor_coord_get_gravity (&info->scale_center);
9963 clutter_actor_set_opacity_internal (ClutterActor *self,
9966 ClutterActorPrivate *priv = self->priv;
9968 if (priv->opacity != opacity)
9970 priv->opacity = opacity;
9972 /* Queue a redraw from the flatten effect so that it can use
9973 its cached image if available instead of having to redraw the
9974 actual actor. If it doesn't end up using the FBO then the
9975 effect is still able to continue the paint anyway. If there
9976 is no flatten effect yet then this is equivalent to queueing
9978 _clutter_actor_queue_redraw_full (self,
9981 priv->flatten_effect);
9983 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9988 * clutter_actor_set_opacity:
9989 * @self: A #ClutterActor
9990 * @opacity: New opacity value for the actor.
9992 * Sets the actor's opacity, with zero being completely transparent and
9993 * 255 (0xff) being fully opaque.
9995 * The #ClutterActor:opacity property is animatable.
9998 clutter_actor_set_opacity (ClutterActor *self,
10001 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10003 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10005 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10006 self->priv->opacity,
10010 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10014 * clutter_actor_get_paint_opacity_internal:
10015 * @self: a #ClutterActor
10017 * Retrieves the absolute opacity of the actor, as it appears on the stage
10019 * This function does not do type checks
10021 * Return value: the absolute opacity of the actor
10024 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10026 ClutterActorPrivate *priv = self->priv;
10027 ClutterActor *parent;
10029 /* override the top-level opacity to always be 255; even in
10030 * case of ClutterStage:use-alpha being TRUE we want the rest
10031 * of the scene to be painted
10033 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10036 if (priv->opacity_override >= 0)
10037 return priv->opacity_override;
10039 parent = priv->parent;
10041 /* Factor in the actual actors opacity with parents */
10042 if (parent != NULL)
10044 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10046 if (opacity != 0xff)
10047 return (opacity * priv->opacity) / 0xff;
10050 return priv->opacity;
10055 * clutter_actor_get_paint_opacity:
10056 * @self: A #ClutterActor
10058 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10060 * This function traverses the hierarchy chain and composites the opacity of
10061 * the actor with that of its parents.
10063 * This function is intended for subclasses to use in the paint virtual
10064 * function, to paint themselves with the correct opacity.
10066 * Return value: The actor opacity value.
10071 clutter_actor_get_paint_opacity (ClutterActor *self)
10073 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10075 return clutter_actor_get_paint_opacity_internal (self);
10079 * clutter_actor_get_opacity:
10080 * @self: a #ClutterActor
10082 * Retrieves the opacity value of an actor, as set by
10083 * clutter_actor_set_opacity().
10085 * For retrieving the absolute opacity of the actor inside a paint
10086 * virtual function, see clutter_actor_get_paint_opacity().
10088 * Return value: the opacity of the actor
10091 clutter_actor_get_opacity (ClutterActor *self)
10093 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10095 return self->priv->opacity;
10099 * clutter_actor_set_offscreen_redirect:
10100 * @self: A #ClutterActor
10101 * @redirect: New offscreen redirect flags for the actor.
10103 * Defines the circumstances where the actor should be redirected into
10104 * an offscreen image. The offscreen image is used to flatten the
10105 * actor into a single image while painting for two main reasons.
10106 * Firstly, when the actor is painted a second time without any of its
10107 * contents changing it can simply repaint the cached image without
10108 * descending further down the actor hierarchy. Secondly, it will make
10109 * the opacity look correct even if there are overlapping primitives
10112 * Caching the actor could in some cases be a performance win and in
10113 * some cases be a performance lose so it is important to determine
10114 * which value is right for an actor before modifying this value. For
10115 * example, there is never any reason to flatten an actor that is just
10116 * a single texture (such as a #ClutterTexture) because it is
10117 * effectively already cached in an image so the offscreen would be
10118 * redundant. Also if the actor contains primitives that are far apart
10119 * with a large transparent area in the middle (such as a large
10120 * CluterGroup with a small actor in the top left and a small actor in
10121 * the bottom right) then the cached image will contain the entire
10122 * image of the large area and the paint will waste time blending all
10123 * of the transparent pixels in the middle.
10125 * The default method of implementing opacity on a container simply
10126 * forwards on the opacity to all of the children. If the children are
10127 * overlapping then it will appear as if they are two separate glassy
10128 * objects and there will be a break in the color where they
10129 * overlap. By redirecting to an offscreen buffer it will be as if the
10130 * two opaque objects are combined into one and then made transparent
10131 * which is usually what is expected.
10133 * The image below demonstrates the difference between redirecting and
10134 * not. The image shows two Clutter groups, each containing a red and
10135 * a green rectangle which overlap. The opacity on the group is set to
10136 * 128 (which is 50%). When the offscreen redirect is not used, the
10137 * red rectangle can be seen through the blue rectangle as if the two
10138 * rectangles were separately transparent. When the redirect is used
10139 * the group as a whole is transparent instead so the red rectangle is
10140 * not visible where they overlap.
10142 * <figure id="offscreen-redirect">
10143 * <title>Sample of using an offscreen redirect for transparency</title>
10144 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10147 * The default value for this property is 0, so we effectively will
10148 * never redirect an actor offscreen by default. This means that there
10149 * are times that transparent actors may look glassy as described
10150 * above. The reason this is the default is because there is a
10151 * performance trade off between quality and performance here. In many
10152 * cases the default form of glassy opacity looks good enough, but if
10153 * it's not you will need to set the
10154 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10155 * redirection for opacity.
10157 * Custom actors that don't contain any overlapping primitives are
10158 * recommended to override the has_overlaps() virtual to return %FALSE
10159 * for maximum efficiency.
10164 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10165 ClutterOffscreenRedirect redirect)
10167 ClutterActorPrivate *priv;
10169 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10173 if (priv->offscreen_redirect != redirect)
10175 priv->offscreen_redirect = redirect;
10177 /* Queue a redraw from the effect so that it can use its cached
10178 image if available instead of having to redraw the actual
10179 actor. If it doesn't end up using the FBO then the effect is
10180 still able to continue the paint anyway. If there is no
10181 effect then this is equivalent to queuing a full redraw */
10182 _clutter_actor_queue_redraw_full (self,
10185 priv->flatten_effect);
10187 g_object_notify_by_pspec (G_OBJECT (self),
10188 obj_props[PROP_OFFSCREEN_REDIRECT]);
10193 * clutter_actor_get_offscreen_redirect:
10194 * @self: a #ClutterActor
10196 * Retrieves whether to redirect the actor to an offscreen buffer, as
10197 * set by clutter_actor_set_offscreen_redirect().
10199 * Return value: the value of the offscreen-redirect property of the actor
10203 ClutterOffscreenRedirect
10204 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10206 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10208 return self->priv->offscreen_redirect;
10212 * clutter_actor_set_name:
10213 * @self: A #ClutterActor
10214 * @name: Textual tag to apply to actor
10216 * Sets the given name to @self. The name can be used to identify
10220 clutter_actor_set_name (ClutterActor *self,
10223 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10225 g_free (self->priv->name);
10226 self->priv->name = g_strdup (name);
10228 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10232 * clutter_actor_get_name:
10233 * @self: A #ClutterActor
10235 * Retrieves the name of @self.
10237 * Return value: the name of the actor, or %NULL. The returned string is
10238 * owned by the actor and should not be modified or freed.
10241 clutter_actor_get_name (ClutterActor *self)
10243 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10245 return self->priv->name;
10249 * clutter_actor_get_gid:
10250 * @self: A #ClutterActor
10252 * Retrieves the unique id for @self.
10254 * Return value: Globally unique value for this object instance.
10258 * Deprecated: 1.8: The id is not used any longer.
10261 clutter_actor_get_gid (ClutterActor *self)
10263 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10265 return self->priv->id;
10269 clutter_actor_set_depth_internal (ClutterActor *self,
10272 ClutterTransformInfo *info;
10274 info = _clutter_actor_get_transform_info (self);
10276 if (info->depth != depth)
10278 /* Sets Z value - XXX 2.0: should we invert? */
10279 info->depth = depth;
10281 self->priv->transform_valid = FALSE;
10283 /* FIXME - remove this crap; sadly, there are still containers
10284 * in Clutter that depend on this utter brain damage
10286 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10288 clutter_actor_queue_redraw (self);
10290 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10295 * clutter_actor_set_depth:
10296 * @self: a #ClutterActor
10299 * Sets the Z coordinate of @self to @depth.
10301 * The unit used by @depth is dependant on the perspective setup. See
10302 * also clutter_stage_set_perspective().
10305 clutter_actor_set_depth (ClutterActor *self,
10308 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10310 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10312 const ClutterTransformInfo *info;
10314 info = _clutter_actor_get_transform_info_or_defaults (self);
10316 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10321 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10323 clutter_actor_queue_redraw (self);
10327 * clutter_actor_get_depth:
10328 * @self: a #ClutterActor
10330 * Retrieves the depth of @self.
10332 * Return value: the depth of the actor
10335 clutter_actor_get_depth (ClutterActor *self)
10337 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10339 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10343 * clutter_actor_set_rotation:
10344 * @self: a #ClutterActor
10345 * @axis: the axis of rotation
10346 * @angle: the angle of rotation
10347 * @x: X coordinate of the rotation center
10348 * @y: Y coordinate of the rotation center
10349 * @z: Z coordinate of the rotation center
10351 * Sets the rotation angle of @self around the given axis.
10353 * The rotation center coordinates used depend on the value of @axis:
10355 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10356 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10357 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10360 * The rotation coordinates are relative to the anchor point of the
10361 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10362 * point is set, the upper left corner is assumed as the origin.
10367 clutter_actor_set_rotation (ClutterActor *self,
10368 ClutterRotateAxis axis,
10376 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10382 g_object_freeze_notify (G_OBJECT (self));
10384 clutter_actor_set_rotation_angle (self, axis, angle);
10385 clutter_actor_set_rotation_center_internal (self, axis, &v);
10387 g_object_thaw_notify (G_OBJECT (self));
10391 * clutter_actor_set_z_rotation_from_gravity:
10392 * @self: a #ClutterActor
10393 * @angle: the angle of rotation
10394 * @gravity: the center point of the rotation
10396 * Sets the rotation angle of @self around the Z axis using the center
10397 * point specified as a compass point. For example to rotate such that
10398 * the center of the actor remains static you can use
10399 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10400 * will move accordingly.
10405 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10407 ClutterGravity gravity)
10409 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10411 if (gravity == CLUTTER_GRAVITY_NONE)
10412 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10415 GObject *obj = G_OBJECT (self);
10416 ClutterTransformInfo *info;
10418 info = _clutter_actor_get_transform_info (self);
10420 g_object_freeze_notify (obj);
10422 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10424 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10425 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10426 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10428 g_object_thaw_notify (obj);
10433 * clutter_actor_get_rotation:
10434 * @self: a #ClutterActor
10435 * @axis: the axis of rotation
10436 * @x: (out): return value for the X coordinate of the center of rotation
10437 * @y: (out): return value for the Y coordinate of the center of rotation
10438 * @z: (out): return value for the Z coordinate of the center of rotation
10440 * Retrieves the angle and center of rotation on the given axis,
10441 * set using clutter_actor_set_rotation().
10443 * Return value: the angle of rotation
10448 clutter_actor_get_rotation (ClutterActor *self,
10449 ClutterRotateAxis axis,
10454 const ClutterTransformInfo *info;
10455 const AnchorCoord *anchor_coord;
10456 gdouble retval = 0;
10458 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10460 info = _clutter_actor_get_transform_info_or_defaults (self);
10464 case CLUTTER_X_AXIS:
10465 anchor_coord = &info->rx_center;
10466 retval = info->rx_angle;
10469 case CLUTTER_Y_AXIS:
10470 anchor_coord = &info->ry_center;
10471 retval = info->ry_angle;
10474 case CLUTTER_Z_AXIS:
10475 anchor_coord = &info->rz_center;
10476 retval = info->rz_angle;
10480 anchor_coord = NULL;
10485 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10491 * clutter_actor_get_z_rotation_gravity:
10492 * @self: A #ClutterActor
10494 * Retrieves the center for the rotation around the Z axis as a
10495 * compass direction. If the center was specified in pixels or units
10496 * this will return %CLUTTER_GRAVITY_NONE.
10498 * Return value: the Z rotation center
10503 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10505 const ClutterTransformInfo *info;
10507 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10509 info = _clutter_actor_get_transform_info_or_defaults (self);
10511 return clutter_anchor_coord_get_gravity (&info->rz_center);
10515 * clutter_actor_set_clip:
10516 * @self: A #ClutterActor
10517 * @xoff: X offset of the clip rectangle
10518 * @yoff: Y offset of the clip rectangle
10519 * @width: Width of the clip rectangle
10520 * @height: Height of the clip rectangle
10522 * Sets clip area for @self. The clip area is always computed from the
10523 * upper left corner of the actor, even if the anchor point is set
10529 clutter_actor_set_clip (ClutterActor *self,
10535 ClutterActorPrivate *priv;
10537 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10541 if (priv->has_clip &&
10542 priv->clip.x == xoff &&
10543 priv->clip.y == yoff &&
10544 priv->clip.width == width &&
10545 priv->clip.height == height)
10548 priv->clip.x = xoff;
10549 priv->clip.y = yoff;
10550 priv->clip.width = width;
10551 priv->clip.height = height;
10553 priv->has_clip = TRUE;
10555 clutter_actor_queue_redraw (self);
10557 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10558 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10562 * clutter_actor_remove_clip:
10563 * @self: A #ClutterActor
10565 * Removes clip area from @self.
10568 clutter_actor_remove_clip (ClutterActor *self)
10570 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10572 if (!self->priv->has_clip)
10575 self->priv->has_clip = FALSE;
10577 clutter_actor_queue_redraw (self);
10579 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10583 * clutter_actor_has_clip:
10584 * @self: a #ClutterActor
10586 * Determines whether the actor has a clip area set or not.
10588 * Return value: %TRUE if the actor has a clip area set.
10593 clutter_actor_has_clip (ClutterActor *self)
10595 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10597 return self->priv->has_clip;
10601 * clutter_actor_get_clip:
10602 * @self: a #ClutterActor
10603 * @xoff: (out) (allow-none): return location for the X offset of
10604 * the clip rectangle, or %NULL
10605 * @yoff: (out) (allow-none): return location for the Y offset of
10606 * the clip rectangle, or %NULL
10607 * @width: (out) (allow-none): return location for the width of
10608 * the clip rectangle, or %NULL
10609 * @height: (out) (allow-none): return location for the height of
10610 * the clip rectangle, or %NULL
10612 * Gets the clip area for @self, if any is set
10617 clutter_actor_get_clip (ClutterActor *self,
10623 ClutterActorPrivate *priv;
10625 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10629 if (!priv->has_clip)
10633 *xoff = priv->clip.x;
10636 *yoff = priv->clip.y;
10639 *width = priv->clip.width;
10641 if (height != NULL)
10642 *height = priv->clip.height;
10646 * clutter_actor_get_children:
10647 * @self: a #ClutterActor
10649 * Retrieves the list of children of @self.
10651 * Return value: (transfer container) (element-type ClutterActor): A newly
10652 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10658 clutter_actor_get_children (ClutterActor *self)
10660 ClutterActor *iter;
10663 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10665 /* we walk the list backward so that we can use prepend(),
10668 for (iter = self->priv->last_child, res = NULL;
10670 iter = iter->priv->prev_sibling)
10672 res = g_list_prepend (res, iter);
10679 * insert_child_at_depth:
10680 * @self: a #ClutterActor
10681 * @child: a #ClutterActor
10683 * Inserts @child inside the list of children held by @self, using
10684 * the depth as the insertion criteria.
10686 * This sadly makes the insertion not O(1), but we can keep the
10687 * list sorted so that the painters algorithm we use for painting
10688 * the children will work correctly.
10691 insert_child_at_depth (ClutterActor *self,
10692 ClutterActor *child,
10693 gpointer dummy G_GNUC_UNUSED)
10695 ClutterActor *iter;
10698 child->priv->parent = self;
10701 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10703 /* special-case the first child */
10704 if (self->priv->n_children == 0)
10706 self->priv->first_child = child;
10707 self->priv->last_child = child;
10709 child->priv->next_sibling = NULL;
10710 child->priv->prev_sibling = NULL;
10715 /* Find the right place to insert the child so that it will still be
10716 sorted and the child will be after all of the actors at the same
10718 for (iter = self->priv->first_child;
10720 iter = iter->priv->next_sibling)
10725 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10727 if (iter_depth > child_depth)
10733 ClutterActor *tmp = iter->priv->prev_sibling;
10736 tmp->priv->next_sibling = child;
10738 /* Insert the node before the found one */
10739 child->priv->prev_sibling = iter->priv->prev_sibling;
10740 child->priv->next_sibling = iter;
10741 iter->priv->prev_sibling = child;
10745 ClutterActor *tmp = self->priv->last_child;
10748 tmp->priv->next_sibling = child;
10750 /* insert the node at the end of the list */
10751 child->priv->prev_sibling = self->priv->last_child;
10752 child->priv->next_sibling = NULL;
10755 if (child->priv->prev_sibling == NULL)
10756 self->priv->first_child = child;
10758 if (child->priv->next_sibling == NULL)
10759 self->priv->last_child = child;
10763 insert_child_at_index (ClutterActor *self,
10764 ClutterActor *child,
10767 gint index_ = GPOINTER_TO_INT (data_);
10769 child->priv->parent = self;
10773 ClutterActor *tmp = self->priv->first_child;
10776 tmp->priv->prev_sibling = child;
10778 child->priv->prev_sibling = NULL;
10779 child->priv->next_sibling = tmp;
10781 else if (index_ < 0 || index_ >= self->priv->n_children)
10783 ClutterActor *tmp = self->priv->last_child;
10786 tmp->priv->next_sibling = child;
10788 child->priv->prev_sibling = tmp;
10789 child->priv->next_sibling = NULL;
10793 ClutterActor *iter;
10796 for (iter = self->priv->first_child, i = 0;
10798 iter = iter->priv->next_sibling, i += 1)
10802 ClutterActor *tmp = iter->priv->prev_sibling;
10804 child->priv->prev_sibling = tmp;
10805 child->priv->next_sibling = iter;
10807 iter->priv->prev_sibling = child;
10810 tmp->priv->next_sibling = child;
10817 if (child->priv->prev_sibling == NULL)
10818 self->priv->first_child = child;
10820 if (child->priv->next_sibling == NULL)
10821 self->priv->last_child = child;
10825 insert_child_above (ClutterActor *self,
10826 ClutterActor *child,
10829 ClutterActor *sibling = data;
10831 child->priv->parent = self;
10833 if (sibling == NULL)
10834 sibling = self->priv->last_child;
10836 child->priv->prev_sibling = sibling;
10838 if (sibling != NULL)
10840 ClutterActor *tmp = sibling->priv->next_sibling;
10842 child->priv->next_sibling = tmp;
10845 tmp->priv->prev_sibling = child;
10847 sibling->priv->next_sibling = child;
10850 child->priv->next_sibling = NULL;
10852 if (child->priv->prev_sibling == NULL)
10853 self->priv->first_child = child;
10855 if (child->priv->next_sibling == NULL)
10856 self->priv->last_child = child;
10860 insert_child_below (ClutterActor *self,
10861 ClutterActor *child,
10864 ClutterActor *sibling = data;
10866 child->priv->parent = self;
10868 if (sibling == NULL)
10869 sibling = self->priv->first_child;
10871 child->priv->next_sibling = sibling;
10873 if (sibling != NULL)
10875 ClutterActor *tmp = sibling->priv->prev_sibling;
10877 child->priv->prev_sibling = tmp;
10880 tmp->priv->next_sibling = child;
10882 sibling->priv->prev_sibling = child;
10885 child->priv->prev_sibling = NULL;
10887 if (child->priv->prev_sibling == NULL)
10888 self->priv->first_child = child;
10890 if (child->priv->next_sibling == NULL)
10891 self->priv->last_child = child;
10894 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10895 ClutterActor *child,
10899 ADD_CHILD_CREATE_META = 1 << 0,
10900 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10901 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10902 ADD_CHILD_CHECK_STATE = 1 << 3,
10903 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10905 /* default flags for public API */
10906 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10907 ADD_CHILD_EMIT_PARENT_SET |
10908 ADD_CHILD_EMIT_ACTOR_ADDED |
10909 ADD_CHILD_CHECK_STATE |
10910 ADD_CHILD_NOTIFY_FIRST_LAST,
10912 /* flags for legacy/deprecated API */
10913 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10914 ADD_CHILD_CHECK_STATE |
10915 ADD_CHILD_NOTIFY_FIRST_LAST
10916 } ClutterActorAddChildFlags;
10919 * clutter_actor_add_child_internal:
10920 * @self: a #ClutterActor
10921 * @child: a #ClutterActor
10922 * @flags: control flags for actions
10923 * @add_func: delegate function
10924 * @data: (closure): data to pass to @add_func
10926 * Adds @child to the list of children of @self.
10928 * The actual insertion inside the list is delegated to @add_func: this
10929 * function will just set up the state, perform basic checks, and emit
10932 * The @flags argument is used to perform additional operations.
10935 clutter_actor_add_child_internal (ClutterActor *self,
10936 ClutterActor *child,
10937 ClutterActorAddChildFlags flags,
10938 ClutterActorAddChildFunc add_func,
10941 ClutterTextDirection text_dir;
10942 gboolean create_meta;
10943 gboolean emit_parent_set, emit_actor_added;
10944 gboolean check_state;
10945 gboolean notify_first_last;
10946 ClutterActor *old_first_child, *old_last_child;
10948 if (child->priv->parent != NULL)
10950 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10951 "use clutter_actor_remove_child() first.",
10952 _clutter_actor_get_debug_name (child),
10953 _clutter_actor_get_debug_name (child->priv->parent));
10957 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10959 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10960 "a child of another actor.",
10961 _clutter_actor_get_debug_name (child));
10966 /* XXX - this check disallows calling methods that change the stacking
10967 * order within the destruction sequence, by triggering a critical
10968 * warning first, and leaving the actor in an undefined state, which
10969 * then ends up being caught by an assertion.
10971 * the reproducible sequence is:
10973 * - actor gets destroyed;
10974 * - another actor, linked to the first, will try to change the
10975 * stacking order of the first actor;
10976 * - changing the stacking order is a composite operation composed
10977 * by the following steps:
10978 * 1. ref() the child;
10979 * 2. remove_child_internal(), which removes the reference;
10980 * 3. add_child_internal(), which adds a reference;
10981 * - the state of the actor is not changed between (2) and (3), as
10982 * it could be an expensive recomputation;
10983 * - if (3) bails out, then the actor is in an undefined state, but
10985 * - the destruction sequence terminates, but the actor is unparented
10986 * while its state indicates being parented instead.
10987 * - assertion failure.
10989 * the obvious fix would be to decompose each set_child_*_sibling()
10990 * method into proper remove_child()/add_child(), with state validation;
10991 * this may cause excessive work, though, and trigger a cascade of other
10992 * bugs in code that assumes that a change in the stacking order is an
10993 * atomic operation.
10995 * another potential fix is to just remove this check here, and let
10996 * code doing stacking order changes inside the destruction sequence
10997 * of an actor continue doing the work.
10999 * the third fix is to silently bail out early from every
11000 * set_child_*_sibling() and set_child_at_index() method, and avoid
11003 * I have a preference for the second solution, since it involves the
11004 * least amount of work, and the least amount of code duplication.
11006 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11008 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11010 g_warning ("The actor '%s' is currently being destroyed, and "
11011 "cannot be added as a child of another actor.",
11012 _clutter_actor_get_debug_name (child));
11017 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11018 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11019 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11020 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11021 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11023 old_first_child = self->priv->first_child;
11024 old_last_child = self->priv->last_child;
11026 g_object_freeze_notify (G_OBJECT (self));
11029 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11031 g_object_ref_sink (child);
11032 child->priv->parent = NULL;
11033 child->priv->next_sibling = NULL;
11034 child->priv->prev_sibling = NULL;
11036 /* delegate the actual insertion */
11037 add_func (self, child, data);
11039 g_assert (child->priv->parent == self);
11041 self->priv->n_children += 1;
11043 self->priv->age += 1;
11045 /* if push_internal() has been called then we automatically set
11046 * the flag on the actor
11048 if (self->priv->internal_child)
11049 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11051 /* clutter_actor_reparent() will emit ::parent-set for us */
11052 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11053 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11057 /* If parent is mapped or realized, we need to also be mapped or
11058 * realized once we're inside the parent.
11060 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11062 /* propagate the parent's text direction to the child */
11063 text_dir = clutter_actor_get_text_direction (self);
11064 clutter_actor_set_text_direction (child, text_dir);
11067 if (child->priv->show_on_set_parent)
11068 clutter_actor_show (child);
11070 if (CLUTTER_ACTOR_IS_MAPPED (child))
11071 clutter_actor_queue_redraw (child);
11073 /* maintain the invariant that if an actor needs layout,
11074 * its parents do as well
11076 if (child->priv->needs_width_request ||
11077 child->priv->needs_height_request ||
11078 child->priv->needs_allocation)
11080 /* we work around the short-circuiting we do
11081 * in clutter_actor_queue_relayout() since we
11082 * want to force a relayout
11084 child->priv->needs_width_request = TRUE;
11085 child->priv->needs_height_request = TRUE;
11086 child->priv->needs_allocation = TRUE;
11088 clutter_actor_queue_relayout (child->priv->parent);
11091 if (emit_actor_added)
11092 g_signal_emit_by_name (self, "actor-added", child);
11094 if (notify_first_last)
11096 if (old_first_child != self->priv->first_child)
11097 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11099 if (old_last_child != self->priv->last_child)
11100 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11103 g_object_thaw_notify (G_OBJECT (self));
11107 * clutter_actor_add_child:
11108 * @self: a #ClutterActor
11109 * @child: a #ClutterActor
11111 * Adds @child to the children of @self.
11113 * This function will acquire a reference on @child that will only
11114 * be released when calling clutter_actor_remove_child().
11116 * This function will take into consideration the #ClutterActor:depth
11117 * of @child, and will keep the list of children sorted.
11119 * This function will emit the #ClutterContainer::actor-added signal
11125 clutter_actor_add_child (ClutterActor *self,
11126 ClutterActor *child)
11128 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11129 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11130 g_return_if_fail (self != child);
11131 g_return_if_fail (child->priv->parent == NULL);
11133 clutter_actor_add_child_internal (self, child,
11134 ADD_CHILD_DEFAULT_FLAGS,
11135 insert_child_at_depth,
11140 * clutter_actor_insert_child_at_index:
11141 * @self: a #ClutterActor
11142 * @child: a #ClutterActor
11143 * @index_: the index
11145 * Inserts @child into the list of children of @self, using the
11146 * given @index_. If @index_ is greater than the number of children
11147 * in @self, or is less than 0, then the new child is added at the end.
11149 * This function will acquire a reference on @child that will only
11150 * be released when calling clutter_actor_remove_child().
11152 * This function will not take into consideration the #ClutterActor:depth
11155 * This function will emit the #ClutterContainer::actor-added signal
11161 clutter_actor_insert_child_at_index (ClutterActor *self,
11162 ClutterActor *child,
11165 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11166 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11167 g_return_if_fail (self != child);
11168 g_return_if_fail (child->priv->parent == NULL);
11170 clutter_actor_add_child_internal (self, child,
11171 ADD_CHILD_DEFAULT_FLAGS,
11172 insert_child_at_index,
11173 GINT_TO_POINTER (index_));
11177 * clutter_actor_insert_child_above:
11178 * @self: a #ClutterActor
11179 * @child: a #ClutterActor
11180 * @sibling: (allow-none): a child of @self, or %NULL
11182 * Inserts @child into the list of children of @self, above another
11183 * child of @self or, if @sibling is %NULL, above all the children
11186 * This function will acquire a reference on @child that will only
11187 * be released when calling clutter_actor_remove_child().
11189 * This function will not take into consideration the #ClutterActor:depth
11192 * This function will emit the #ClutterContainer::actor-added signal
11198 clutter_actor_insert_child_above (ClutterActor *self,
11199 ClutterActor *child,
11200 ClutterActor *sibling)
11202 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11203 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11204 g_return_if_fail (self != child);
11205 g_return_if_fail (child != sibling);
11206 g_return_if_fail (child->priv->parent == NULL);
11207 g_return_if_fail (sibling == NULL ||
11208 (CLUTTER_IS_ACTOR (sibling) &&
11209 sibling->priv->parent == self));
11211 clutter_actor_add_child_internal (self, child,
11212 ADD_CHILD_DEFAULT_FLAGS,
11213 insert_child_above,
11218 * clutter_actor_insert_child_below:
11219 * @self: a #ClutterActor
11220 * @child: a #ClutterActor
11221 * @sibling: (allow-none): a child of @self, or %NULL
11223 * Inserts @child into the list of children of @self, below another
11224 * child of @self or, if @sibling is %NULL, below all the children
11227 * This function will acquire a reference on @child that will only
11228 * be released when calling clutter_actor_remove_child().
11230 * This function will not take into consideration the #ClutterActor:depth
11233 * This function will emit the #ClutterContainer::actor-added signal
11239 clutter_actor_insert_child_below (ClutterActor *self,
11240 ClutterActor *child,
11241 ClutterActor *sibling)
11243 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11244 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11245 g_return_if_fail (self != child);
11246 g_return_if_fail (child != sibling);
11247 g_return_if_fail (child->priv->parent == NULL);
11248 g_return_if_fail (sibling == NULL ||
11249 (CLUTTER_IS_ACTOR (sibling) &&
11250 sibling->priv->parent == self));
11252 clutter_actor_add_child_internal (self, child,
11253 ADD_CHILD_DEFAULT_FLAGS,
11254 insert_child_below,
11259 * clutter_actor_set_parent:
11260 * @self: A #ClutterActor
11261 * @parent: A new #ClutterActor parent
11263 * Sets the parent of @self to @parent.
11265 * This function will result in @parent acquiring a reference on @self,
11266 * eventually by sinking its floating reference first. The reference
11267 * will be released by clutter_actor_unparent().
11269 * This function should only be called by legacy #ClutterActor<!-- -->s
11270 * implementing the #ClutterContainer interface.
11272 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11275 clutter_actor_set_parent (ClutterActor *self,
11276 ClutterActor *parent)
11278 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11279 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11280 g_return_if_fail (self != parent);
11281 g_return_if_fail (self->priv->parent == NULL);
11283 /* as this function will be called inside ClutterContainer::add
11284 * implementations or when building up a composite actor, we have
11285 * to preserve the old behaviour, and not create child meta or
11286 * emit the ::actor-added signal, to avoid recursion or double
11289 clutter_actor_add_child_internal (parent, self,
11290 ADD_CHILD_LEGACY_FLAGS,
11291 insert_child_at_depth,
11296 * clutter_actor_get_parent:
11297 * @self: A #ClutterActor
11299 * Retrieves the parent of @self.
11301 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11302 * if no parent is set
11305 clutter_actor_get_parent (ClutterActor *self)
11307 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11309 return self->priv->parent;
11313 * clutter_actor_get_paint_visibility:
11314 * @self: A #ClutterActor
11316 * Retrieves the 'paint' visibility of an actor recursively checking for non
11319 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11321 * Return Value: %TRUE if the actor is visibile and will be painted.
11326 clutter_actor_get_paint_visibility (ClutterActor *actor)
11328 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11330 return CLUTTER_ACTOR_IS_MAPPED (actor);
11334 * clutter_actor_remove_child:
11335 * @self: a #ClutterActor
11336 * @child: a #ClutterActor
11338 * Removes @child from the children of @self.
11340 * This function will release the reference added by
11341 * clutter_actor_add_child(), so if you want to keep using @child
11342 * you will have to acquire a referenced on it before calling this
11345 * This function will emit the #ClutterContainer::actor-removed
11351 clutter_actor_remove_child (ClutterActor *self,
11352 ClutterActor *child)
11354 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11355 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11356 g_return_if_fail (self != child);
11357 g_return_if_fail (child->priv->parent != NULL);
11358 g_return_if_fail (child->priv->parent == self);
11360 clutter_actor_remove_child_internal (self, child,
11361 REMOVE_CHILD_DEFAULT_FLAGS);
11365 * clutter_actor_remove_all_children:
11366 * @self: a #ClutterActor
11368 * Removes all children of @self.
11370 * This function releases the reference added by inserting a child actor
11371 * in the list of children of @self.
11373 * If the reference count of a child drops to zero, the child will be
11374 * destroyed. If you want to ensure the destruction of all the children
11375 * of @self, use clutter_actor_destroy_all_children().
11380 clutter_actor_remove_all_children (ClutterActor *self)
11382 ClutterActorIter iter;
11384 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11386 if (self->priv->n_children == 0)
11389 g_object_freeze_notify (G_OBJECT (self));
11391 clutter_actor_iter_init (&iter, self);
11392 while (clutter_actor_iter_next (&iter, NULL))
11393 clutter_actor_iter_remove (&iter);
11395 g_object_thaw_notify (G_OBJECT (self));
11398 g_assert (self->priv->first_child == NULL);
11399 g_assert (self->priv->last_child == NULL);
11400 g_assert (self->priv->n_children == 0);
11404 * clutter_actor_destroy_all_children:
11405 * @self: a #ClutterActor
11407 * Destroys all children of @self.
11409 * This function releases the reference added by inserting a child
11410 * actor in the list of children of @self, and ensures that the
11411 * #ClutterActor::destroy signal is emitted on each child of the
11414 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11415 * when its reference count drops to 0; the default handler of the
11416 * #ClutterActor::destroy signal will destroy all the children of an
11417 * actor. This function ensures that all children are destroyed, instead
11418 * of just removed from @self, unlike clutter_actor_remove_all_children()
11419 * which will merely release the reference and remove each child.
11421 * Unless you acquired an additional reference on each child of @self
11422 * prior to calling clutter_actor_remove_all_children() and want to reuse
11423 * the actors, you should use clutter_actor_destroy_all_children() in
11424 * order to make sure that children are destroyed and signal handlers
11425 * are disconnected even in cases where circular references prevent this
11426 * from automatically happening through reference counting alone.
11431 clutter_actor_destroy_all_children (ClutterActor *self)
11433 ClutterActorIter iter;
11435 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11437 if (self->priv->n_children == 0)
11440 g_object_freeze_notify (G_OBJECT (self));
11442 clutter_actor_iter_init (&iter, self);
11443 while (clutter_actor_iter_next (&iter, NULL))
11444 clutter_actor_iter_destroy (&iter);
11446 g_object_thaw_notify (G_OBJECT (self));
11449 g_assert (self->priv->first_child == NULL);
11450 g_assert (self->priv->last_child == NULL);
11451 g_assert (self->priv->n_children == 0);
11454 typedef struct _InsertBetweenData {
11455 ClutterActor *prev_sibling;
11456 ClutterActor *next_sibling;
11457 } InsertBetweenData;
11460 insert_child_between (ClutterActor *self,
11461 ClutterActor *child,
11464 InsertBetweenData *data = data_;
11465 ClutterActor *prev_sibling = data->prev_sibling;
11466 ClutterActor *next_sibling = data->next_sibling;
11468 child->priv->parent = self;
11469 child->priv->prev_sibling = prev_sibling;
11470 child->priv->next_sibling = next_sibling;
11472 if (prev_sibling != NULL)
11473 prev_sibling->priv->next_sibling = child;
11475 if (next_sibling != NULL)
11476 next_sibling->priv->prev_sibling = child;
11478 if (child->priv->prev_sibling == NULL)
11479 self->priv->first_child = child;
11481 if (child->priv->next_sibling == NULL)
11482 self->priv->last_child = child;
11486 * clutter_actor_replace_child:
11487 * @self: a #ClutterActor
11488 * @old_child: the child of @self to replace
11489 * @new_child: the #ClutterActor to replace @old_child
11491 * Replaces @old_child with @new_child in the list of children of @self.
11496 clutter_actor_replace_child (ClutterActor *self,
11497 ClutterActor *old_child,
11498 ClutterActor *new_child)
11500 ClutterActor *prev_sibling, *next_sibling;
11501 InsertBetweenData clos;
11503 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11504 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11505 g_return_if_fail (old_child->priv->parent == self);
11506 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11507 g_return_if_fail (old_child != new_child);
11508 g_return_if_fail (new_child != self);
11509 g_return_if_fail (new_child->priv->parent == NULL);
11511 prev_sibling = old_child->priv->prev_sibling;
11512 next_sibling = old_child->priv->next_sibling;
11513 clutter_actor_remove_child_internal (self, old_child,
11514 REMOVE_CHILD_DEFAULT_FLAGS);
11516 clos.prev_sibling = prev_sibling;
11517 clos.next_sibling = next_sibling;
11518 clutter_actor_add_child_internal (self, new_child,
11519 ADD_CHILD_DEFAULT_FLAGS,
11520 insert_child_between,
11525 * clutter_actor_unparent:
11526 * @self: a #ClutterActor
11528 * Removes the parent of @self.
11530 * This will cause the parent of @self to release the reference
11531 * acquired when calling clutter_actor_set_parent(), so if you
11532 * want to keep @self you will have to acquire a reference of
11533 * your own, through g_object_ref().
11535 * This function should only be called by legacy #ClutterActor<!-- -->s
11536 * implementing the #ClutterContainer interface.
11540 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11543 clutter_actor_unparent (ClutterActor *self)
11545 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11547 if (self->priv->parent == NULL)
11550 clutter_actor_remove_child_internal (self->priv->parent, self,
11551 REMOVE_CHILD_LEGACY_FLAGS);
11555 * clutter_actor_reparent:
11556 * @self: a #ClutterActor
11557 * @new_parent: the new #ClutterActor parent
11559 * Resets the parent actor of @self.
11561 * This function is logically equivalent to calling clutter_actor_unparent()
11562 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11563 * ensures the child is not finalized when unparented, and emits the
11564 * #ClutterActor::parent-set signal only once.
11566 * In reality, calling this function is less useful than it sounds, as some
11567 * application code may rely on changes in the intermediate state between
11568 * removal and addition of the actor from its old parent to the @new_parent.
11569 * Thus, it is strongly encouraged to avoid using this function in application
11574 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11575 * clutter_actor_add_child() instead; remember to take a reference on
11576 * the actor being removed before calling clutter_actor_remove_child()
11577 * to avoid the reference count dropping to zero and the actor being
11581 clutter_actor_reparent (ClutterActor *self,
11582 ClutterActor *new_parent)
11584 ClutterActorPrivate *priv;
11586 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11587 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11588 g_return_if_fail (self != new_parent);
11590 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11592 g_warning ("Cannot set a parent on a toplevel actor");
11596 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11598 g_warning ("Cannot set a parent currently being destroyed");
11604 if (priv->parent != new_parent)
11606 ClutterActor *old_parent;
11608 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11610 old_parent = priv->parent;
11612 g_object_ref (self);
11614 if (old_parent != NULL)
11616 /* go through the Container implementation if this is a regular
11617 * child and not an internal one
11619 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11621 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11623 /* this will have to call unparent() */
11624 clutter_container_remove_actor (parent, self);
11627 clutter_actor_remove_child_internal (old_parent, self,
11628 REMOVE_CHILD_LEGACY_FLAGS);
11631 /* Note, will call set_parent() */
11632 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11633 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11635 clutter_actor_add_child_internal (new_parent, self,
11636 ADD_CHILD_LEGACY_FLAGS,
11637 insert_child_at_depth,
11640 /* we emit the ::parent-set signal once */
11641 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11643 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11645 /* the IN_REPARENT flag suspends state updates */
11646 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11648 g_object_unref (self);
11653 * clutter_actor_contains:
11654 * @self: A #ClutterActor
11655 * @descendant: A #ClutterActor, possibly contained in @self
11657 * Determines if @descendant is contained inside @self (either as an
11658 * immediate child, or as a deeper descendant). If @self and
11659 * @descendant point to the same actor then it will also return %TRUE.
11661 * Return value: whether @descendent is contained within @self
11666 clutter_actor_contains (ClutterActor *self,
11667 ClutterActor *descendant)
11669 ClutterActor *actor;
11671 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11672 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11674 for (actor = descendant; actor; actor = actor->priv->parent)
11682 * clutter_actor_set_child_above_sibling:
11683 * @self: a #ClutterActor
11684 * @child: a #ClutterActor child of @self
11685 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11687 * Sets @child to be above @sibling in the list of children of @self.
11689 * If @sibling is %NULL, @child will be the new last child of @self.
11691 * This function is logically equivalent to removing @child and using
11692 * clutter_actor_insert_child_above(), but it will not emit signals
11693 * or change state on @child.
11698 clutter_actor_set_child_above_sibling (ClutterActor *self,
11699 ClutterActor *child,
11700 ClutterActor *sibling)
11702 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11703 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11704 g_return_if_fail (child->priv->parent == self);
11705 g_return_if_fail (child != sibling);
11706 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11708 if (sibling != NULL)
11709 g_return_if_fail (sibling->priv->parent == self);
11711 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11712 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11713 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11716 /* we don't want to change the state of child, or emit signals, or
11717 * regenerate ChildMeta instances here, but we still want to follow
11718 * the correct sequence of steps encoded in remove_child() and
11719 * add_child(), so that correctness is ensured, and we only go
11720 * through one known code path.
11722 g_object_ref (child);
11723 clutter_actor_remove_child_internal (self, child, 0);
11724 clutter_actor_add_child_internal (self, child,
11725 ADD_CHILD_NOTIFY_FIRST_LAST,
11726 insert_child_above,
11729 clutter_actor_queue_relayout (self);
11733 * clutter_actor_set_child_below_sibling:
11734 * @self: a #ClutterActor
11735 * @child: a #ClutterActor child of @self
11736 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11738 * Sets @child to be below @sibling in the list of children of @self.
11740 * If @sibling is %NULL, @child will be the new first child of @self.
11742 * This function is logically equivalent to removing @self and using
11743 * clutter_actor_insert_child_below(), but it will not emit signals
11744 * or change state on @child.
11749 clutter_actor_set_child_below_sibling (ClutterActor *self,
11750 ClutterActor *child,
11751 ClutterActor *sibling)
11753 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11754 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11755 g_return_if_fail (child->priv->parent == self);
11756 g_return_if_fail (child != sibling);
11757 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11759 if (sibling != NULL)
11760 g_return_if_fail (sibling->priv->parent == self);
11762 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11763 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11764 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11767 /* see the comment in set_child_above_sibling() */
11768 g_object_ref (child);
11769 clutter_actor_remove_child_internal (self, child, 0);
11770 clutter_actor_add_child_internal (self, child,
11771 ADD_CHILD_NOTIFY_FIRST_LAST,
11772 insert_child_below,
11775 clutter_actor_queue_relayout (self);
11779 * clutter_actor_set_child_at_index:
11780 * @self: a #ClutterActor
11781 * @child: a #ClutterActor child of @self
11782 * @index_: the new index for @child
11784 * Changes the index of @child in the list of children of @self.
11786 * This function is logically equivalent to removing @child and
11787 * calling clutter_actor_insert_child_at_index(), but it will not
11788 * emit signals or change state on @child.
11793 clutter_actor_set_child_at_index (ClutterActor *self,
11794 ClutterActor *child,
11797 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11798 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11799 g_return_if_fail (child->priv->parent == self);
11800 g_return_if_fail (index_ <= self->priv->n_children);
11802 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11803 CLUTTER_ACTOR_IN_DESTRUCTION (child))
11806 g_object_ref (child);
11807 clutter_actor_remove_child_internal (self, child, 0);
11808 clutter_actor_add_child_internal (self, child,
11809 ADD_CHILD_NOTIFY_FIRST_LAST,
11810 insert_child_at_index,
11811 GINT_TO_POINTER (index_));
11813 clutter_actor_queue_relayout (self);
11817 * clutter_actor_raise:
11818 * @self: A #ClutterActor
11819 * @below: (allow-none): A #ClutterActor to raise above.
11821 * Puts @self above @below.
11823 * Both actors must have the same parent, and the parent must implement
11824 * the #ClutterContainer interface
11826 * This function calls clutter_container_raise_child() internally.
11828 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11831 clutter_actor_raise (ClutterActor *self,
11832 ClutterActor *below)
11834 ClutterActor *parent;
11836 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11838 parent = clutter_actor_get_parent (self);
11839 if (parent == NULL)
11841 g_warning ("%s: Actor '%s' is not inside a container",
11843 _clutter_actor_get_debug_name (self));
11849 if (parent != clutter_actor_get_parent (below))
11851 g_warning ("%s Actor '%s' is not in the same container as "
11854 _clutter_actor_get_debug_name (self),
11855 _clutter_actor_get_debug_name (below));
11860 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11864 * clutter_actor_lower:
11865 * @self: A #ClutterActor
11866 * @above: (allow-none): A #ClutterActor to lower below
11868 * Puts @self below @above.
11870 * Both actors must have the same parent, and the parent must implement
11871 * the #ClutterContainer interface.
11873 * This function calls clutter_container_lower_child() internally.
11875 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11878 clutter_actor_lower (ClutterActor *self,
11879 ClutterActor *above)
11881 ClutterActor *parent;
11883 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11885 parent = clutter_actor_get_parent (self);
11886 if (parent == NULL)
11888 g_warning ("%s: Actor of type %s is not inside a container",
11890 _clutter_actor_get_debug_name (self));
11896 if (parent != clutter_actor_get_parent (above))
11898 g_warning ("%s: Actor '%s' is not in the same container as "
11901 _clutter_actor_get_debug_name (self),
11902 _clutter_actor_get_debug_name (above));
11907 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11911 * clutter_actor_raise_top:
11912 * @self: A #ClutterActor
11914 * Raises @self to the top.
11916 * This function calls clutter_actor_raise() internally.
11918 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11919 * a %NULL sibling, instead.
11922 clutter_actor_raise_top (ClutterActor *self)
11924 clutter_actor_raise (self, NULL);
11928 * clutter_actor_lower_bottom:
11929 * @self: A #ClutterActor
11931 * Lowers @self to the bottom.
11933 * This function calls clutter_actor_lower() internally.
11935 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11936 * a %NULL sibling, instead.
11939 clutter_actor_lower_bottom (ClutterActor *self)
11941 clutter_actor_lower (self, NULL);
11949 * clutter_actor_event:
11950 * @actor: a #ClutterActor
11951 * @event: a #ClutterEvent
11952 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11954 * This function is used to emit an event on the main stage.
11955 * You should rarely need to use this function, except for
11956 * synthetising events.
11958 * Return value: the return value from the signal emission: %TRUE
11959 * if the actor handled the event, or %FALSE if the event was
11965 clutter_actor_event (ClutterActor *actor,
11966 ClutterEvent *event,
11969 gboolean retval = FALSE;
11970 gint signal_num = -1;
11972 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11973 g_return_val_if_fail (event != NULL, FALSE);
11975 g_object_ref (actor);
11979 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11985 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11989 switch (event->type)
11991 case CLUTTER_NOTHING:
11993 case CLUTTER_BUTTON_PRESS:
11994 signal_num = BUTTON_PRESS_EVENT;
11996 case CLUTTER_BUTTON_RELEASE:
11997 signal_num = BUTTON_RELEASE_EVENT;
11999 case CLUTTER_SCROLL:
12000 signal_num = SCROLL_EVENT;
12002 case CLUTTER_KEY_PRESS:
12003 signal_num = KEY_PRESS_EVENT;
12005 case CLUTTER_KEY_RELEASE:
12006 signal_num = KEY_RELEASE_EVENT;
12008 case CLUTTER_MOTION:
12009 signal_num = MOTION_EVENT;
12011 case CLUTTER_ENTER:
12012 signal_num = ENTER_EVENT;
12014 case CLUTTER_LEAVE:
12015 signal_num = LEAVE_EVENT;
12017 case CLUTTER_DELETE:
12018 case CLUTTER_DESTROY_NOTIFY:
12019 case CLUTTER_CLIENT_MESSAGE:
12025 if (signal_num != -1)
12026 g_signal_emit (actor, actor_signals[signal_num], 0,
12031 g_object_unref (actor);
12037 * clutter_actor_set_reactive:
12038 * @actor: a #ClutterActor
12039 * @reactive: whether the actor should be reactive to events
12041 * Sets @actor as reactive. Reactive actors will receive events.
12046 clutter_actor_set_reactive (ClutterActor *actor,
12049 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12051 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12055 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12057 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12059 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12063 * clutter_actor_get_reactive:
12064 * @actor: a #ClutterActor
12066 * Checks whether @actor is marked as reactive.
12068 * Return value: %TRUE if the actor is reactive
12073 clutter_actor_get_reactive (ClutterActor *actor)
12075 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12077 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12081 * clutter_actor_get_anchor_point:
12082 * @self: a #ClutterActor
12083 * @anchor_x: (out): return location for the X coordinate of the anchor point
12084 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12086 * Gets the current anchor point of the @actor in pixels.
12091 clutter_actor_get_anchor_point (ClutterActor *self,
12095 const ClutterTransformInfo *info;
12097 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12099 info = _clutter_actor_get_transform_info_or_defaults (self);
12100 clutter_anchor_coord_get_units (self, &info->anchor,
12107 * clutter_actor_set_anchor_point:
12108 * @self: a #ClutterActor
12109 * @anchor_x: X coordinate of the anchor point
12110 * @anchor_y: Y coordinate of the anchor point
12112 * Sets an anchor point for @self. The anchor point is a point in the
12113 * coordinate space of an actor to which the actor position within its
12114 * parent is relative; the default is (0, 0), i.e. the top-left corner
12120 clutter_actor_set_anchor_point (ClutterActor *self,
12124 ClutterTransformInfo *info;
12125 ClutterActorPrivate *priv;
12126 gboolean changed = FALSE;
12127 gfloat old_anchor_x, old_anchor_y;
12130 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12132 obj = G_OBJECT (self);
12134 info = _clutter_actor_get_transform_info (self);
12136 g_object_freeze_notify (obj);
12138 clutter_anchor_coord_get_units (self, &info->anchor,
12143 if (info->anchor.is_fractional)
12144 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12146 if (old_anchor_x != anchor_x)
12148 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12152 if (old_anchor_y != anchor_y)
12154 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12158 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12162 priv->transform_valid = FALSE;
12163 clutter_actor_queue_redraw (self);
12166 g_object_thaw_notify (obj);
12170 * clutter_actor_get_anchor_point_gravity:
12171 * @self: a #ClutterActor
12173 * Retrieves the anchor position expressed as a #ClutterGravity. If
12174 * the anchor point was specified using pixels or units this will
12175 * return %CLUTTER_GRAVITY_NONE.
12177 * Return value: the #ClutterGravity used by the anchor point
12182 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12184 const ClutterTransformInfo *info;
12186 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12188 info = _clutter_actor_get_transform_info_or_defaults (self);
12190 return clutter_anchor_coord_get_gravity (&info->anchor);
12194 * clutter_actor_move_anchor_point:
12195 * @self: a #ClutterActor
12196 * @anchor_x: X coordinate of the anchor point
12197 * @anchor_y: Y coordinate of the anchor point
12199 * Sets an anchor point for the actor, and adjusts the actor postion so that
12200 * the relative position of the actor toward its parent remains the same.
12205 clutter_actor_move_anchor_point (ClutterActor *self,
12209 gfloat old_anchor_x, old_anchor_y;
12210 const ClutterTransformInfo *info;
12212 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12214 info = _clutter_actor_get_transform_info (self);
12215 clutter_anchor_coord_get_units (self, &info->anchor,
12220 g_object_freeze_notify (G_OBJECT (self));
12222 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12224 if (self->priv->position_set)
12225 clutter_actor_move_by (self,
12226 anchor_x - old_anchor_x,
12227 anchor_y - old_anchor_y);
12229 g_object_thaw_notify (G_OBJECT (self));
12233 * clutter_actor_move_anchor_point_from_gravity:
12234 * @self: a #ClutterActor
12235 * @gravity: #ClutterGravity.
12237 * Sets an anchor point on the actor based on the given gravity, adjusting the
12238 * actor postion so that its relative position within its parent remains
12241 * Since version 1.0 the anchor point will be stored as a gravity so
12242 * that if the actor changes size then the anchor point will move. For
12243 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12244 * and later double the size of the actor, the anchor point will move
12245 * to the bottom right.
12250 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12251 ClutterGravity gravity)
12253 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12254 const ClutterTransformInfo *info;
12255 ClutterActorPrivate *priv;
12257 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12260 info = _clutter_actor_get_transform_info (self);
12262 g_object_freeze_notify (G_OBJECT (self));
12264 clutter_anchor_coord_get_units (self, &info->anchor,
12268 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12269 clutter_anchor_coord_get_units (self, &info->anchor,
12274 if (priv->position_set)
12275 clutter_actor_move_by (self,
12276 new_anchor_x - old_anchor_x,
12277 new_anchor_y - old_anchor_y);
12279 g_object_thaw_notify (G_OBJECT (self));
12283 * clutter_actor_set_anchor_point_from_gravity:
12284 * @self: a #ClutterActor
12285 * @gravity: #ClutterGravity.
12287 * Sets an anchor point on the actor, based on the given gravity (this is a
12288 * convenience function wrapping clutter_actor_set_anchor_point()).
12290 * Since version 1.0 the anchor point will be stored as a gravity so
12291 * that if the actor changes size then the anchor point will move. For
12292 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12293 * and later double the size of the actor, the anchor point will move
12294 * to the bottom right.
12299 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12300 ClutterGravity gravity)
12302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12304 if (gravity == CLUTTER_GRAVITY_NONE)
12305 clutter_actor_set_anchor_point (self, 0, 0);
12308 GObject *obj = G_OBJECT (self);
12309 ClutterTransformInfo *info;
12311 g_object_freeze_notify (obj);
12313 info = _clutter_actor_get_transform_info (self);
12314 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12316 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12317 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12318 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12320 self->priv->transform_valid = FALSE;
12322 clutter_actor_queue_redraw (self);
12324 g_object_thaw_notify (obj);
12329 clutter_actor_store_content_box (ClutterActor *self,
12330 const ClutterActorBox *box)
12334 self->priv->content_box = *box;
12335 self->priv->content_box_valid = TRUE;
12338 self->priv->content_box_valid = FALSE;
12340 clutter_actor_queue_redraw (self);
12342 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12346 clutter_container_iface_init (ClutterContainerIface *iface)
12348 /* we don't override anything, as ClutterContainer already has a default
12349 * implementation that we can use, and which calls into our own API.
12364 parse_units (ClutterActor *self,
12365 ParseDimension dimension,
12368 GValue value = G_VALUE_INIT;
12371 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12374 json_node_get_value (node, &value);
12376 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12378 retval = (gfloat) g_value_get_int64 (&value);
12380 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12382 retval = g_value_get_double (&value);
12384 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12386 ClutterUnits units;
12389 res = clutter_units_from_string (&units, g_value_get_string (&value));
12391 retval = clutter_units_to_pixels (&units);
12394 g_warning ("Invalid value '%s': integers, strings or floating point "
12395 "values can be used for the x, y, width and height "
12396 "properties. Valid modifiers for strings are 'px', 'mm', "
12398 g_value_get_string (&value));
12404 g_warning ("Invalid value of type '%s': integers, strings of floating "
12405 "point values can be used for the x, y, width, height "
12406 "anchor-x and anchor-y properties.",
12407 g_type_name (G_VALUE_TYPE (&value)));
12410 g_value_unset (&value);
12416 ClutterRotateAxis axis;
12425 static inline gboolean
12426 parse_rotation_array (ClutterActor *actor,
12428 RotationInfo *info)
12432 if (json_array_get_length (array) != 2)
12436 element = json_array_get_element (array, 0);
12437 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12438 info->angle = json_node_get_double (element);
12443 element = json_array_get_element (array, 1);
12444 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12446 JsonArray *center = json_node_get_array (element);
12448 if (json_array_get_length (center) != 2)
12451 switch (info->axis)
12453 case CLUTTER_X_AXIS:
12454 info->center_y = parse_units (actor, PARSE_Y,
12455 json_array_get_element (center, 0));
12456 info->center_z = parse_units (actor, PARSE_Y,
12457 json_array_get_element (center, 1));
12460 case CLUTTER_Y_AXIS:
12461 info->center_x = parse_units (actor, PARSE_X,
12462 json_array_get_element (center, 0));
12463 info->center_z = parse_units (actor, PARSE_X,
12464 json_array_get_element (center, 1));
12467 case CLUTTER_Z_AXIS:
12468 info->center_x = parse_units (actor, PARSE_X,
12469 json_array_get_element (center, 0));
12470 info->center_y = parse_units (actor, PARSE_Y,
12471 json_array_get_element (center, 1));
12480 parse_rotation (ClutterActor *actor,
12482 RotationInfo *info)
12486 gboolean retval = FALSE;
12488 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12490 g_warning ("Invalid node of type '%s' found, expecting an array",
12491 json_node_type_name (node));
12495 array = json_node_get_array (node);
12496 len = json_array_get_length (array);
12498 for (i = 0; i < len; i++)
12500 JsonNode *element = json_array_get_element (array, i);
12501 JsonObject *object;
12504 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12506 g_warning ("Invalid node of type '%s' found, expecting an object",
12507 json_node_type_name (element));
12511 object = json_node_get_object (element);
12513 if (json_object_has_member (object, "x-axis"))
12515 member = json_object_get_member (object, "x-axis");
12517 info->axis = CLUTTER_X_AXIS;
12519 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12521 info->angle = json_node_get_double (member);
12524 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12525 retval = parse_rotation_array (actor,
12526 json_node_get_array (member),
12531 else if (json_object_has_member (object, "y-axis"))
12533 member = json_object_get_member (object, "y-axis");
12535 info->axis = CLUTTER_Y_AXIS;
12537 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12539 info->angle = json_node_get_double (member);
12542 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12543 retval = parse_rotation_array (actor,
12544 json_node_get_array (member),
12549 else if (json_object_has_member (object, "z-axis"))
12551 member = json_object_get_member (object, "z-axis");
12553 info->axis = CLUTTER_Z_AXIS;
12555 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12557 info->angle = json_node_get_double (member);
12560 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12561 retval = parse_rotation_array (actor,
12562 json_node_get_array (member),
12573 parse_actor_metas (ClutterScript *script,
12574 ClutterActor *actor,
12577 GList *elements, *l;
12578 GSList *retval = NULL;
12580 if (!JSON_NODE_HOLDS_ARRAY (node))
12583 elements = json_array_get_elements (json_node_get_array (node));
12585 for (l = elements; l != NULL; l = l->next)
12587 JsonNode *element = l->data;
12588 const gchar *id_ = _clutter_script_get_id_from_node (element);
12591 if (id_ == NULL || *id_ == '\0')
12594 meta = clutter_script_get_object (script, id_);
12598 retval = g_slist_prepend (retval, meta);
12601 g_list_free (elements);
12603 return g_slist_reverse (retval);
12607 parse_behaviours (ClutterScript *script,
12608 ClutterActor *actor,
12611 GList *elements, *l;
12612 GSList *retval = NULL;
12614 if (!JSON_NODE_HOLDS_ARRAY (node))
12617 elements = json_array_get_elements (json_node_get_array (node));
12619 for (l = elements; l != NULL; l = l->next)
12621 JsonNode *element = l->data;
12622 const gchar *id_ = _clutter_script_get_id_from_node (element);
12623 GObject *behaviour;
12625 if (id_ == NULL || *id_ == '\0')
12628 behaviour = clutter_script_get_object (script, id_);
12629 if (behaviour == NULL)
12632 retval = g_slist_prepend (retval, behaviour);
12635 g_list_free (elements);
12637 return g_slist_reverse (retval);
12641 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12642 ClutterScript *script,
12647 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12648 gboolean retval = FALSE;
12650 if ((name[0] == 'x' && name[1] == '\0') ||
12651 (name[0] == 'y' && name[1] == '\0') ||
12652 (strcmp (name, "width") == 0) ||
12653 (strcmp (name, "height") == 0) ||
12654 (strcmp (name, "anchor_x") == 0) ||
12655 (strcmp (name, "anchor_y") == 0))
12657 ParseDimension dimension;
12660 if (name[0] == 'x')
12661 dimension = PARSE_X;
12662 else if (name[0] == 'y')
12663 dimension = PARSE_Y;
12664 else if (name[0] == 'w')
12665 dimension = PARSE_WIDTH;
12666 else if (name[0] == 'h')
12667 dimension = PARSE_HEIGHT;
12668 else if (name[0] == 'a' && name[7] == 'x')
12669 dimension = PARSE_ANCHOR_X;
12670 else if (name[0] == 'a' && name[7] == 'y')
12671 dimension = PARSE_ANCHOR_Y;
12675 units = parse_units (actor, dimension, node);
12677 /* convert back to pixels: all properties are pixel-based */
12678 g_value_init (value, G_TYPE_FLOAT);
12679 g_value_set_float (value, units);
12683 else if (strcmp (name, "rotation") == 0)
12685 RotationInfo *info;
12687 info = g_slice_new0 (RotationInfo);
12688 retval = parse_rotation (actor, node, info);
12692 g_value_init (value, G_TYPE_POINTER);
12693 g_value_set_pointer (value, info);
12696 g_slice_free (RotationInfo, info);
12698 else if (strcmp (name, "behaviours") == 0)
12702 #ifdef CLUTTER_ENABLE_DEBUG
12703 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12704 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12705 "and it should not be used in newly "
12706 "written ClutterScript definitions.");
12709 l = parse_behaviours (script, actor, node);
12711 g_value_init (value, G_TYPE_POINTER);
12712 g_value_set_pointer (value, l);
12716 else if (strcmp (name, "actions") == 0 ||
12717 strcmp (name, "constraints") == 0 ||
12718 strcmp (name, "effects") == 0)
12722 l = parse_actor_metas (script, actor, node);
12724 g_value_init (value, G_TYPE_POINTER);
12725 g_value_set_pointer (value, l);
12734 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12735 ClutterScript *script,
12737 const GValue *value)
12739 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12741 #ifdef CLUTTER_ENABLE_DEBUG
12742 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12744 gchar *tmp = g_strdup_value_contents (value);
12746 CLUTTER_NOTE (SCRIPT,
12747 "in ClutterActor::set_custom_property('%s') = %s",
12753 #endif /* CLUTTER_ENABLE_DEBUG */
12755 if (strcmp (name, "rotation") == 0)
12757 RotationInfo *info;
12759 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12762 info = g_value_get_pointer (value);
12764 clutter_actor_set_rotation (actor,
12765 info->axis, info->angle,
12770 g_slice_free (RotationInfo, info);
12775 if (strcmp (name, "behaviours") == 0)
12777 GSList *behaviours, *l;
12779 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12782 behaviours = g_value_get_pointer (value);
12783 for (l = behaviours; l != NULL; l = l->next)
12785 ClutterBehaviour *behaviour = l->data;
12787 clutter_behaviour_apply (behaviour, actor);
12790 g_slist_free (behaviours);
12795 if (strcmp (name, "actions") == 0 ||
12796 strcmp (name, "constraints") == 0 ||
12797 strcmp (name, "effects") == 0)
12801 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12804 metas = g_value_get_pointer (value);
12805 for (l = metas; l != NULL; l = l->next)
12807 if (name[0] == 'a')
12808 clutter_actor_add_action (actor, l->data);
12810 if (name[0] == 'c')
12811 clutter_actor_add_constraint (actor, l->data);
12813 if (name[0] == 'e')
12814 clutter_actor_add_effect (actor, l->data);
12817 g_slist_free (metas);
12822 g_object_set_property (G_OBJECT (scriptable), name, value);
12826 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12828 iface->parse_custom_node = clutter_actor_parse_custom_node;
12829 iface->set_custom_property = clutter_actor_set_custom_property;
12832 static ClutterActorMeta *
12833 get_meta_from_animation_property (ClutterActor *actor,
12837 ClutterActorPrivate *priv = actor->priv;
12838 ClutterActorMeta *meta = NULL;
12841 /* if this is not a special property, fall through */
12842 if (name[0] != '@')
12845 /* detect the properties named using the following spec:
12847 * @<section>.<meta-name>.<property-name>
12849 * where <section> can be one of the following:
12855 * and <meta-name> is the name set on a specific ActorMeta
12858 tokens = g_strsplit (name + 1, ".", -1);
12859 if (tokens == NULL || g_strv_length (tokens) != 3)
12861 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12863 g_strfreev (tokens);
12867 if (strcmp (tokens[0], "actions") == 0)
12868 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12870 if (strcmp (tokens[0], "constraints") == 0)
12871 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12873 if (strcmp (tokens[0], "effects") == 0)
12874 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12876 if (name_p != NULL)
12877 *name_p = g_strdup (tokens[2]);
12879 CLUTTER_NOTE (ANIMATION,
12880 "Looking for property '%s' of object '%s' in section '%s'",
12885 g_strfreev (tokens);
12890 static GParamSpec *
12891 clutter_actor_find_property (ClutterAnimatable *animatable,
12892 const gchar *property_name)
12894 ClutterActorMeta *meta = NULL;
12895 GObjectClass *klass = NULL;
12896 GParamSpec *pspec = NULL;
12897 gchar *p_name = NULL;
12899 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12905 klass = G_OBJECT_GET_CLASS (meta);
12907 pspec = g_object_class_find_property (klass, p_name);
12911 klass = G_OBJECT_GET_CLASS (animatable);
12913 pspec = g_object_class_find_property (klass, property_name);
12922 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12923 const gchar *property_name,
12926 ClutterActorMeta *meta = NULL;
12927 gchar *p_name = NULL;
12929 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12934 g_object_get_property (G_OBJECT (meta), p_name, initial);
12936 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12942 * clutter_actor_set_animatable_property:
12943 * @actor: a #ClutterActor
12944 * @prop_id: the paramspec id
12945 * @value: the value to set
12946 * @pspec: the paramspec
12948 * Sets values of animatable properties.
12950 * This is a variant of clutter_actor_set_property() that gets called
12951 * by the #ClutterAnimatable implementation of #ClutterActor for the
12952 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12955 * Unlike the implementation of #GObjectClass.set_property(), this
12956 * function will not update the interval if a transition involving an
12957 * animatable property is in progress - this avoids cycles with the
12958 * transition API calling the public API.
12961 clutter_actor_set_animatable_property (ClutterActor *actor,
12963 const GValue *value,
12966 GObject *obj = G_OBJECT (actor);
12968 g_object_freeze_notify (obj);
12973 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12977 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12981 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12985 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12989 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12993 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12996 case PROP_BACKGROUND_COLOR:
12997 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13001 clutter_actor_set_scale_factor_internal (actor,
13002 g_value_get_double (value),
13007 clutter_actor_set_scale_factor_internal (actor,
13008 g_value_get_double (value),
13012 case PROP_ROTATION_ANGLE_X:
13013 clutter_actor_set_rotation_angle_internal (actor,
13015 g_value_get_double (value));
13018 case PROP_ROTATION_ANGLE_Y:
13019 clutter_actor_set_rotation_angle_internal (actor,
13021 g_value_get_double (value));
13024 case PROP_ROTATION_ANGLE_Z:
13025 clutter_actor_set_rotation_angle_internal (actor,
13027 g_value_get_double (value));
13030 case PROP_CONTENT_BOX:
13031 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13035 g_object_set_property (obj, pspec->name, value);
13039 g_object_thaw_notify (obj);
13043 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13044 const gchar *property_name,
13045 const GValue *final)
13047 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13048 ClutterActorMeta *meta = NULL;
13049 gchar *p_name = NULL;
13051 meta = get_meta_from_animation_property (actor,
13055 g_object_set_property (G_OBJECT (meta), p_name, final);
13058 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13061 pspec = g_object_class_find_property (obj_class, property_name);
13063 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13065 /* XXX - I'm going to the special hell for this */
13066 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13069 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13076 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13078 iface->find_property = clutter_actor_find_property;
13079 iface->get_initial_state = clutter_actor_get_initial_state;
13080 iface->set_final_state = clutter_actor_set_final_state;
13084 * clutter_actor_transform_stage_point:
13085 * @self: A #ClutterActor
13086 * @x: (in): x screen coordinate of the point to unproject
13087 * @y: (in): y screen coordinate of the point to unproject
13088 * @x_out: (out): return location for the unprojected x coordinance
13089 * @y_out: (out): return location for the unprojected y coordinance
13091 * This function translates screen coordinates (@x, @y) to
13092 * coordinates relative to the actor. For example, it can be used to translate
13093 * screen events from global screen coordinates into actor-local coordinates.
13095 * The conversion can fail, notably if the transform stack results in the
13096 * actor being projected on the screen as a mere line.
13098 * The conversion should not be expected to be pixel-perfect due to the
13099 * nature of the operation. In general the error grows when the skewing
13100 * of the actor rectangle on screen increases.
13102 * <note><para>This function can be computationally intensive.</para></note>
13104 * <note><para>This function only works when the allocation is up-to-date,
13105 * i.e. inside of paint().</para></note>
13107 * Return value: %TRUE if conversion was successful.
13112 clutter_actor_transform_stage_point (ClutterActor *self,
13118 ClutterVertex v[4];
13121 int du, dv, xi, yi;
13123 float xf, yf, wf, det;
13124 ClutterActorPrivate *priv;
13126 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13130 /* This implementation is based on the quad -> quad projection algorithm
13131 * described by Paul Heckbert in:
13133 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13135 * and the sample implementation at:
13137 * http://www.cs.cmu.edu/~ph/src/texfund/
13139 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13140 * quad to rectangle only, which significantly simplifies things; the
13141 * function calls have been unrolled, and most of the math is done in fixed
13145 clutter_actor_get_abs_allocation_vertices (self, v);
13147 /* Keeping these as ints simplifies the multiplication (no significant
13148 * loss of precision here).
13150 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13151 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13156 #define UX2FP(x) (x)
13157 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13159 /* First, find mapping from unit uv square to xy quadrilateral; this
13160 * equivalent to the pmap_square_quad() functions in the sample
13161 * implementation, which we can simplify, since our target is always
13164 px = v[0].x - v[1].x + v[3].x - v[2].x;
13165 py = v[0].y - v[1].y + v[3].y - v[2].y;
13169 /* affine transform */
13170 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13171 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13172 RQ[2][0] = UX2FP (v[0].x);
13173 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13174 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13175 RQ[2][1] = UX2FP (v[0].y);
13182 /* projective transform */
13183 double dx1, dx2, dy1, dy2, del;
13185 dx1 = UX2FP (v[1].x - v[3].x);
13186 dx2 = UX2FP (v[2].x - v[3].x);
13187 dy1 = UX2FP (v[1].y - v[3].y);
13188 dy2 = UX2FP (v[2].y - v[3].y);
13190 del = DET2FP (dx1, dx2, dy1, dy2);
13195 * The division here needs to be done in floating point for
13196 * precisions reasons.
13198 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13199 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13200 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13202 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13203 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13204 RQ[2][0] = UX2FP (v[0].x);
13205 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13206 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13207 RQ[2][1] = UX2FP (v[0].y);
13211 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13212 * square. Since our rectangle is based at 0,0 we only need to scale.
13222 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13225 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13226 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13227 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13228 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13229 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13230 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13231 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13232 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13233 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13236 * Check the resulting matrix is OK.
13238 det = (RQ[0][0] * ST[0][0])
13239 + (RQ[0][1] * ST[0][1])
13240 + (RQ[0][2] * ST[0][2]);
13245 * Now transform our point with the ST matrix; the notional w
13246 * coordinate is 1, hence the last part is simply added.
13251 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13252 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13253 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13271 static ClutterGeometry*
13272 clutter_geometry_copy (const ClutterGeometry *geometry)
13274 return g_slice_dup (ClutterGeometry, geometry);
13278 clutter_geometry_free (ClutterGeometry *geometry)
13280 if (G_LIKELY (geometry != NULL))
13281 g_slice_free (ClutterGeometry, geometry);
13285 * clutter_geometry_union:
13286 * @geometry_a: a #ClutterGeometry
13287 * @geometry_b: another #ClutterGeometry
13288 * @result: (out): location to store the result
13290 * Find the union of two rectangles represented as #ClutterGeometry.
13295 clutter_geometry_union (const ClutterGeometry *geometry_a,
13296 const ClutterGeometry *geometry_b,
13297 ClutterGeometry *result)
13299 /* We don't try to handle rectangles that can't be represented
13300 * as a signed integer box */
13301 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13302 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13303 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13304 geometry_b->x + (gint)geometry_b->width);
13305 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13306 geometry_b->y + (gint)geometry_b->height);
13309 result->width = x_2 - x_1;
13310 result->height = y_2 - y_1;
13314 * clutter_geometry_intersects:
13315 * @geometry0: The first geometry to test
13316 * @geometry1: The second geometry to test
13318 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13319 * they do else %FALSE.
13321 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13327 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13328 const ClutterGeometry *geometry1)
13330 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13331 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13332 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13333 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13340 clutter_geometry_progress (const GValue *a,
13345 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13346 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13347 ClutterGeometry res = { 0, };
13348 gint a_width = a_geom->width;
13349 gint b_width = b_geom->width;
13350 gint a_height = a_geom->height;
13351 gint b_height = b_geom->height;
13353 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13354 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13356 res.width = a_width + (b_width - a_width) * progress;
13357 res.height = a_height + (b_height - a_height) * progress;
13359 g_value_set_boxed (retval, &res);
13364 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13365 clutter_geometry_copy,
13366 clutter_geometry_free,
13367 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13374 * clutter_vertex_new:
13379 * Creates a new #ClutterVertex for the point in 3D space
13380 * identified by the 3 coordinates @x, @y, @z
13382 * Return value: the newly allocate #ClutterVertex. Use
13383 * clutter_vertex_free() to free the resources
13388 clutter_vertex_new (gfloat x,
13392 ClutterVertex *vertex;
13394 vertex = g_slice_new (ClutterVertex);
13395 clutter_vertex_init (vertex, x, y, z);
13401 * clutter_vertex_init:
13402 * @vertex: a #ClutterVertex
13407 * Initializes @vertex with the given coordinates.
13412 clutter_vertex_init (ClutterVertex *vertex,
13417 g_return_if_fail (vertex != NULL);
13425 * clutter_vertex_copy:
13426 * @vertex: a #ClutterVertex
13430 * Return value: a newly allocated copy of #ClutterVertex. Use
13431 * clutter_vertex_free() to free the allocated resources
13436 clutter_vertex_copy (const ClutterVertex *vertex)
13438 if (G_LIKELY (vertex != NULL))
13439 return g_slice_dup (ClutterVertex, vertex);
13445 * clutter_vertex_free:
13446 * @vertex: a #ClutterVertex
13448 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13453 clutter_vertex_free (ClutterVertex *vertex)
13455 if (G_UNLIKELY (vertex != NULL))
13456 g_slice_free (ClutterVertex, vertex);
13460 * clutter_vertex_equal:
13461 * @vertex_a: a #ClutterVertex
13462 * @vertex_b: a #ClutterVertex
13464 * Compares @vertex_a and @vertex_b for equality
13466 * Return value: %TRUE if the passed #ClutterVertex are equal
13471 clutter_vertex_equal (const ClutterVertex *vertex_a,
13472 const ClutterVertex *vertex_b)
13474 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13476 if (vertex_a == vertex_b)
13479 return vertex_a->x == vertex_b->x &&
13480 vertex_a->y == vertex_b->y &&
13481 vertex_a->z == vertex_b->z;
13485 clutter_vertex_progress (const GValue *a,
13490 const ClutterVertex *av = g_value_get_boxed (a);
13491 const ClutterVertex *bv = g_value_get_boxed (b);
13492 ClutterVertex res = { 0, };
13494 res.x = av->x + (bv->x - av->x) * progress;
13495 res.y = av->y + (bv->y - av->y) * progress;
13496 res.z = av->z + (bv->z - av->z) * progress;
13498 g_value_set_boxed (retval, &res);
13503 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13504 clutter_vertex_copy,
13505 clutter_vertex_free,
13506 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13509 * clutter_actor_is_rotated:
13510 * @self: a #ClutterActor
13512 * Checks whether any rotation is applied to the actor.
13514 * Return value: %TRUE if the actor is rotated.
13519 clutter_actor_is_rotated (ClutterActor *self)
13521 const ClutterTransformInfo *info;
13523 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13525 info = _clutter_actor_get_transform_info_or_defaults (self);
13527 if (info->rx_angle || info->ry_angle || info->rz_angle)
13534 * clutter_actor_is_scaled:
13535 * @self: a #ClutterActor
13537 * Checks whether the actor is scaled in either dimension.
13539 * Return value: %TRUE if the actor is scaled.
13544 clutter_actor_is_scaled (ClutterActor *self)
13546 const ClutterTransformInfo *info;
13548 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13550 info = _clutter_actor_get_transform_info_or_defaults (self);
13552 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13559 _clutter_actor_get_stage_internal (ClutterActor *actor)
13561 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13562 actor = actor->priv->parent;
13568 * clutter_actor_get_stage:
13569 * @actor: a #ClutterActor
13571 * Retrieves the #ClutterStage where @actor is contained.
13573 * Return value: (transfer none) (type Clutter.Stage): the stage
13574 * containing the actor, or %NULL
13579 clutter_actor_get_stage (ClutterActor *actor)
13581 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13583 return _clutter_actor_get_stage_internal (actor);
13587 * clutter_actor_allocate_available_size:
13588 * @self: a #ClutterActor
13589 * @x: the actor's X coordinate
13590 * @y: the actor's Y coordinate
13591 * @available_width: the maximum available width, or -1 to use the
13592 * actor's natural width
13593 * @available_height: the maximum available height, or -1 to use the
13594 * actor's natural height
13595 * @flags: flags controlling the allocation
13597 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13598 * preferred size, but limiting it to the maximum available width
13599 * and height provided.
13601 * This function will do the right thing when dealing with the
13602 * actor's request mode.
13604 * The implementation of this function is equivalent to:
13607 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13609 * clutter_actor_get_preferred_width (self, available_height,
13611 * &natural_width);
13612 * width = CLAMP (natural_width, min_width, available_width);
13614 * clutter_actor_get_preferred_height (self, width,
13616 * &natural_height);
13617 * height = CLAMP (natural_height, min_height, available_height);
13621 * clutter_actor_get_preferred_height (self, available_width,
13623 * &natural_height);
13624 * height = CLAMP (natural_height, min_height, available_height);
13626 * clutter_actor_get_preferred_width (self, height,
13628 * &natural_width);
13629 * width = CLAMP (natural_width, min_width, available_width);
13632 * box.x1 = x; box.y1 = y;
13633 * box.x2 = box.x1 + available_width;
13634 * box.y2 = box.y1 + available_height;
13635 * clutter_actor_allocate (self, &box, flags);
13638 * This function can be used by fluid layout managers to allocate
13639 * an actor's preferred size without making it bigger than the area
13640 * available for the container.
13645 clutter_actor_allocate_available_size (ClutterActor *self,
13648 gfloat available_width,
13649 gfloat available_height,
13650 ClutterAllocationFlags flags)
13652 ClutterActorPrivate *priv;
13653 gfloat width, height;
13654 gfloat min_width, min_height;
13655 gfloat natural_width, natural_height;
13656 ClutterActorBox box;
13658 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13662 width = height = 0.0;
13664 switch (priv->request_mode)
13666 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13667 clutter_actor_get_preferred_width (self, available_height,
13670 width = CLAMP (natural_width, min_width, available_width);
13672 clutter_actor_get_preferred_height (self, width,
13675 height = CLAMP (natural_height, min_height, available_height);
13678 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13679 clutter_actor_get_preferred_height (self, available_width,
13682 height = CLAMP (natural_height, min_height, available_height);
13684 clutter_actor_get_preferred_width (self, height,
13687 width = CLAMP (natural_width, min_width, available_width);
13694 box.x2 = box.x1 + width;
13695 box.y2 = box.y1 + height;
13696 clutter_actor_allocate (self, &box, flags);
13700 * clutter_actor_allocate_preferred_size:
13701 * @self: a #ClutterActor
13702 * @flags: flags controlling the allocation
13704 * Allocates the natural size of @self.
13706 * This function is a utility call for #ClutterActor implementations
13707 * that allocates the actor's preferred natural size. It can be used
13708 * by fixed layout managers (like #ClutterGroup or so called
13709 * 'composite actors') inside the ClutterActor::allocate
13710 * implementation to give each child exactly how much space it
13713 * This function is not meant to be used by applications. It is also
13714 * not meant to be used outside the implementation of the
13715 * ClutterActor::allocate virtual function.
13720 clutter_actor_allocate_preferred_size (ClutterActor *self,
13721 ClutterAllocationFlags flags)
13723 gfloat actor_x, actor_y;
13724 gfloat natural_width, natural_height;
13725 ClutterActorBox actor_box;
13727 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13729 actor_x = clutter_actor_get_x (self);
13730 actor_y = clutter_actor_get_y (self);
13732 clutter_actor_get_preferred_size (self,
13737 actor_box.x1 = actor_x;
13738 actor_box.y1 = actor_y;
13739 actor_box.x2 = actor_box.x1 + natural_width;
13740 actor_box.y2 = actor_box.y1 + natural_height;
13742 clutter_actor_allocate (self, &actor_box, flags);
13746 * clutter_actor_allocate_align_fill:
13747 * @self: a #ClutterActor
13748 * @box: a #ClutterActorBox, containing the available width and height
13749 * @x_align: the horizontal alignment, between 0 and 1
13750 * @y_align: the vertical alignment, between 0 and 1
13751 * @x_fill: whether the actor should fill horizontally
13752 * @y_fill: whether the actor should fill vertically
13753 * @flags: allocation flags to be passed to clutter_actor_allocate()
13755 * Allocates @self by taking into consideration the available allocation
13756 * area; an alignment factor on either axis; and whether the actor should
13757 * fill the allocation on either axis.
13759 * The @box should contain the available allocation width and height;
13760 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13761 * allocation will be offset by their value.
13763 * This function takes into consideration the geometry request specified by
13764 * the #ClutterActor:request-mode property, and the text direction.
13766 * This function is useful for fluid layout managers, like #ClutterBinLayout
13767 * or #ClutterTableLayout
13772 clutter_actor_allocate_align_fill (ClutterActor *self,
13773 const ClutterActorBox *box,
13778 ClutterAllocationFlags flags)
13780 ClutterActorPrivate *priv;
13781 ClutterActorBox allocation = { 0, };
13782 gfloat x_offset, y_offset;
13783 gfloat available_width, available_height;
13784 gfloat child_width, child_height;
13786 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13787 g_return_if_fail (box != NULL);
13788 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13789 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13793 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13794 clutter_actor_box_get_size (box, &available_width, &available_height);
13796 if (available_width < 0)
13797 available_width = 0;
13799 if (available_height < 0)
13800 available_height = 0;
13804 allocation.x1 = x_offset;
13805 allocation.x2 = allocation.x1 + available_width;
13810 allocation.y1 = y_offset;
13811 allocation.y2 = allocation.y1 + available_height;
13814 /* if we are filling horizontally and vertically then we're done */
13815 if (x_fill && y_fill)
13818 child_width = child_height = 0.0f;
13820 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13822 gfloat min_width, natural_width;
13823 gfloat min_height, natural_height;
13825 clutter_actor_get_preferred_width (self, available_height,
13829 child_width = CLAMP (natural_width, min_width, available_width);
13833 clutter_actor_get_preferred_height (self, child_width,
13837 child_height = CLAMP (natural_height, min_height, available_height);
13842 gfloat min_width, natural_width;
13843 gfloat min_height, natural_height;
13845 clutter_actor_get_preferred_height (self, available_width,
13849 child_height = CLAMP (natural_height, min_height, available_height);
13853 clutter_actor_get_preferred_width (self, child_height,
13857 child_width = CLAMP (natural_width, min_width, available_width);
13861 /* invert the horizontal alignment for RTL languages */
13862 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13863 x_align = 1.0 - x_align;
13867 allocation.x1 = x_offset
13868 + ((available_width - child_width) * x_align);
13869 allocation.x2 = allocation.x1 + child_width;
13874 allocation.y1 = y_offset
13875 + ((available_height - child_height) * y_align);
13876 allocation.y2 = allocation.y1 + child_height;
13880 clutter_actor_box_clamp_to_pixel (&allocation);
13881 clutter_actor_allocate (self, &allocation, flags);
13885 * clutter_actor_grab_key_focus:
13886 * @self: a #ClutterActor
13888 * Sets the key focus of the #ClutterStage including @self
13889 * to this #ClutterActor.
13894 clutter_actor_grab_key_focus (ClutterActor *self)
13896 ClutterActor *stage;
13898 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13900 stage = _clutter_actor_get_stage_internal (self);
13902 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13906 * clutter_actor_get_pango_context:
13907 * @self: a #ClutterActor
13909 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13910 * is already configured using the appropriate font map, resolution
13911 * and font options.
13913 * Unlike clutter_actor_create_pango_context(), this context is owend
13914 * by the #ClutterActor and it will be updated each time the options
13915 * stored by the #ClutterBackend change.
13917 * You can use the returned #PangoContext to create a #PangoLayout
13918 * and render text using cogl_pango_render_layout() to reuse the
13919 * glyphs cache also used by Clutter.
13921 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13922 * The returned #PangoContext is owned by the actor and should not be
13923 * unreferenced by the application code
13928 clutter_actor_get_pango_context (ClutterActor *self)
13930 ClutterActorPrivate *priv;
13932 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13936 if (priv->pango_context != NULL)
13937 return priv->pango_context;
13939 priv->pango_context = _clutter_context_get_pango_context ();
13940 g_object_ref (priv->pango_context);
13942 return priv->pango_context;
13946 * clutter_actor_create_pango_context:
13947 * @self: a #ClutterActor
13949 * Creates a #PangoContext for the given actor. The #PangoContext
13950 * is already configured using the appropriate font map, resolution
13951 * and font options.
13953 * See also clutter_actor_get_pango_context().
13955 * Return value: (transfer full): the newly created #PangoContext.
13956 * Use g_object_unref() on the returned value to deallocate its
13962 clutter_actor_create_pango_context (ClutterActor *self)
13964 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13966 return _clutter_context_create_pango_context ();
13970 * clutter_actor_create_pango_layout:
13971 * @self: a #ClutterActor
13972 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13974 * Creates a new #PangoLayout from the same #PangoContext used
13975 * by the #ClutterActor. The #PangoLayout is already configured
13976 * with the font map, resolution and font options, and the
13979 * If you want to keep around a #PangoLayout created by this
13980 * function you will have to connect to the #ClutterBackend::font-changed
13981 * and #ClutterBackend::resolution-changed signals, and call
13982 * pango_layout_context_changed() in response to them.
13984 * Return value: (transfer full): the newly created #PangoLayout.
13985 * Use g_object_unref() when done
13990 clutter_actor_create_pango_layout (ClutterActor *self,
13993 PangoContext *context;
13994 PangoLayout *layout;
13996 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13998 context = clutter_actor_get_pango_context (self);
13999 layout = pango_layout_new (context);
14002 pango_layout_set_text (layout, text, -1);
14007 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14008 * ClutterOffscreenEffect.
14011 _clutter_actor_set_opacity_override (ClutterActor *self,
14014 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14016 self->priv->opacity_override = opacity;
14020 _clutter_actor_get_opacity_override (ClutterActor *self)
14022 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14024 return self->priv->opacity_override;
14027 /* Allows you to disable applying the actors model view transform during
14028 * a paint. Used by ClutterClone. */
14030 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14033 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14035 self->priv->enable_model_view_transform = enable;
14039 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14042 ClutterActorPrivate *priv;
14044 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14048 priv->enable_paint_unmapped = enable;
14050 if (priv->enable_paint_unmapped)
14052 /* Make sure that the parents of the widget are realized first;
14053 * otherwise checks in clutter_actor_update_map_state() will
14056 clutter_actor_realize (self);
14058 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14062 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14067 clutter_anchor_coord_get_units (ClutterActor *self,
14068 const AnchorCoord *coord,
14073 if (coord->is_fractional)
14075 gfloat actor_width, actor_height;
14077 clutter_actor_get_size (self, &actor_width, &actor_height);
14080 *x = actor_width * coord->v.fraction.x;
14083 *y = actor_height * coord->v.fraction.y;
14091 *x = coord->v.units.x;
14094 *y = coord->v.units.y;
14097 *z = coord->v.units.z;
14102 clutter_anchor_coord_set_units (AnchorCoord *coord,
14107 coord->is_fractional = FALSE;
14108 coord->v.units.x = x;
14109 coord->v.units.y = y;
14110 coord->v.units.z = z;
14113 static ClutterGravity
14114 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14116 if (coord->is_fractional)
14118 if (coord->v.fraction.x == 0.0)
14120 if (coord->v.fraction.y == 0.0)
14121 return CLUTTER_GRAVITY_NORTH_WEST;
14122 else if (coord->v.fraction.y == 0.5)
14123 return CLUTTER_GRAVITY_WEST;
14124 else if (coord->v.fraction.y == 1.0)
14125 return CLUTTER_GRAVITY_SOUTH_WEST;
14127 return CLUTTER_GRAVITY_NONE;
14129 else if (coord->v.fraction.x == 0.5)
14131 if (coord->v.fraction.y == 0.0)
14132 return CLUTTER_GRAVITY_NORTH;
14133 else if (coord->v.fraction.y == 0.5)
14134 return CLUTTER_GRAVITY_CENTER;
14135 else if (coord->v.fraction.y == 1.0)
14136 return CLUTTER_GRAVITY_SOUTH;
14138 return CLUTTER_GRAVITY_NONE;
14140 else if (coord->v.fraction.x == 1.0)
14142 if (coord->v.fraction.y == 0.0)
14143 return CLUTTER_GRAVITY_NORTH_EAST;
14144 else if (coord->v.fraction.y == 0.5)
14145 return CLUTTER_GRAVITY_EAST;
14146 else if (coord->v.fraction.y == 1.0)
14147 return CLUTTER_GRAVITY_SOUTH_EAST;
14149 return CLUTTER_GRAVITY_NONE;
14152 return CLUTTER_GRAVITY_NONE;
14155 return CLUTTER_GRAVITY_NONE;
14159 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14160 ClutterGravity gravity)
14164 case CLUTTER_GRAVITY_NORTH:
14165 coord->v.fraction.x = 0.5;
14166 coord->v.fraction.y = 0.0;
14169 case CLUTTER_GRAVITY_NORTH_EAST:
14170 coord->v.fraction.x = 1.0;
14171 coord->v.fraction.y = 0.0;
14174 case CLUTTER_GRAVITY_EAST:
14175 coord->v.fraction.x = 1.0;
14176 coord->v.fraction.y = 0.5;
14179 case CLUTTER_GRAVITY_SOUTH_EAST:
14180 coord->v.fraction.x = 1.0;
14181 coord->v.fraction.y = 1.0;
14184 case CLUTTER_GRAVITY_SOUTH:
14185 coord->v.fraction.x = 0.5;
14186 coord->v.fraction.y = 1.0;
14189 case CLUTTER_GRAVITY_SOUTH_WEST:
14190 coord->v.fraction.x = 0.0;
14191 coord->v.fraction.y = 1.0;
14194 case CLUTTER_GRAVITY_WEST:
14195 coord->v.fraction.x = 0.0;
14196 coord->v.fraction.y = 0.5;
14199 case CLUTTER_GRAVITY_NORTH_WEST:
14200 coord->v.fraction.x = 0.0;
14201 coord->v.fraction.y = 0.0;
14204 case CLUTTER_GRAVITY_CENTER:
14205 coord->v.fraction.x = 0.5;
14206 coord->v.fraction.y = 0.5;
14210 coord->v.fraction.x = 0.0;
14211 coord->v.fraction.y = 0.0;
14215 coord->is_fractional = TRUE;
14219 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14221 if (coord->is_fractional)
14222 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14224 return (coord->v.units.x == 0.0
14225 && coord->v.units.y == 0.0
14226 && coord->v.units.z == 0.0);
14230 * clutter_actor_get_flags:
14231 * @self: a #ClutterActor
14233 * Retrieves the flags set on @self
14235 * Return value: a bitwise or of #ClutterActorFlags or 0
14240 clutter_actor_get_flags (ClutterActor *self)
14242 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14244 return self->flags;
14248 * clutter_actor_set_flags:
14249 * @self: a #ClutterActor
14250 * @flags: the flags to set
14252 * Sets @flags on @self
14254 * This function will emit notifications for the changed properties
14259 clutter_actor_set_flags (ClutterActor *self,
14260 ClutterActorFlags flags)
14262 ClutterActorFlags old_flags;
14264 gboolean was_reactive_set, reactive_set;
14265 gboolean was_realized_set, realized_set;
14266 gboolean was_mapped_set, mapped_set;
14267 gboolean was_visible_set, visible_set;
14269 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14271 if (self->flags == flags)
14274 obj = G_OBJECT (self);
14275 g_object_ref (obj);
14276 g_object_freeze_notify (obj);
14278 old_flags = self->flags;
14280 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14281 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14282 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14283 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14285 self->flags |= flags;
14287 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14288 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14289 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14290 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14292 if (reactive_set != was_reactive_set)
14293 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14295 if (realized_set != was_realized_set)
14296 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14298 if (mapped_set != was_mapped_set)
14299 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14301 if (visible_set != was_visible_set)
14302 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14304 g_object_thaw_notify (obj);
14305 g_object_unref (obj);
14309 * clutter_actor_unset_flags:
14310 * @self: a #ClutterActor
14311 * @flags: the flags to unset
14313 * Unsets @flags on @self
14315 * This function will emit notifications for the changed properties
14320 clutter_actor_unset_flags (ClutterActor *self,
14321 ClutterActorFlags flags)
14323 ClutterActorFlags old_flags;
14325 gboolean was_reactive_set, reactive_set;
14326 gboolean was_realized_set, realized_set;
14327 gboolean was_mapped_set, mapped_set;
14328 gboolean was_visible_set, visible_set;
14330 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14332 obj = G_OBJECT (self);
14333 g_object_freeze_notify (obj);
14335 old_flags = self->flags;
14337 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14338 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14339 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14340 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14342 self->flags &= ~flags;
14344 if (self->flags == old_flags)
14347 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14348 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14349 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14350 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14352 if (reactive_set != was_reactive_set)
14353 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14355 if (realized_set != was_realized_set)
14356 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14358 if (mapped_set != was_mapped_set)
14359 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14361 if (visible_set != was_visible_set)
14362 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14364 g_object_thaw_notify (obj);
14368 * clutter_actor_get_transformation_matrix:
14369 * @self: a #ClutterActor
14370 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14372 * Retrieves the transformations applied to @self relative to its
14378 clutter_actor_get_transformation_matrix (ClutterActor *self,
14379 CoglMatrix *matrix)
14381 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14383 cogl_matrix_init_identity (matrix);
14385 _clutter_actor_apply_modelview_transform (self, matrix);
14389 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14390 gboolean is_in_clone_paint)
14392 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14393 self->priv->in_clone_paint = is_in_clone_paint;
14397 * clutter_actor_is_in_clone_paint:
14398 * @self: a #ClutterActor
14400 * Checks whether @self is being currently painted by a #ClutterClone
14402 * This function is useful only inside the ::paint virtual function
14403 * implementations or within handlers for the #ClutterActor::paint
14406 * This function should not be used by applications
14408 * Return value: %TRUE if the #ClutterActor is currently being painted
14409 * by a #ClutterClone, and %FALSE otherwise
14414 clutter_actor_is_in_clone_paint (ClutterActor *self)
14416 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14418 return self->priv->in_clone_paint;
14422 set_direction_recursive (ClutterActor *actor,
14423 gpointer user_data)
14425 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14427 clutter_actor_set_text_direction (actor, text_dir);
14433 * clutter_actor_set_text_direction:
14434 * @self: a #ClutterActor
14435 * @text_dir: the text direction for @self
14437 * Sets the #ClutterTextDirection for an actor
14439 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14441 * If @self implements #ClutterContainer then this function will recurse
14442 * inside all the children of @self (including the internal ones).
14444 * Composite actors not implementing #ClutterContainer, or actors requiring
14445 * special handling when the text direction changes, should connect to
14446 * the #GObject::notify signal for the #ClutterActor:text-direction property
14451 clutter_actor_set_text_direction (ClutterActor *self,
14452 ClutterTextDirection text_dir)
14454 ClutterActorPrivate *priv;
14456 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14457 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14461 if (priv->text_direction != text_dir)
14463 priv->text_direction = text_dir;
14465 /* we need to emit the notify::text-direction first, so that
14466 * the sub-classes can catch that and do specific handling of
14467 * the text direction; see clutter_text_direction_changed_cb()
14468 * inside clutter-text.c
14470 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14472 _clutter_actor_foreach_child (self, set_direction_recursive,
14473 GINT_TO_POINTER (text_dir));
14475 clutter_actor_queue_relayout (self);
14480 _clutter_actor_set_has_pointer (ClutterActor *self,
14481 gboolean has_pointer)
14483 ClutterActorPrivate *priv = self->priv;
14485 if (priv->has_pointer != has_pointer)
14487 priv->has_pointer = has_pointer;
14489 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14494 * clutter_actor_get_text_direction:
14495 * @self: a #ClutterActor
14497 * Retrieves the value set using clutter_actor_set_text_direction()
14499 * If no text direction has been previously set, the default text
14500 * direction, as returned by clutter_get_default_text_direction(), will
14501 * be returned instead
14503 * Return value: the #ClutterTextDirection for the actor
14507 ClutterTextDirection
14508 clutter_actor_get_text_direction (ClutterActor *self)
14510 ClutterActorPrivate *priv;
14512 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14513 CLUTTER_TEXT_DIRECTION_LTR);
14517 /* if no direction has been set yet use the default */
14518 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14519 priv->text_direction = clutter_get_default_text_direction ();
14521 return priv->text_direction;
14525 * clutter_actor_push_internal:
14526 * @self: a #ClutterActor
14528 * Should be used by actors implementing the #ClutterContainer and with
14529 * internal children added through clutter_actor_set_parent(), for instance:
14533 * my_actor_init (MyActor *self)
14535 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14537 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14539 * /* calling clutter_actor_set_parent() now will result in
14540 * * the internal flag being set on a child of MyActor
14543 * /* internal child - a background texture */
14544 * self->priv->background_tex = clutter_texture_new ();
14545 * clutter_actor_set_parent (self->priv->background_tex,
14546 * CLUTTER_ACTOR (self));
14548 * /* internal child - a label */
14549 * self->priv->label = clutter_text_new ();
14550 * clutter_actor_set_parent (self->priv->label,
14551 * CLUTTER_ACTOR (self));
14553 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14555 * /* calling clutter_actor_set_parent() now will not result in
14556 * * the internal flag being set on a child of MyActor
14561 * This function will be used by Clutter to toggle an "internal child"
14562 * flag whenever clutter_actor_set_parent() is called; internal children
14563 * are handled differently by Clutter, specifically when destroying their
14566 * Call clutter_actor_pop_internal() when you finished adding internal
14569 * Nested calls to clutter_actor_push_internal() are allowed, but each
14570 * one must by followed by a clutter_actor_pop_internal() call.
14574 * Deprecated: 1.10: All children of an actor are accessible through
14575 * the #ClutterActor API, and #ClutterActor implements the
14576 * #ClutterContainer interface, so this function is only useful
14577 * for legacy containers overriding the default implementation.
14580 clutter_actor_push_internal (ClutterActor *self)
14582 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14584 self->priv->internal_child += 1;
14588 * clutter_actor_pop_internal:
14589 * @self: a #ClutterActor
14591 * Disables the effects of clutter_actor_push_internal().
14595 * Deprecated: 1.10: All children of an actor are accessible through
14596 * the #ClutterActor API. This function is only useful for legacy
14597 * containers overriding the default implementation of the
14598 * #ClutterContainer interface.
14601 clutter_actor_pop_internal (ClutterActor *self)
14603 ClutterActorPrivate *priv;
14605 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14609 if (priv->internal_child == 0)
14611 g_warning ("Mismatched %s: you need to call "
14612 "clutter_actor_push_composite() at least once before "
14613 "calling this function", G_STRFUNC);
14617 priv->internal_child -= 1;
14621 * clutter_actor_has_pointer:
14622 * @self: a #ClutterActor
14624 * Checks whether an actor contains the pointer of a
14625 * #ClutterInputDevice
14627 * Return value: %TRUE if the actor contains the pointer, and
14633 clutter_actor_has_pointer (ClutterActor *self)
14635 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14637 return self->priv->has_pointer;
14640 /* XXX: This is a workaround for not being able to break the ABI of
14641 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14642 * clutter_actor_queue_clipped_redraw() for details.
14644 ClutterPaintVolume *
14645 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14647 return g_object_get_data (G_OBJECT (self),
14648 "-clutter-actor-queue-redraw-clip");
14652 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14653 ClutterPaintVolume *clip)
14655 g_object_set_data (G_OBJECT (self),
14656 "-clutter-actor-queue-redraw-clip",
14661 * clutter_actor_has_allocation:
14662 * @self: a #ClutterActor
14664 * Checks if the actor has an up-to-date allocation assigned to
14665 * it. This means that the actor should have an allocation: it's
14666 * visible and has a parent. It also means that there is no
14667 * outstanding relayout request in progress for the actor or its
14668 * children (There might be other outstanding layout requests in
14669 * progress that will cause the actor to get a new allocation
14670 * when the stage is laid out, however).
14672 * If this function returns %FALSE, then the actor will normally
14673 * be allocated before it is next drawn on the screen.
14675 * Return value: %TRUE if the actor has an up-to-date allocation
14680 clutter_actor_has_allocation (ClutterActor *self)
14682 ClutterActorPrivate *priv;
14684 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14688 return priv->parent != NULL &&
14689 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14690 !priv->needs_allocation;
14694 * clutter_actor_add_action:
14695 * @self: a #ClutterActor
14696 * @action: a #ClutterAction
14698 * Adds @action to the list of actions applied to @self
14700 * A #ClutterAction can only belong to one actor at a time
14702 * The #ClutterActor will hold a reference on @action until either
14703 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14709 clutter_actor_add_action (ClutterActor *self,
14710 ClutterAction *action)
14712 ClutterActorPrivate *priv;
14714 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14715 g_return_if_fail (CLUTTER_IS_ACTION (action));
14719 if (priv->actions == NULL)
14721 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14722 priv->actions->actor = self;
14725 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14727 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14731 * clutter_actor_add_action_with_name:
14732 * @self: a #ClutterActor
14733 * @name: the name to set on the action
14734 * @action: a #ClutterAction
14736 * A convenience function for setting the name of a #ClutterAction
14737 * while adding it to the list of actions applied to @self
14739 * This function is the logical equivalent of:
14742 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14743 * clutter_actor_add_action (self, action);
14749 clutter_actor_add_action_with_name (ClutterActor *self,
14751 ClutterAction *action)
14753 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14754 g_return_if_fail (name != NULL);
14755 g_return_if_fail (CLUTTER_IS_ACTION (action));
14757 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14758 clutter_actor_add_action (self, action);
14762 * clutter_actor_remove_action:
14763 * @self: a #ClutterActor
14764 * @action: a #ClutterAction
14766 * Removes @action from the list of actions applied to @self
14768 * The reference held by @self on the #ClutterAction will be released
14773 clutter_actor_remove_action (ClutterActor *self,
14774 ClutterAction *action)
14776 ClutterActorPrivate *priv;
14778 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14779 g_return_if_fail (CLUTTER_IS_ACTION (action));
14783 if (priv->actions == NULL)
14786 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14788 if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14789 g_clear_object (&priv->actions);
14791 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14795 * clutter_actor_remove_action_by_name:
14796 * @self: a #ClutterActor
14797 * @name: the name of the action to remove
14799 * Removes the #ClutterAction with the given name from the list
14800 * of actions applied to @self
14805 clutter_actor_remove_action_by_name (ClutterActor *self,
14808 ClutterActorPrivate *priv;
14809 ClutterActorMeta *meta;
14811 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14812 g_return_if_fail (name != NULL);
14816 if (priv->actions == NULL)
14819 meta = _clutter_meta_group_get_meta (priv->actions, name);
14823 _clutter_meta_group_remove_meta (priv->actions, meta);
14825 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14829 * clutter_actor_get_actions:
14830 * @self: a #ClutterActor
14832 * Retrieves the list of actions applied to @self
14834 * Return value: (transfer container) (element-type Clutter.Action): a copy
14835 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14836 * owned by the #ClutterActor. Use g_list_free() to free the resources
14837 * allocated by the returned #GList
14842 clutter_actor_get_actions (ClutterActor *self)
14844 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14846 if (self->priv->actions == NULL)
14849 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14853 * clutter_actor_get_action:
14854 * @self: a #ClutterActor
14855 * @name: the name of the action to retrieve
14857 * Retrieves the #ClutterAction with the given name in the list
14858 * of actions applied to @self
14860 * Return value: (transfer none): a #ClutterAction for the given
14861 * name, or %NULL. The returned #ClutterAction is owned by the
14862 * actor and it should not be unreferenced directly
14867 clutter_actor_get_action (ClutterActor *self,
14870 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14871 g_return_val_if_fail (name != NULL, NULL);
14873 if (self->priv->actions == NULL)
14876 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14880 * clutter_actor_clear_actions:
14881 * @self: a #ClutterActor
14883 * Clears the list of actions applied to @self
14888 clutter_actor_clear_actions (ClutterActor *self)
14890 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14892 if (self->priv->actions == NULL)
14895 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14899 * clutter_actor_add_constraint:
14900 * @self: a #ClutterActor
14901 * @constraint: a #ClutterConstraint
14903 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14906 * The #ClutterActor will hold a reference on the @constraint until
14907 * either clutter_actor_remove_constraint() or
14908 * clutter_actor_clear_constraints() is called.
14913 clutter_actor_add_constraint (ClutterActor *self,
14914 ClutterConstraint *constraint)
14916 ClutterActorPrivate *priv;
14918 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14919 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14923 if (priv->constraints == NULL)
14925 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14926 priv->constraints->actor = self;
14929 _clutter_meta_group_add_meta (priv->constraints,
14930 CLUTTER_ACTOR_META (constraint));
14931 clutter_actor_queue_relayout (self);
14933 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14937 * clutter_actor_add_constraint_with_name:
14938 * @self: a #ClutterActor
14939 * @name: the name to set on the constraint
14940 * @constraint: a #ClutterConstraint
14942 * A convenience function for setting the name of a #ClutterConstraint
14943 * while adding it to the list of constraints applied to @self
14945 * This function is the logical equivalent of:
14948 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14949 * clutter_actor_add_constraint (self, constraint);
14955 clutter_actor_add_constraint_with_name (ClutterActor *self,
14957 ClutterConstraint *constraint)
14959 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14960 g_return_if_fail (name != NULL);
14961 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14963 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14964 clutter_actor_add_constraint (self, constraint);
14968 * clutter_actor_remove_constraint:
14969 * @self: a #ClutterActor
14970 * @constraint: a #ClutterConstraint
14972 * Removes @constraint from the list of constraints applied to @self
14974 * The reference held by @self on the #ClutterConstraint will be released
14979 clutter_actor_remove_constraint (ClutterActor *self,
14980 ClutterConstraint *constraint)
14982 ClutterActorPrivate *priv;
14984 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14985 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14989 if (priv->constraints == NULL)
14992 _clutter_meta_group_remove_meta (priv->constraints,
14993 CLUTTER_ACTOR_META (constraint));
14995 if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
14996 g_clear_object (&priv->constraints);
14998 clutter_actor_queue_relayout (self);
15000 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15004 * clutter_actor_remove_constraint_by_name:
15005 * @self: a #ClutterActor
15006 * @name: the name of the constraint to remove
15008 * Removes the #ClutterConstraint with the given name from the list
15009 * of constraints applied to @self
15014 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15017 ClutterActorPrivate *priv;
15018 ClutterActorMeta *meta;
15020 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15021 g_return_if_fail (name != NULL);
15025 if (priv->constraints == NULL)
15028 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15032 _clutter_meta_group_remove_meta (priv->constraints, meta);
15033 clutter_actor_queue_relayout (self);
15037 * clutter_actor_get_constraints:
15038 * @self: a #ClutterActor
15040 * Retrieves the list of constraints applied to @self
15042 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15043 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15044 * owned by the #ClutterActor. Use g_list_free() to free the resources
15045 * allocated by the returned #GList
15050 clutter_actor_get_constraints (ClutterActor *self)
15052 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15054 if (self->priv->constraints == NULL)
15057 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15061 * clutter_actor_get_constraint:
15062 * @self: a #ClutterActor
15063 * @name: the name of the constraint to retrieve
15065 * Retrieves the #ClutterConstraint with the given name in the list
15066 * of constraints applied to @self
15068 * Return value: (transfer none): a #ClutterConstraint for the given
15069 * name, or %NULL. The returned #ClutterConstraint is owned by the
15070 * actor and it should not be unreferenced directly
15074 ClutterConstraint *
15075 clutter_actor_get_constraint (ClutterActor *self,
15078 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15079 g_return_val_if_fail (name != NULL, NULL);
15081 if (self->priv->constraints == NULL)
15084 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15088 * clutter_actor_clear_constraints:
15089 * @self: a #ClutterActor
15091 * Clears the list of constraints applied to @self
15096 clutter_actor_clear_constraints (ClutterActor *self)
15098 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15100 if (self->priv->constraints == NULL)
15103 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15105 clutter_actor_queue_relayout (self);
15109 * clutter_actor_set_clip_to_allocation:
15110 * @self: a #ClutterActor
15111 * @clip_set: %TRUE to apply a clip tracking the allocation
15113 * Sets whether @self should be clipped to the same size as its
15119 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15122 ClutterActorPrivate *priv;
15124 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15126 clip_set = !!clip_set;
15130 if (priv->clip_to_allocation != clip_set)
15132 priv->clip_to_allocation = clip_set;
15134 clutter_actor_queue_redraw (self);
15136 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15141 * clutter_actor_get_clip_to_allocation:
15142 * @self: a #ClutterActor
15144 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15146 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15151 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15153 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15155 return self->priv->clip_to_allocation;
15159 * clutter_actor_add_effect:
15160 * @self: a #ClutterActor
15161 * @effect: a #ClutterEffect
15163 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15165 * The #ClutterActor will hold a reference on the @effect until either
15166 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15172 clutter_actor_add_effect (ClutterActor *self,
15173 ClutterEffect *effect)
15175 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15176 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15178 _clutter_actor_add_effect_internal (self, effect);
15180 clutter_actor_queue_redraw (self);
15182 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15186 * clutter_actor_add_effect_with_name:
15187 * @self: a #ClutterActor
15188 * @name: the name to set on the effect
15189 * @effect: a #ClutterEffect
15191 * A convenience function for setting the name of a #ClutterEffect
15192 * while adding it to the list of effectss applied to @self
15194 * This function is the logical equivalent of:
15197 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15198 * clutter_actor_add_effect (self, effect);
15204 clutter_actor_add_effect_with_name (ClutterActor *self,
15206 ClutterEffect *effect)
15208 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15209 g_return_if_fail (name != NULL);
15210 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15212 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15213 clutter_actor_add_effect (self, effect);
15217 * clutter_actor_remove_effect:
15218 * @self: a #ClutterActor
15219 * @effect: a #ClutterEffect
15221 * Removes @effect from the list of effects applied to @self
15223 * The reference held by @self on the #ClutterEffect will be released
15228 clutter_actor_remove_effect (ClutterActor *self,
15229 ClutterEffect *effect)
15231 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15232 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15234 _clutter_actor_remove_effect_internal (self, effect);
15236 clutter_actor_queue_redraw (self);
15238 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15242 * clutter_actor_remove_effect_by_name:
15243 * @self: a #ClutterActor
15244 * @name: the name of the effect to remove
15246 * Removes the #ClutterEffect with the given name from the list
15247 * of effects applied to @self
15252 clutter_actor_remove_effect_by_name (ClutterActor *self,
15255 ClutterActorPrivate *priv;
15256 ClutterActorMeta *meta;
15258 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15259 g_return_if_fail (name != NULL);
15263 if (priv->effects == NULL)
15266 meta = _clutter_meta_group_get_meta (priv->effects, name);
15270 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15274 * clutter_actor_get_effects:
15275 * @self: a #ClutterActor
15277 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15279 * Return value: (transfer container) (element-type Clutter.Effect): a list
15280 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15281 * list are owned by Clutter and they should not be freed. You should
15282 * free the returned list using g_list_free() when done
15287 clutter_actor_get_effects (ClutterActor *self)
15289 ClutterActorPrivate *priv;
15291 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15295 if (priv->effects == NULL)
15298 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15302 * clutter_actor_get_effect:
15303 * @self: a #ClutterActor
15304 * @name: the name of the effect to retrieve
15306 * Retrieves the #ClutterEffect with the given name in the list
15307 * of effects applied to @self
15309 * Return value: (transfer none): a #ClutterEffect for the given
15310 * name, or %NULL. The returned #ClutterEffect is owned by the
15311 * actor and it should not be unreferenced directly
15316 clutter_actor_get_effect (ClutterActor *self,
15319 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15320 g_return_val_if_fail (name != NULL, NULL);
15322 if (self->priv->effects == NULL)
15325 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15329 * clutter_actor_clear_effects:
15330 * @self: a #ClutterActor
15332 * Clears the list of effects applied to @self
15337 clutter_actor_clear_effects (ClutterActor *self)
15339 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15341 if (self->priv->effects == NULL)
15344 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15346 clutter_actor_queue_redraw (self);
15350 * clutter_actor_has_key_focus:
15351 * @self: a #ClutterActor
15353 * Checks whether @self is the #ClutterActor that has key focus
15355 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15360 clutter_actor_has_key_focus (ClutterActor *self)
15362 ClutterActor *stage;
15364 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15366 stage = _clutter_actor_get_stage_internal (self);
15370 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15374 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15375 ClutterPaintVolume *pv)
15377 ClutterActorPrivate *priv = self->priv;
15379 /* Actors are only expected to report a valid paint volume
15380 * while they have a valid allocation. */
15381 if (G_UNLIKELY (priv->needs_allocation))
15383 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15384 "Actor needs allocation",
15385 _clutter_actor_get_debug_name (self));
15389 /* Check if there are any handlers connected to the paint
15390 * signal. If there are then all bets are off for what the paint
15391 * volume for this actor might possibly be!
15393 * XXX: It's expected that this is going to end up being quite a
15394 * costly check to have to do here, but we haven't come up with
15395 * another solution that can reliably catch paint signal handlers at
15396 * the right time to either avoid artefacts due to invalid stage
15397 * clipping or due to incorrect culling.
15399 * Previously we checked in clutter_actor_paint(), but at that time
15400 * we may already be using a stage clip that could be derived from
15401 * an invalid paint-volume. We used to try and handle that by
15402 * queuing a follow up, unclipped, redraw but still the previous
15403 * checking wasn't enough to catch invalid volumes involved in
15404 * culling (considering that containers may derive their volume from
15405 * children that haven't yet been painted)
15407 * Longer term, improved solutions could be:
15408 * - Disallow painting in the paint signal, only allow using it
15409 * for tracking when paints happen. We can add another API that
15410 * allows monkey patching the paint of arbitrary actors but in a
15411 * more controlled way and that also supports modifying the
15413 * - If we could be notified somehow when signal handlers are
15414 * connected we wouldn't have to poll for handlers like this.
15416 if (g_signal_has_handler_pending (self,
15417 actor_signals[PAINT],
15421 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15422 "Actor has \"paint\" signal handlers",
15423 _clutter_actor_get_debug_name (self));
15427 _clutter_paint_volume_init_static (pv, self);
15429 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15431 clutter_paint_volume_free (pv);
15432 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15433 "Actor failed to report a volume",
15434 _clutter_actor_get_debug_name (self));
15438 /* since effects can modify the paint volume, we allow them to actually
15439 * do this by making get_paint_volume() "context sensitive"
15441 if (priv->effects != NULL)
15443 if (priv->current_effect != NULL)
15445 const GList *effects, *l;
15447 /* if we are being called from within the paint sequence of
15448 * an actor, get the paint volume up to the current effect
15450 effects = _clutter_meta_group_peek_metas (priv->effects);
15452 l != NULL || (l != NULL && l->data != priv->current_effect);
15455 if (!_clutter_effect_get_paint_volume (l->data, pv))
15457 clutter_paint_volume_free (pv);
15458 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15459 "Effect (%s) failed to report a volume",
15460 _clutter_actor_get_debug_name (self),
15461 _clutter_actor_meta_get_debug_name (l->data));
15468 const GList *effects, *l;
15470 /* otherwise, get the cumulative volume */
15471 effects = _clutter_meta_group_peek_metas (priv->effects);
15472 for (l = effects; l != NULL; l = l->next)
15473 if (!_clutter_effect_get_paint_volume (l->data, pv))
15475 clutter_paint_volume_free (pv);
15476 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15477 "Effect (%s) failed to report a volume",
15478 _clutter_actor_get_debug_name (self),
15479 _clutter_actor_meta_get_debug_name (l->data));
15488 /* The public clutter_actor_get_paint_volume API returns a const
15489 * pointer since we return a pointer directly to the cached
15490 * PaintVolume associated with the actor and don't want the user to
15491 * inadvertently modify it, but for internal uses we sometimes need
15492 * access to the same PaintVolume but need to apply some book-keeping
15493 * modifications to it so we don't want a const pointer.
15495 static ClutterPaintVolume *
15496 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15498 ClutterActorPrivate *priv;
15502 if (priv->paint_volume_valid)
15503 clutter_paint_volume_free (&priv->paint_volume);
15505 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15507 priv->paint_volume_valid = TRUE;
15508 return &priv->paint_volume;
15512 priv->paint_volume_valid = FALSE;
15518 * clutter_actor_get_paint_volume:
15519 * @self: a #ClutterActor
15521 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15522 * when a paint volume can't be determined.
15524 * The paint volume is defined as the 3D space occupied by an actor
15525 * when being painted.
15527 * This function will call the <function>get_paint_volume()</function>
15528 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15529 * should not usually care about overriding the default implementation,
15530 * unless they are, for instance: painting outside their allocation, or
15531 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15534 * <note>2D actors overriding <function>get_paint_volume()</function>
15535 * ensure their volume has a depth of 0. (This will be true so long as
15536 * you don't call clutter_paint_volume_set_depth().)</note>
15538 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15539 * or %NULL if no volume could be determined. The returned pointer
15540 * is not guaranteed to be valid across multiple frames; if you want
15541 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15545 const ClutterPaintVolume *
15546 clutter_actor_get_paint_volume (ClutterActor *self)
15548 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15550 return _clutter_actor_get_paint_volume_mutable (self);
15554 * clutter_actor_get_transformed_paint_volume:
15555 * @self: a #ClutterActor
15556 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15557 * (or %NULL for the stage)
15559 * Retrieves the 3D paint volume of an actor like
15560 * clutter_actor_get_paint_volume() does (Please refer to the
15561 * documentation of clutter_actor_get_paint_volume() for more
15562 * details.) and it additionally transforms the paint volume into the
15563 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15564 * is passed for @relative_to_ancestor)
15566 * This can be used by containers that base their paint volume on
15567 * the volume of their children. Such containers can query the
15568 * transformed paint volume of all of its children and union them
15569 * together using clutter_paint_volume_union().
15571 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15572 * or %NULL if no volume could be determined. The returned pointer is
15573 * not guaranteed to be valid across multiple frames; if you wish to
15574 * keep it, you will have to copy it using clutter_paint_volume_copy().
15578 const ClutterPaintVolume *
15579 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15580 ClutterActor *relative_to_ancestor)
15582 const ClutterPaintVolume *volume;
15583 ClutterActor *stage;
15584 ClutterPaintVolume *transformed_volume;
15586 stage = _clutter_actor_get_stage_internal (self);
15587 if (G_UNLIKELY (stage == NULL))
15590 if (relative_to_ancestor == NULL)
15591 relative_to_ancestor = stage;
15593 volume = clutter_actor_get_paint_volume (self);
15594 if (volume == NULL)
15597 transformed_volume =
15598 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15600 _clutter_paint_volume_copy_static (volume, transformed_volume);
15602 _clutter_paint_volume_transform_relative (transformed_volume,
15603 relative_to_ancestor);
15605 return transformed_volume;
15609 * clutter_actor_get_paint_box:
15610 * @self: a #ClutterActor
15611 * @box: (out): return location for a #ClutterActorBox
15613 * Retrieves the paint volume of the passed #ClutterActor, and
15614 * transforms it into a 2D bounding box in stage coordinates.
15616 * This function is useful to determine the on screen area occupied by
15617 * the actor. The box is only an approximation and may often be
15618 * considerably larger due to the optimizations used to calculate the
15619 * box. The box is never smaller though, so it can reliably be used
15622 * There are times when a 2D paint box can't be determined, e.g.
15623 * because the actor isn't yet parented under a stage or because
15624 * the actor is unable to determine a paint volume.
15626 * Return value: %TRUE if a 2D paint box could be determined, else
15632 clutter_actor_get_paint_box (ClutterActor *self,
15633 ClutterActorBox *box)
15635 ClutterActor *stage;
15636 ClutterPaintVolume *pv;
15638 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15639 g_return_val_if_fail (box != NULL, FALSE);
15641 stage = _clutter_actor_get_stage_internal (self);
15642 if (G_UNLIKELY (!stage))
15645 pv = _clutter_actor_get_paint_volume_mutable (self);
15646 if (G_UNLIKELY (!pv))
15649 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15655 * clutter_actor_has_overlaps:
15656 * @self: A #ClutterActor
15658 * Asks the actor's implementation whether it may contain overlapping
15661 * For example; Clutter may use this to determine whether the painting
15662 * should be redirected to an offscreen buffer to correctly implement
15663 * the opacity property.
15665 * Custom actors can override the default response by implementing the
15666 * #ClutterActor <function>has_overlaps</function> virtual function. See
15667 * clutter_actor_set_offscreen_redirect() for more information.
15669 * Return value: %TRUE if the actor may have overlapping primitives, and
15675 clutter_actor_has_overlaps (ClutterActor *self)
15677 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15679 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15683 * clutter_actor_has_effects:
15684 * @self: A #ClutterActor
15686 * Returns whether the actor has any effects applied.
15688 * Return value: %TRUE if the actor has any effects,
15694 clutter_actor_has_effects (ClutterActor *self)
15696 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15698 if (self->priv->effects == NULL)
15701 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15705 * clutter_actor_has_constraints:
15706 * @self: A #ClutterActor
15708 * Returns whether the actor has any constraints applied.
15710 * Return value: %TRUE if the actor has any constraints,
15716 clutter_actor_has_constraints (ClutterActor *self)
15718 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15720 return self->priv->constraints != NULL;
15724 * clutter_actor_has_actions:
15725 * @self: A #ClutterActor
15727 * Returns whether the actor has any actions applied.
15729 * Return value: %TRUE if the actor has any actions,
15735 clutter_actor_has_actions (ClutterActor *self)
15737 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15739 return self->priv->actions != NULL;
15743 * clutter_actor_get_n_children:
15744 * @self: a #ClutterActor
15746 * Retrieves the number of children of @self.
15748 * Return value: the number of children of an actor
15753 clutter_actor_get_n_children (ClutterActor *self)
15755 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15757 return self->priv->n_children;
15761 * clutter_actor_get_child_at_index:
15762 * @self: a #ClutterActor
15763 * @index_: the position in the list of children
15765 * Retrieves the actor at the given @index_ inside the list of
15766 * children of @self.
15768 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15773 clutter_actor_get_child_at_index (ClutterActor *self,
15776 ClutterActor *iter;
15779 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15780 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15782 for (iter = self->priv->first_child, i = 0;
15783 iter != NULL && i < index_;
15784 iter = iter->priv->next_sibling, i += 1)
15791 * _clutter_actor_foreach_child:
15792 * @actor: The actor whos children you want to iterate
15793 * @callback: The function to call for each child
15794 * @user_data: Private data to pass to @callback
15796 * Calls a given @callback once for each child of the specified @actor and
15797 * passing the @user_data pointer each time.
15799 * Return value: returns %TRUE if all children were iterated, else
15800 * %FALSE if a callback broke out of iteration early.
15803 _clutter_actor_foreach_child (ClutterActor *self,
15804 ClutterForeachCallback callback,
15805 gpointer user_data)
15807 ClutterActor *iter;
15810 if (self->priv->first_child == NULL)
15814 iter = self->priv->first_child;
15816 /* we use this form so that it's safe to change the children
15817 * list while iterating it
15819 while (cont && iter != NULL)
15821 ClutterActor *next = iter->priv->next_sibling;
15823 cont = callback (iter, user_data);
15832 /* For debugging purposes this gives us a simple way to print out
15833 * the scenegraph e.g in gdb using:
15835 * _clutter_actor_traverse (stage,
15837 * clutter_debug_print_actor_cb,
15842 static ClutterActorTraverseVisitFlags
15843 clutter_debug_print_actor_cb (ClutterActor *actor,
15847 g_print ("%*s%s:%p\n",
15849 _clutter_actor_get_debug_name (actor),
15852 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15857 _clutter_actor_traverse_breadth (ClutterActor *actor,
15858 ClutterTraverseCallback callback,
15859 gpointer user_data)
15861 GQueue *queue = g_queue_new ();
15862 ClutterActor dummy;
15863 int current_depth = 0;
15865 g_queue_push_tail (queue, actor);
15866 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15868 while ((actor = g_queue_pop_head (queue)))
15870 ClutterActorTraverseVisitFlags flags;
15872 if (actor == &dummy)
15875 g_queue_push_tail (queue, &dummy);
15879 flags = callback (actor, current_depth, user_data);
15880 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15882 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15884 ClutterActor *iter;
15886 for (iter = actor->priv->first_child;
15888 iter = iter->priv->next_sibling)
15890 g_queue_push_tail (queue, iter);
15895 g_queue_free (queue);
15898 static ClutterActorTraverseVisitFlags
15899 _clutter_actor_traverse_depth (ClutterActor *actor,
15900 ClutterTraverseCallback before_children_callback,
15901 ClutterTraverseCallback after_children_callback,
15903 gpointer user_data)
15905 ClutterActorTraverseVisitFlags flags;
15907 flags = before_children_callback (actor, current_depth, user_data);
15908 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15909 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15911 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15913 ClutterActor *iter;
15915 for (iter = actor->priv->first_child;
15917 iter = iter->priv->next_sibling)
15919 flags = _clutter_actor_traverse_depth (iter,
15920 before_children_callback,
15921 after_children_callback,
15925 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15926 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15930 if (after_children_callback)
15931 return after_children_callback (actor, current_depth, user_data);
15933 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15936 /* _clutter_actor_traverse:
15937 * @actor: The actor to start traversing the graph from
15938 * @flags: These flags may affect how the traversal is done
15939 * @before_children_callback: A function to call before visiting the
15940 * children of the current actor.
15941 * @after_children_callback: A function to call after visiting the
15942 * children of the current actor. (Ignored if
15943 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15944 * @user_data: The private data to pass to the callbacks
15946 * Traverses the scenegraph starting at the specified @actor and
15947 * descending through all its children and its children's children.
15948 * For each actor traversed @before_children_callback and
15949 * @after_children_callback are called with the specified
15950 * @user_data, before and after visiting that actor's children.
15952 * The callbacks can return flags that affect the ongoing traversal
15953 * such as by skipping over an actors children or bailing out of
15954 * any further traversing.
15957 _clutter_actor_traverse (ClutterActor *actor,
15958 ClutterActorTraverseFlags flags,
15959 ClutterTraverseCallback before_children_callback,
15960 ClutterTraverseCallback after_children_callback,
15961 gpointer user_data)
15963 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15964 _clutter_actor_traverse_breadth (actor,
15965 before_children_callback,
15967 else /* DEPTH_FIRST */
15968 _clutter_actor_traverse_depth (actor,
15969 before_children_callback,
15970 after_children_callback,
15971 0, /* start depth */
15976 on_layout_manager_changed (ClutterLayoutManager *manager,
15977 ClutterActor *self)
15979 clutter_actor_queue_relayout (self);
15983 * clutter_actor_set_layout_manager:
15984 * @self: a #ClutterActor
15985 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15987 * Sets the #ClutterLayoutManager delegate object that will be used to
15988 * lay out the children of @self.
15990 * The #ClutterActor will take a reference on the passed @manager which
15991 * will be released either when the layout manager is removed, or when
15992 * the actor is destroyed.
15997 clutter_actor_set_layout_manager (ClutterActor *self,
15998 ClutterLayoutManager *manager)
16000 ClutterActorPrivate *priv;
16002 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16003 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16007 if (priv->layout_manager != NULL)
16009 g_signal_handlers_disconnect_by_func (priv->layout_manager,
16010 G_CALLBACK (on_layout_manager_changed),
16012 clutter_layout_manager_set_container (priv->layout_manager, NULL);
16013 g_clear_object (&priv->layout_manager);
16016 priv->layout_manager = manager;
16018 if (priv->layout_manager != NULL)
16020 g_object_ref_sink (priv->layout_manager);
16021 clutter_layout_manager_set_container (priv->layout_manager,
16022 CLUTTER_CONTAINER (self));
16023 g_signal_connect (priv->layout_manager, "layout-changed",
16024 G_CALLBACK (on_layout_manager_changed),
16028 clutter_actor_queue_relayout (self);
16030 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16034 * clutter_actor_get_layout_manager:
16035 * @self: a #ClutterActor
16037 * Retrieves the #ClutterLayoutManager used by @self.
16039 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16044 ClutterLayoutManager *
16045 clutter_actor_get_layout_manager (ClutterActor *self)
16047 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16049 return self->priv->layout_manager;
16052 static const ClutterLayoutInfo default_layout_info = {
16055 { 0, 0, 0, 0 }, /* margin */
16056 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16057 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16058 0.f, 0.f, /* min_width, natural_width */
16059 0.f, 0.f, /* natual_width, natural_height */
16063 layout_info_free (gpointer data)
16065 if (G_LIKELY (data != NULL))
16066 g_slice_free (ClutterLayoutInfo, data);
16070 * _clutter_actor_get_layout_info:
16071 * @self: a #ClutterActor
16073 * Retrieves a pointer to the ClutterLayoutInfo structure.
16075 * If the actor does not have a ClutterLayoutInfo associated to it, one
16076 * will be created and initialized to the default values.
16078 * This function should be used for setters.
16080 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16083 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16085 ClutterLayoutInfo *
16086 _clutter_actor_get_layout_info (ClutterActor *self)
16088 ClutterLayoutInfo *retval;
16090 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16091 if (retval == NULL)
16093 retval = g_slice_new (ClutterLayoutInfo);
16095 *retval = default_layout_info;
16097 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16106 * _clutter_actor_get_layout_info_or_defaults:
16107 * @self: a #ClutterActor
16109 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16111 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16112 * then the default structure will be returned.
16114 * This function should only be used for getters.
16116 * Return value: a const pointer to the ClutterLayoutInfo structure
16118 const ClutterLayoutInfo *
16119 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16121 const ClutterLayoutInfo *info;
16123 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16125 return &default_layout_info;
16131 * clutter_actor_set_x_align:
16132 * @self: a #ClutterActor
16133 * @x_align: the horizontal alignment policy
16135 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16136 * actor received extra horizontal space.
16138 * See also the #ClutterActor:x-align property.
16143 clutter_actor_set_x_align (ClutterActor *self,
16144 ClutterActorAlign x_align)
16146 ClutterLayoutInfo *info;
16148 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16150 info = _clutter_actor_get_layout_info (self);
16152 if (info->x_align != x_align)
16154 info->x_align = x_align;
16156 clutter_actor_queue_relayout (self);
16158 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16163 * clutter_actor_get_x_align:
16164 * @self: a #ClutterActor
16166 * Retrieves the horizontal alignment policy set using
16167 * clutter_actor_set_x_align().
16169 * Return value: the horizontal alignment policy.
16174 clutter_actor_get_x_align (ClutterActor *self)
16176 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16178 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16182 * clutter_actor_set_y_align:
16183 * @self: a #ClutterActor
16184 * @y_align: the vertical alignment policy
16186 * Sets the vertical alignment policy of a #ClutterActor, in case the
16187 * actor received extra vertical space.
16189 * See also the #ClutterActor:y-align property.
16194 clutter_actor_set_y_align (ClutterActor *self,
16195 ClutterActorAlign y_align)
16197 ClutterLayoutInfo *info;
16199 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16201 info = _clutter_actor_get_layout_info (self);
16203 if (info->y_align != y_align)
16205 info->y_align = y_align;
16207 clutter_actor_queue_relayout (self);
16209 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16214 * clutter_actor_get_y_align:
16215 * @self: a #ClutterActor
16217 * Retrieves the vertical alignment policy set using
16218 * clutter_actor_set_y_align().
16220 * Return value: the vertical alignment policy.
16225 clutter_actor_get_y_align (ClutterActor *self)
16227 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16229 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16234 * clutter_margin_new:
16236 * Creates a new #ClutterMargin.
16238 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16239 * clutter_margin_free() to free the resources associated with it when
16245 clutter_margin_new (void)
16247 return g_slice_new0 (ClutterMargin);
16251 * clutter_margin_copy:
16252 * @margin_: a #ClutterMargin
16254 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16255 * the newly created structure.
16257 * Return value: (transfer full): a copy of the #ClutterMargin.
16262 clutter_margin_copy (const ClutterMargin *margin_)
16264 if (G_LIKELY (margin_ != NULL))
16265 return g_slice_dup (ClutterMargin, margin_);
16271 * clutter_margin_free:
16272 * @margin_: a #ClutterMargin
16274 * Frees the resources allocated by clutter_margin_new() and
16275 * clutter_margin_copy().
16280 clutter_margin_free (ClutterMargin *margin_)
16282 if (G_LIKELY (margin_ != NULL))
16283 g_slice_free (ClutterMargin, margin_);
16286 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16287 clutter_margin_copy,
16288 clutter_margin_free)
16291 * clutter_actor_set_margin:
16292 * @self: a #ClutterActor
16293 * @margin: a #ClutterMargin
16295 * Sets all the components of the margin of a #ClutterActor.
16300 clutter_actor_set_margin (ClutterActor *self,
16301 const ClutterMargin *margin)
16303 ClutterLayoutInfo *info;
16307 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16308 g_return_if_fail (margin != NULL);
16310 obj = G_OBJECT (self);
16313 g_object_freeze_notify (obj);
16315 info = _clutter_actor_get_layout_info (self);
16317 if (info->margin.top != margin->top)
16319 info->margin.top = margin->top;
16320 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16324 if (info->margin.right != margin->right)
16326 info->margin.right = margin->right;
16327 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16331 if (info->margin.bottom != margin->bottom)
16333 info->margin.bottom = margin->bottom;
16334 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16338 if (info->margin.left != margin->left)
16340 info->margin.left = margin->left;
16341 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16346 clutter_actor_queue_relayout (self);
16348 g_object_thaw_notify (obj);
16352 * clutter_actor_get_margin:
16353 * @self: a #ClutterActor
16354 * @margin: (out caller-allocates): return location for a #ClutterMargin
16356 * Retrieves all the components of the margin of a #ClutterActor.
16361 clutter_actor_get_margin (ClutterActor *self,
16362 ClutterMargin *margin)
16364 const ClutterLayoutInfo *info;
16366 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16367 g_return_if_fail (margin != NULL);
16369 info = _clutter_actor_get_layout_info_or_defaults (self);
16371 *margin = info->margin;
16375 * clutter_actor_set_margin_top:
16376 * @self: a #ClutterActor
16377 * @margin: the top margin
16379 * Sets the margin from the top of a #ClutterActor.
16384 clutter_actor_set_margin_top (ClutterActor *self,
16387 ClutterLayoutInfo *info;
16389 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16390 g_return_if_fail (margin >= 0.f);
16392 info = _clutter_actor_get_layout_info (self);
16394 if (info->margin.top == margin)
16397 info->margin.top = margin;
16399 clutter_actor_queue_relayout (self);
16401 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16405 * clutter_actor_get_margin_top:
16406 * @self: a #ClutterActor
16408 * Retrieves the top margin of a #ClutterActor.
16410 * Return value: the top margin
16415 clutter_actor_get_margin_top (ClutterActor *self)
16417 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16419 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16423 * clutter_actor_set_margin_bottom:
16424 * @self: a #ClutterActor
16425 * @margin: the bottom margin
16427 * Sets the margin from the bottom of a #ClutterActor.
16432 clutter_actor_set_margin_bottom (ClutterActor *self,
16435 ClutterLayoutInfo *info;
16437 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16438 g_return_if_fail (margin >= 0.f);
16440 info = _clutter_actor_get_layout_info (self);
16442 if (info->margin.bottom == margin)
16445 info->margin.bottom = margin;
16447 clutter_actor_queue_relayout (self);
16449 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16453 * clutter_actor_get_margin_bottom:
16454 * @self: a #ClutterActor
16456 * Retrieves the bottom margin of a #ClutterActor.
16458 * Return value: the bottom margin
16463 clutter_actor_get_margin_bottom (ClutterActor *self)
16465 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16467 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16471 * clutter_actor_set_margin_left:
16472 * @self: a #ClutterActor
16473 * @margin: the left margin
16475 * Sets the margin from the left of a #ClutterActor.
16480 clutter_actor_set_margin_left (ClutterActor *self,
16483 ClutterLayoutInfo *info;
16485 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16486 g_return_if_fail (margin >= 0.f);
16488 info = _clutter_actor_get_layout_info (self);
16490 if (info->margin.left == margin)
16493 info->margin.left = margin;
16495 clutter_actor_queue_relayout (self);
16497 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16501 * clutter_actor_get_margin_left:
16502 * @self: a #ClutterActor
16504 * Retrieves the left margin of a #ClutterActor.
16506 * Return value: the left margin
16511 clutter_actor_get_margin_left (ClutterActor *self)
16513 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16515 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16519 * clutter_actor_set_margin_right:
16520 * @self: a #ClutterActor
16521 * @margin: the right margin
16523 * Sets the margin from the right of a #ClutterActor.
16528 clutter_actor_set_margin_right (ClutterActor *self,
16531 ClutterLayoutInfo *info;
16533 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16534 g_return_if_fail (margin >= 0.f);
16536 info = _clutter_actor_get_layout_info (self);
16538 if (info->margin.right == margin)
16541 info->margin.right = margin;
16543 clutter_actor_queue_relayout (self);
16545 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16549 * clutter_actor_get_margin_right:
16550 * @self: a #ClutterActor
16552 * Retrieves the right margin of a #ClutterActor.
16554 * Return value: the right margin
16559 clutter_actor_get_margin_right (ClutterActor *self)
16561 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16563 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16567 clutter_actor_set_background_color_internal (ClutterActor *self,
16568 const ClutterColor *color)
16570 ClutterActorPrivate *priv = self->priv;
16573 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16576 obj = G_OBJECT (self);
16578 priv->bg_color = *color;
16579 priv->bg_color_set = TRUE;
16581 clutter_actor_queue_redraw (self);
16583 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16584 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16588 * clutter_actor_set_background_color:
16589 * @self: a #ClutterActor
16590 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16593 * Sets the background color of a #ClutterActor.
16595 * The background color will be used to cover the whole allocation of the
16596 * actor. The default background color of an actor is transparent.
16598 * To check whether an actor has a background color, you can use the
16599 * #ClutterActor:background-color-set actor property.
16601 * The #ClutterActor:background-color property is animatable.
16606 clutter_actor_set_background_color (ClutterActor *self,
16607 const ClutterColor *color)
16609 ClutterActorPrivate *priv;
16611 GParamSpec *bg_color_pspec;
16613 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16615 obj = G_OBJECT (self);
16621 priv->bg_color_set = FALSE;
16622 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16623 clutter_actor_queue_redraw (self);
16627 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16628 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16630 _clutter_actor_create_transition (self, bg_color_pspec,
16635 _clutter_actor_update_transition (self, bg_color_pspec, color);
16637 clutter_actor_queue_redraw (self);
16641 * clutter_actor_get_background_color:
16642 * @self: a #ClutterActor
16643 * @color: (out caller-allocates): return location for a #ClutterColor
16645 * Retrieves the color set using clutter_actor_set_background_color().
16650 clutter_actor_get_background_color (ClutterActor *self,
16651 ClutterColor *color)
16653 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16654 g_return_if_fail (color != NULL);
16656 *color = self->priv->bg_color;
16660 * clutter_actor_get_previous_sibling:
16661 * @self: a #ClutterActor
16663 * Retrieves the sibling of @self that comes before it in the list
16664 * of children of @self's parent.
16666 * The returned pointer is only valid until the scene graph changes; it
16667 * is not safe to modify the list of children of @self while iterating
16670 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16675 clutter_actor_get_previous_sibling (ClutterActor *self)
16677 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16679 return self->priv->prev_sibling;
16683 * clutter_actor_get_next_sibling:
16684 * @self: a #ClutterActor
16686 * Retrieves the sibling of @self that comes after it in the list
16687 * of children of @self's parent.
16689 * The returned pointer is only valid until the scene graph changes; it
16690 * is not safe to modify the list of children of @self while iterating
16693 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16698 clutter_actor_get_next_sibling (ClutterActor *self)
16700 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16702 return self->priv->next_sibling;
16706 * clutter_actor_get_first_child:
16707 * @self: a #ClutterActor
16709 * Retrieves the first child of @self.
16711 * The returned pointer is only valid until the scene graph changes; it
16712 * is not safe to modify the list of children of @self while iterating
16715 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16720 clutter_actor_get_first_child (ClutterActor *self)
16722 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16724 return self->priv->first_child;
16728 * clutter_actor_get_last_child:
16729 * @self: a #ClutterActor
16731 * Retrieves the last child of @self.
16733 * The returned pointer is only valid until the scene graph changes; it
16734 * is not safe to modify the list of children of @self while iterating
16737 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16742 clutter_actor_get_last_child (ClutterActor *self)
16744 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16746 return self->priv->last_child;
16749 /* easy way to have properly named fields instead of the dummy ones
16750 * we use in the public structure
16752 typedef struct _RealActorIter
16754 ClutterActor *root; /* dummy1 */
16755 ClutterActor *current; /* dummy2 */
16756 gpointer padding_1; /* dummy3 */
16757 gint age; /* dummy4 */
16758 gpointer padding_2; /* dummy5 */
16762 * clutter_actor_iter_init:
16763 * @iter: a #ClutterActorIter
16764 * @root: a #ClutterActor
16766 * Initializes a #ClutterActorIter, which can then be used to iterate
16767 * efficiently over a section of the scene graph, and associates it
16770 * Modifying the scene graph section that contains @root will invalidate
16774 * ClutterActorIter iter;
16775 * ClutterActor *child;
16777 * clutter_actor_iter_init (&iter, container);
16778 * while (clutter_actor_iter_next (&iter, &child))
16780 * /* do something with child */
16787 clutter_actor_iter_init (ClutterActorIter *iter,
16788 ClutterActor *root)
16790 RealActorIter *ri = (RealActorIter *) iter;
16792 g_return_if_fail (iter != NULL);
16793 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16796 ri->current = NULL;
16797 ri->age = root->priv->age;
16801 * clutter_actor_iter_next:
16802 * @iter: a #ClutterActorIter
16803 * @child: (out): return location for a #ClutterActor
16805 * Advances the @iter and retrieves the next child of the root #ClutterActor
16806 * that was used to initialize the #ClutterActorIterator.
16808 * If the iterator can advance, this function returns %TRUE and sets the
16811 * If the iterator cannot advance, this function returns %FALSE, and
16812 * the contents of @child are undefined.
16814 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16819 clutter_actor_iter_next (ClutterActorIter *iter,
16820 ClutterActor **child)
16822 RealActorIter *ri = (RealActorIter *) iter;
16824 g_return_val_if_fail (iter != NULL, FALSE);
16825 g_return_val_if_fail (ri->root != NULL, FALSE);
16826 #ifndef G_DISABLE_ASSERT
16827 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16830 if (ri->current == NULL)
16831 ri->current = ri->root->priv->first_child;
16833 ri->current = ri->current->priv->next_sibling;
16836 *child = ri->current;
16838 return ri->current != NULL;
16842 * clutter_actor_iter_prev:
16843 * @iter: a #ClutterActorIter
16844 * @child: (out): return location for a #ClutterActor
16846 * Advances the @iter and retrieves the previous child of the root
16847 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16849 * If the iterator can advance, this function returns %TRUE and sets the
16852 * If the iterator cannot advance, this function returns %FALSE, and
16853 * the contents of @child are undefined.
16855 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16860 clutter_actor_iter_prev (ClutterActorIter *iter,
16861 ClutterActor **child)
16863 RealActorIter *ri = (RealActorIter *) iter;
16865 g_return_val_if_fail (iter != NULL, FALSE);
16866 g_return_val_if_fail (ri->root != NULL, FALSE);
16867 #ifndef G_DISABLE_ASSERT
16868 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16871 if (ri->current == NULL)
16872 ri->current = ri->root->priv->last_child;
16874 ri->current = ri->current->priv->prev_sibling;
16877 *child = ri->current;
16879 return ri->current != NULL;
16883 * clutter_actor_iter_remove:
16884 * @iter: a #ClutterActorIter
16886 * Safely removes the #ClutterActor currently pointer to by the iterator
16889 * This function can only be called after clutter_actor_iter_next() or
16890 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16891 * than once for the same actor.
16893 * This function will call clutter_actor_remove_child() internally.
16898 clutter_actor_iter_remove (ClutterActorIter *iter)
16900 RealActorIter *ri = (RealActorIter *) iter;
16903 g_return_if_fail (iter != NULL);
16904 g_return_if_fail (ri->root != NULL);
16905 #ifndef G_DISABLE_ASSERT
16906 g_return_if_fail (ri->age == ri->root->priv->age);
16908 g_return_if_fail (ri->current != NULL);
16914 ri->current = cur->priv->prev_sibling;
16916 clutter_actor_remove_child_internal (ri->root, cur,
16917 REMOVE_CHILD_DEFAULT_FLAGS);
16924 * clutter_actor_iter_destroy:
16925 * @iter: a #ClutterActorIter
16927 * Safely destroys the #ClutterActor currently pointer to by the iterator
16930 * This function can only be called after clutter_actor_iter_next() or
16931 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16932 * than once for the same actor.
16934 * This function will call clutter_actor_destroy() internally.
16939 clutter_actor_iter_destroy (ClutterActorIter *iter)
16941 RealActorIter *ri = (RealActorIter *) iter;
16944 g_return_if_fail (iter != NULL);
16945 g_return_if_fail (ri->root != NULL);
16946 #ifndef G_DISABLE_ASSERT
16947 g_return_if_fail (ri->age == ri->root->priv->age);
16949 g_return_if_fail (ri->current != NULL);
16955 ri->current = cur->priv->prev_sibling;
16957 clutter_actor_destroy (cur);
16963 static const ClutterAnimationInfo default_animation_info = {
16964 NULL, /* transitions */
16966 NULL, /* cur_state */
16970 clutter_animation_info_free (gpointer data)
16974 ClutterAnimationInfo *info = data;
16976 if (info->transitions != NULL)
16977 g_hash_table_unref (info->transitions);
16979 if (info->states != NULL)
16980 g_array_unref (info->states);
16982 g_slice_free (ClutterAnimationInfo, info);
16986 const ClutterAnimationInfo *
16987 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16989 const ClutterAnimationInfo *res;
16990 GObject *obj = G_OBJECT (self);
16992 res = g_object_get_qdata (obj, quark_actor_animation_info);
16996 return &default_animation_info;
16999 ClutterAnimationInfo *
17000 _clutter_actor_get_animation_info (ClutterActor *self)
17002 GObject *obj = G_OBJECT (self);
17003 ClutterAnimationInfo *res;
17005 res = g_object_get_qdata (obj, quark_actor_animation_info);
17008 res = g_slice_new (ClutterAnimationInfo);
17010 *res = default_animation_info;
17012 g_object_set_qdata_full (obj, quark_actor_animation_info,
17014 clutter_animation_info_free);
17020 ClutterTransition *
17021 _clutter_actor_get_transition (ClutterActor *actor,
17024 const ClutterAnimationInfo *info;
17026 info = _clutter_actor_get_animation_info_or_defaults (actor);
17028 if (info->transitions == NULL)
17031 return g_hash_table_lookup (info->transitions, pspec->name);
17034 typedef struct _TransitionClosure
17036 ClutterActor *actor;
17037 ClutterTransition *transition;
17039 gulong completed_id;
17040 } TransitionClosure;
17043 transition_closure_free (gpointer data)
17045 if (G_LIKELY (data != NULL))
17047 TransitionClosure *clos = data;
17048 ClutterTimeline *timeline;
17050 timeline = CLUTTER_TIMELINE (clos->transition);
17052 if (clutter_timeline_is_playing (timeline))
17053 clutter_timeline_stop (timeline);
17055 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17057 g_object_unref (clos->transition);
17058 g_free (clos->name);
17060 g_slice_free (TransitionClosure, clos);
17065 on_transition_completed (ClutterTransition *transition,
17066 TransitionClosure *clos)
17068 ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17069 ClutterActor *actor = clos->actor;
17070 ClutterAnimationInfo *info;
17071 gint n_repeats, cur_repeat;
17073 info = _clutter_actor_get_animation_info (actor);
17075 /* reset the caches used by animations */
17076 clutter_actor_store_content_box (actor, NULL);
17078 /* ensure that we remove the transition only at the end
17079 * of its run; we emit ::completed for every repeat
17081 n_repeats = clutter_timeline_get_repeat_count (timeline);
17082 cur_repeat = clutter_timeline_get_current_repeat (timeline);
17084 if (cur_repeat == n_repeats)
17086 if (clutter_transition_get_remove_on_complete (transition))
17088 /* we take a reference here because removing the closure
17089 * will release the reference on the transition, and we
17090 * want the transition to survive the signal emission;
17091 * the master clock will release the last reference at
17092 * the end of the frame processing.
17094 g_object_ref (transition);
17095 g_hash_table_remove (info->transitions, clos->name);
17099 /* if it's the last transition then we clean up */
17100 if (g_hash_table_size (info->transitions) == 0)
17102 g_hash_table_unref (info->transitions);
17103 info->transitions = NULL;
17105 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17106 _clutter_actor_get_debug_name (actor));
17108 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17113 _clutter_actor_update_transition (ClutterActor *actor,
17117 TransitionClosure *clos;
17118 ClutterTimeline *timeline;
17119 ClutterInterval *interval;
17120 const ClutterAnimationInfo *info;
17123 GValue initial = G_VALUE_INIT;
17124 GValue final = G_VALUE_INIT;
17125 char *error = NULL;
17127 info = _clutter_actor_get_animation_info_or_defaults (actor);
17129 if (info->transitions == NULL)
17132 clos = g_hash_table_lookup (info->transitions, pspec->name);
17136 timeline = CLUTTER_TIMELINE (clos->transition);
17138 va_start (var_args, pspec);
17140 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17142 g_value_init (&initial, ptype);
17143 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17147 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17150 g_critical ("%s: %s", G_STRLOC, error);
17155 interval = clutter_transition_get_interval (clos->transition);
17156 clutter_interval_set_initial_value (interval, &initial);
17157 clutter_interval_set_final_value (interval, &final);
17159 /* if we're updating with an easing duration of zero milliseconds,
17160 * we just jump the timeline to the end and let it run its course
17162 if (info->cur_state != NULL &&
17163 info->cur_state->easing_duration != 0)
17165 guint cur_duration = clutter_timeline_get_duration (timeline);
17166 ClutterAnimationMode cur_mode =
17167 clutter_timeline_get_progress_mode (timeline);
17169 if (cur_duration != info->cur_state->easing_duration)
17170 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17172 if (cur_mode != info->cur_state->easing_mode)
17173 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17175 clutter_timeline_rewind (timeline);
17179 guint duration = clutter_timeline_get_duration (timeline);
17181 clutter_timeline_advance (timeline, duration);
17185 g_value_unset (&initial);
17186 g_value_unset (&final);
17192 * _clutter_actor_create_transition:
17193 * @actor: a #ClutterActor
17194 * @pspec: the property used for the transition
17195 * @...: initial and final state
17197 * Creates a #ClutterTransition for the property represented by @pspec.
17199 * Return value: a #ClutterTransition
17201 ClutterTransition *
17202 _clutter_actor_create_transition (ClutterActor *actor,
17206 ClutterAnimationInfo *info;
17207 ClutterTransition *res = NULL;
17208 gboolean call_restore = FALSE;
17209 TransitionClosure *clos;
17212 info = _clutter_actor_get_animation_info (actor);
17214 /* XXX - this will go away in 2.0
17216 * if no state has been pushed, we assume that the easing state is
17217 * in "compatibility mode": all transitions have a duration of 0
17218 * msecs, which means that they happen immediately. in Clutter 2.0
17219 * this will turn into a g_assert(info->states != NULL), as every
17220 * actor will start with a predefined easing state
17222 if (info->states == NULL)
17224 clutter_actor_save_easing_state (actor);
17225 clutter_actor_set_easing_duration (actor, 0);
17226 call_restore = TRUE;
17229 if (info->transitions == NULL)
17230 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17232 transition_closure_free);
17234 va_start (var_args, pspec);
17236 clos = g_hash_table_lookup (info->transitions, pspec->name);
17239 ClutterInterval *interval;
17240 GValue initial = G_VALUE_INIT;
17241 GValue final = G_VALUE_INIT;
17245 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17247 G_VALUE_COLLECT_INIT (&initial, ptype,
17252 g_critical ("%s: %s", G_STRLOC, error);
17257 G_VALUE_COLLECT_INIT (&final, ptype,
17263 g_critical ("%s: %s", G_STRLOC, error);
17264 g_value_unset (&initial);
17269 /* if the current easing state has a duration of 0, then we don't
17270 * bother to create the transition, and we just set the final value
17271 * directly on the actor; we don't go through the Animatable
17272 * interface because we know we got here through an animatable
17275 if (info->cur_state->easing_duration == 0)
17277 clutter_actor_set_animatable_property (actor,
17281 g_value_unset (&initial);
17282 g_value_unset (&final);
17287 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17289 g_value_unset (&initial);
17290 g_value_unset (&final);
17292 res = clutter_property_transition_new (pspec->name);
17294 clutter_transition_set_interval (res, interval);
17295 clutter_transition_set_remove_on_complete (res, TRUE);
17297 /* this will start the transition as well */
17298 clutter_actor_add_transition (actor, pspec->name, res);
17300 /* the actor now owns the transition */
17301 g_object_unref (res);
17304 res = clos->transition;
17308 clutter_actor_restore_easing_state (actor);
17316 * clutter_actor_add_transition:
17317 * @self: a #ClutterActor
17318 * @name: the name of the transition to add
17319 * @transition: the #ClutterTransition to add
17321 * Adds a @transition to the #ClutterActor's list of animations.
17323 * The @name string is a per-actor unique identifier of the @transition: only
17324 * one #ClutterTransition can be associated to the specified @name.
17326 * The @transition will be given the easing duration, mode, and delay
17327 * associated to the actor's current easing state; it is possible to modify
17328 * these values after calling clutter_actor_add_transition().
17330 * The @transition will be started once added.
17332 * This function will take a reference on the @transition.
17334 * This function is usually called implicitly when modifying an animatable
17340 clutter_actor_add_transition (ClutterActor *self,
17342 ClutterTransition *transition)
17344 ClutterTimeline *timeline;
17345 TransitionClosure *clos;
17346 ClutterAnimationInfo *info;
17348 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17349 g_return_if_fail (name != NULL);
17350 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17352 info = _clutter_actor_get_animation_info (self);
17354 if (info->cur_state == NULL)
17356 g_warning ("No easing state is defined for the actor '%s'; you "
17357 "must call clutter_actor_save_easing_state() before "
17358 "calling clutter_actor_add_transition().",
17359 _clutter_actor_get_debug_name (self));
17363 if (info->transitions == NULL)
17364 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17366 transition_closure_free);
17368 if (g_hash_table_lookup (info->transitions, name) != NULL)
17370 g_warning ("A transition with name '%s' already exists for "
17373 _clutter_actor_get_debug_name (self));
17377 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17379 timeline = CLUTTER_TIMELINE (transition);
17381 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17382 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17383 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17385 clos = g_slice_new (TransitionClosure);
17386 clos->actor = self;
17387 clos->transition = g_object_ref (transition);
17388 clos->name = g_strdup (name);
17389 clos->completed_id = g_signal_connect (timeline, "completed",
17390 G_CALLBACK (on_transition_completed),
17393 CLUTTER_NOTE (ANIMATION,
17394 "Adding transition '%s' [%p] to actor '%s'",
17397 _clutter_actor_get_debug_name (self));
17399 g_hash_table_insert (info->transitions, clos->name, clos);
17400 clutter_timeline_start (timeline);
17404 * clutter_actor_remove_transition:
17405 * @self: a #ClutterActor
17406 * @name: the name of the transition to remove
17408 * Removes the transition stored inside a #ClutterActor using @name
17411 * If the transition is currently in progress, it will be stopped.
17413 * This function releases the reference acquired when the transition
17414 * was added to the #ClutterActor.
17419 clutter_actor_remove_transition (ClutterActor *self,
17422 const ClutterAnimationInfo *info;
17424 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17425 g_return_if_fail (name != NULL);
17427 info = _clutter_actor_get_animation_info_or_defaults (self);
17429 if (info->transitions == NULL)
17432 g_hash_table_remove (info->transitions, name);
17436 * clutter_actor_remove_all_transitions:
17437 * @self: a #ClutterActor
17439 * Removes all transitions associated to @self.
17444 clutter_actor_remove_all_transitions (ClutterActor *self)
17446 const ClutterAnimationInfo *info;
17448 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17450 info = _clutter_actor_get_animation_info_or_defaults (self);
17451 if (info->transitions == NULL)
17454 g_hash_table_remove_all (info->transitions);
17458 * clutter_actor_set_easing_duration:
17459 * @self: a #ClutterActor
17460 * @msecs: the duration of the easing, or %NULL
17462 * Sets the duration of the tweening for animatable properties
17463 * of @self for the current easing state.
17468 clutter_actor_set_easing_duration (ClutterActor *self,
17471 ClutterAnimationInfo *info;
17473 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17475 info = _clutter_actor_get_animation_info (self);
17477 if (info->cur_state == NULL)
17479 g_warning ("You must call clutter_actor_save_easing_state() prior "
17480 "to calling clutter_actor_set_easing_duration().");
17484 if (info->cur_state->easing_duration != msecs)
17485 info->cur_state->easing_duration = msecs;
17489 * clutter_actor_get_easing_duration:
17490 * @self: a #ClutterActor
17492 * Retrieves the duration of the tweening for animatable
17493 * properties of @self for the current easing state.
17495 * Return value: the duration of the tweening, in milliseconds
17500 clutter_actor_get_easing_duration (ClutterActor *self)
17502 const ClutterAnimationInfo *info;
17504 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17506 info = _clutter_actor_get_animation_info_or_defaults (self);
17508 if (info->cur_state != NULL)
17509 return info->cur_state->easing_duration;
17515 * clutter_actor_set_easing_mode:
17516 * @self: a #ClutterActor
17517 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17519 * Sets the easing mode for the tweening of animatable properties
17525 clutter_actor_set_easing_mode (ClutterActor *self,
17526 ClutterAnimationMode mode)
17528 ClutterAnimationInfo *info;
17530 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17531 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17532 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17534 info = _clutter_actor_get_animation_info (self);
17536 if (info->cur_state == NULL)
17538 g_warning ("You must call clutter_actor_save_easing_state() prior "
17539 "to calling clutter_actor_set_easing_mode().");
17543 if (info->cur_state->easing_mode != mode)
17544 info->cur_state->easing_mode = mode;
17548 * clutter_actor_get_easing_mode:
17549 * @self: a #ClutterActor
17551 * Retrieves the easing mode for the tweening of animatable properties
17552 * of @self for the current easing state.
17554 * Return value: an easing mode
17558 ClutterAnimationMode
17559 clutter_actor_get_easing_mode (ClutterActor *self)
17561 const ClutterAnimationInfo *info;
17563 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17565 info = _clutter_actor_get_animation_info_or_defaults (self);
17567 if (info->cur_state != NULL)
17568 return info->cur_state->easing_mode;
17570 return CLUTTER_EASE_OUT_CUBIC;
17574 * clutter_actor_set_easing_delay:
17575 * @self: a #ClutterActor
17576 * @msecs: the delay before the start of the tweening, in milliseconds
17578 * Sets the delay that should be applied before tweening animatable
17584 clutter_actor_set_easing_delay (ClutterActor *self,
17587 ClutterAnimationInfo *info;
17589 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17591 info = _clutter_actor_get_animation_info (self);
17593 if (info->cur_state == NULL)
17595 g_warning ("You must call clutter_actor_save_easing_state() prior "
17596 "to calling clutter_actor_set_easing_delay().");
17600 if (info->cur_state->easing_delay != msecs)
17601 info->cur_state->easing_delay = msecs;
17605 * clutter_actor_get_easing_delay:
17606 * @self: a #ClutterActor
17608 * Retrieves the delay that should be applied when tweening animatable
17611 * Return value: a delay, in milliseconds
17616 clutter_actor_get_easing_delay (ClutterActor *self)
17618 const ClutterAnimationInfo *info;
17620 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17622 info = _clutter_actor_get_animation_info_or_defaults (self);
17624 if (info->cur_state != NULL)
17625 return info->cur_state->easing_delay;
17631 * clutter_actor_get_transition:
17632 * @self: a #ClutterActor
17633 * @name: the name of the transition
17635 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17636 * transition @name.
17638 * Transitions created for animatable properties use the name of the
17639 * property itself, for instance the code below:
17642 * clutter_actor_set_easing_duration (actor, 1000);
17643 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17645 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17646 * g_signal_connect (transition, "completed",
17647 * G_CALLBACK (on_transition_complete),
17651 * will call the <function>on_transition_complete</function> callback when
17652 * the transition is complete.
17654 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17655 * was found to match the passed name; the returned instance is owned
17656 * by Clutter and it should not be freed
17660 ClutterTransition *
17661 clutter_actor_get_transition (ClutterActor *self,
17664 TransitionClosure *clos;
17665 const ClutterAnimationInfo *info;
17667 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17668 g_return_val_if_fail (name != NULL, NULL);
17670 info = _clutter_actor_get_animation_info_or_defaults (self);
17671 if (info->transitions == NULL)
17674 clos = g_hash_table_lookup (info->transitions, name);
17678 return clos->transition;
17682 * clutter_actor_save_easing_state:
17683 * @self: a #ClutterActor
17685 * Saves the current easing state for animatable properties, and creates
17686 * a new state with the default values for easing mode and duration.
17691 clutter_actor_save_easing_state (ClutterActor *self)
17693 ClutterAnimationInfo *info;
17696 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17698 info = _clutter_actor_get_animation_info (self);
17700 if (info->states == NULL)
17701 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17703 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17704 new_state.easing_duration = 250;
17705 new_state.easing_delay = 0;
17707 g_array_append_val (info->states, new_state);
17709 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17713 * clutter_actor_restore_easing_state:
17714 * @self: a #ClutterActor
17716 * Restores the easing state as it was prior to a call to
17717 * clutter_actor_save_easing_state().
17722 clutter_actor_restore_easing_state (ClutterActor *self)
17724 ClutterAnimationInfo *info;
17726 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17728 info = _clutter_actor_get_animation_info (self);
17730 if (info->states == NULL)
17732 g_critical ("The function clutter_actor_restore_easing_state() has "
17733 "called without a previous call to "
17734 "clutter_actor_save_easing_state().");
17738 g_array_remove_index (info->states, info->states->len - 1);
17740 if (info->states->len > 0)
17741 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17744 g_array_unref (info->states);
17745 info->states = NULL;
17746 info->cur_state = NULL;
17751 * clutter_actor_set_content:
17752 * @self: a #ClutterActor
17753 * @content: (allow-none): a #ClutterContent, or %NULL
17755 * Sets the contents of a #ClutterActor.
17760 clutter_actor_set_content (ClutterActor *self,
17761 ClutterContent *content)
17763 ClutterActorPrivate *priv;
17765 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17766 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17770 if (priv->content != NULL)
17772 _clutter_content_detached (priv->content, self);
17773 g_clear_object (&priv->content);
17776 priv->content = content;
17778 if (priv->content != NULL)
17780 g_object_ref (priv->content);
17781 _clutter_content_attached (priv->content, self);
17784 /* given that the content is always painted within the allocation,
17785 * we only need to queue a redraw here
17787 clutter_actor_queue_redraw (self);
17789 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17791 /* if the content gravity is not resize-fill, and the new content has a
17792 * different preferred size than the previous one, then the content box
17793 * may have been changed. since we compute that lazily, we just notify
17794 * here, and let whomever watches :content-box do whatever they need to
17797 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17798 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17802 * clutter_actor_get_content:
17803 * @self: a #ClutterActor
17805 * Retrieves the contents of @self.
17807 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17808 * or %NULL if none was set
17813 clutter_actor_get_content (ClutterActor *self)
17815 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17817 return self->priv->content;
17821 * clutter_actor_set_content_gravity:
17822 * @self: a #ClutterActor
17823 * @gravity: the #ClutterContentGravity
17825 * Sets the gravity of the #ClutterContent used by @self.
17827 * See the description of the #ClutterActor:content-gravity property for
17828 * more information.
17830 * The #ClutterActor:content-gravity property is animatable.
17835 clutter_actor_set_content_gravity (ClutterActor *self,
17836 ClutterContentGravity gravity)
17838 ClutterActorPrivate *priv;
17840 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17844 if (priv->content_gravity == gravity)
17847 priv->content_box_valid = FALSE;
17849 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17851 ClutterActorBox from_box, to_box;
17853 clutter_actor_get_content_box (self, &from_box);
17855 priv->content_gravity = gravity;
17857 clutter_actor_get_content_box (self, &to_box);
17859 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17865 ClutterActorBox to_box;
17867 priv->content_gravity = gravity;
17869 clutter_actor_get_content_box (self, &to_box);
17871 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17875 clutter_actor_queue_redraw (self);
17877 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17881 * clutter_actor_get_content_gravity:
17882 * @self: a #ClutterActor
17884 * Retrieves the content gravity as set using
17885 * clutter_actor_get_content_gravity().
17887 * Return value: the content gravity
17891 ClutterContentGravity
17892 clutter_actor_get_content_gravity (ClutterActor *self)
17894 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17895 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17897 return self->priv->content_gravity;
17901 * clutter_actor_get_content_box:
17902 * @self: a #ClutterActor
17903 * @box: (out caller-allocates): the return location for the bounding
17904 * box for the #ClutterContent
17906 * Retrieves the bounding box for the #ClutterContent of @self.
17908 * The bounding box is relative to the actor's allocation.
17910 * If no #ClutterContent is set for @self, or if @self has not been
17911 * allocated yet, then the result is undefined.
17913 * The content box is guaranteed to be, at most, as big as the allocation
17914 * of the #ClutterActor.
17916 * If the #ClutterContent used by the actor has a preferred size, then
17917 * it is possible to modify the content box by using the
17918 * #ClutterActor:content-gravity property.
17923 clutter_actor_get_content_box (ClutterActor *self,
17924 ClutterActorBox *box)
17926 ClutterActorPrivate *priv;
17927 gfloat content_w, content_h;
17928 gfloat alloc_w, alloc_h;
17930 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17931 g_return_if_fail (box != NULL);
17937 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17938 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17940 if (priv->content_box_valid)
17942 *box = priv->content_box;
17946 /* no need to do any more work */
17947 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17950 if (priv->content == NULL)
17953 /* if the content does not have a preferred size then there is
17954 * no point in computing the content box
17956 if (!clutter_content_get_preferred_size (priv->content,
17964 switch (priv->content_gravity)
17966 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17967 box->x2 = box->x1 + MIN (content_w, alloc_w);
17968 box->y2 = box->y1 + MIN (content_h, alloc_h);
17971 case CLUTTER_CONTENT_GRAVITY_TOP:
17972 if (alloc_w > content_w)
17974 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17975 box->x2 = box->x1 + content_w;
17977 box->y2 = box->y1 + MIN (content_h, alloc_h);
17980 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17981 if (alloc_w > content_w)
17983 box->x1 += (alloc_w - content_w);
17984 box->x2 = box->x1 + content_w;
17986 box->y2 = box->y1 + MIN (content_h, alloc_h);
17989 case CLUTTER_CONTENT_GRAVITY_LEFT:
17990 box->x2 = box->x1 + MIN (content_w, alloc_w);
17991 if (alloc_h > content_h)
17993 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17994 box->y2 = box->y1 + content_h;
17998 case CLUTTER_CONTENT_GRAVITY_CENTER:
17999 if (alloc_w > content_w)
18001 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18002 box->x2 = box->x1 + content_w;
18004 if (alloc_h > content_h)
18006 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18007 box->y2 = box->y1 + content_h;
18011 case CLUTTER_CONTENT_GRAVITY_RIGHT:
18012 if (alloc_w > content_w)
18014 box->x1 += (alloc_w - content_w);
18015 box->x2 = box->x1 + content_w;
18017 if (alloc_h > content_h)
18019 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18020 box->y2 = box->y1 + content_h;
18024 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18025 box->x2 = box->x1 + MIN (content_w, alloc_w);
18026 if (alloc_h > content_h)
18028 box->y1 += (alloc_h - content_h);
18029 box->y2 = box->y1 + content_h;
18033 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18034 if (alloc_w > content_w)
18036 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18037 box->x2 = box->x1 + content_w;
18039 if (alloc_h > content_h)
18041 box->y1 += (alloc_h - content_h);
18042 box->y2 = box->y1 + content_h;
18046 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18047 if (alloc_w > content_w)
18049 box->x1 += (alloc_w - content_w);
18050 box->x2 = box->x1 + content_w;
18052 if (alloc_h > content_h)
18054 box->y1 += (alloc_h - content_h);
18055 box->y2 = box->y1 + content_h;
18059 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18060 g_assert_not_reached ();
18063 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18065 double r_c = content_w / content_h;
18066 double r_a = alloc_w / alloc_h;
18075 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18076 box->y2 = box->y1 + (alloc_w * r_c);
18083 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18084 box->x2 = box->x1 + (alloc_h * r_c);
18094 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18095 box->x2 = box->x1 + (alloc_h * r_c);
18102 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18103 box->y2 = box->y1 + (alloc_w * r_c);
18112 * clutter_actor_set_content_scaling_filters:
18113 * @self: a #ClutterActor
18114 * @min_filter: the minification filter for the content
18115 * @mag_filter: the magnification filter for the content
18117 * Sets the minification and magnification filter to be applied when
18118 * scaling the #ClutterActor:content of a #ClutterActor.
18120 * The #ClutterActor:minification-filter will be used when reducing
18121 * the size of the content; the #ClutterActor:magnification-filter
18122 * will be used when increasing the size of the content.
18127 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18128 ClutterScalingFilter min_filter,
18129 ClutterScalingFilter mag_filter)
18131 ClutterActorPrivate *priv;
18135 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18138 obj = G_OBJECT (self);
18140 g_object_freeze_notify (obj);
18144 if (priv->min_filter != min_filter)
18146 priv->min_filter = min_filter;
18149 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18152 if (priv->mag_filter != mag_filter)
18154 priv->mag_filter = mag_filter;
18157 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18161 clutter_actor_queue_redraw (self);
18163 g_object_thaw_notify (obj);
18167 * clutter_actor_get_content_scaling_filters:
18168 * @self: a #ClutterActor
18169 * @min_filter: (out) (allow-none): return location for the minification
18171 * @mag_filter: (out) (allow-none): return location for the magnification
18174 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18179 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18180 ClutterScalingFilter *min_filter,
18181 ClutterScalingFilter *mag_filter)
18183 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18185 if (min_filter != NULL)
18186 *min_filter = self->priv->min_filter;
18188 if (mag_filter != NULL)
18189 *mag_filter = self->priv->mag_filter;