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 if (priv->parent == NULL)
1559 priv->show_on_set_parent = set_show;
1560 g_object_notify_by_pspec (G_OBJECT (self),
1561 obj_props[PROP_SHOW_ON_SET_PARENT]);
1566 * clutter_actor_show:
1567 * @self: A #ClutterActor
1569 * Flags an actor to be displayed. An actor that isn't shown will not
1570 * be rendered on the stage.
1572 * Actors are visible by default.
1574 * If this function is called on an actor without a parent, the
1575 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1579 clutter_actor_show (ClutterActor *self)
1581 ClutterActorPrivate *priv;
1583 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1585 /* simple optimization */
1586 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1588 /* we still need to set the :show-on-set-parent property, in
1589 * case show() is called on an unparented actor
1591 set_show_on_set_parent (self, TRUE);
1595 #ifdef CLUTTER_ENABLE_DEBUG
1596 clutter_actor_verify_map_state (self);
1601 g_object_freeze_notify (G_OBJECT (self));
1603 set_show_on_set_parent (self, TRUE);
1605 g_signal_emit (self, actor_signals[SHOW], 0);
1606 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1608 if (priv->parent != NULL)
1609 clutter_actor_queue_redraw (priv->parent);
1611 g_object_thaw_notify (G_OBJECT (self));
1615 * clutter_actor_show_all:
1616 * @self: a #ClutterActor
1618 * Calls clutter_actor_show() on all children of an actor (if any).
1622 * Deprecated: 1.10: Actors are visible by default
1625 clutter_actor_show_all (ClutterActor *self)
1627 ClutterActorClass *klass;
1629 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1631 klass = CLUTTER_ACTOR_GET_CLASS (self);
1632 if (klass->show_all)
1633 klass->show_all (self);
1637 clutter_actor_real_hide (ClutterActor *self)
1639 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1641 ClutterActorPrivate *priv = self->priv;
1643 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1645 /* we notify on the "visible" flag in the clutter_actor_hide()
1646 * wrapper so the entire hide signal emission completes first
1649 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1651 /* we queue a relayout unless the actor is inside a
1652 * container that explicitly told us not to
1654 if (priv->parent != NULL &&
1655 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1656 clutter_actor_queue_relayout (priv->parent);
1661 * clutter_actor_hide:
1662 * @self: A #ClutterActor
1664 * Flags an actor to be hidden. A hidden actor will not be
1665 * rendered on the stage.
1667 * Actors are visible by default.
1669 * If this function is called on an actor without a parent, the
1670 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1674 clutter_actor_hide (ClutterActor *self)
1676 ClutterActorPrivate *priv;
1678 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1680 /* simple optimization */
1681 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1683 /* we still need to set the :show-on-set-parent property, in
1684 * case hide() is called on an unparented actor
1686 set_show_on_set_parent (self, FALSE);
1690 #ifdef CLUTTER_ENABLE_DEBUG
1691 clutter_actor_verify_map_state (self);
1696 g_object_freeze_notify (G_OBJECT (self));
1698 set_show_on_set_parent (self, FALSE);
1700 g_signal_emit (self, actor_signals[HIDE], 0);
1701 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1703 if (priv->parent != NULL)
1704 clutter_actor_queue_redraw (priv->parent);
1706 g_object_thaw_notify (G_OBJECT (self));
1710 * clutter_actor_hide_all:
1711 * @self: a #ClutterActor
1713 * Calls clutter_actor_hide() on all child actors (if any).
1717 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1718 * prevent its children from being painted as well.
1721 clutter_actor_hide_all (ClutterActor *self)
1723 ClutterActorClass *klass;
1725 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1727 klass = CLUTTER_ACTOR_GET_CLASS (self);
1728 if (klass->hide_all)
1729 klass->hide_all (self);
1733 * clutter_actor_realize:
1734 * @self: A #ClutterActor
1736 * Realization informs the actor that it is attached to a stage. It
1737 * can use this to allocate resources if it wanted to delay allocation
1738 * until it would be rendered. However it is perfectly acceptable for
1739 * an actor to create resources before being realized because Clutter
1740 * only ever has a single rendering context so that actor is free to
1741 * be moved from one stage to another.
1743 * This function does nothing if the actor is already realized.
1745 * Because a realized actor must have realized parent actors, calling
1746 * clutter_actor_realize() will also realize all parents of the actor.
1748 * This function does not realize child actors, except in the special
1749 * case that realizing the stage, when the stage is visible, will
1750 * suddenly map (and thus realize) the children of the stage.
1753 clutter_actor_realize (ClutterActor *self)
1755 ClutterActorPrivate *priv;
1757 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1761 #ifdef CLUTTER_ENABLE_DEBUG
1762 clutter_actor_verify_map_state (self);
1765 if (CLUTTER_ACTOR_IS_REALIZED (self))
1768 /* To be realized, our parent actors must be realized first.
1769 * This will only succeed if we're inside a toplevel.
1771 if (priv->parent != NULL)
1772 clutter_actor_realize (priv->parent);
1774 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1776 /* toplevels can be realized at any time */
1780 /* "Fail" the realization if parent is missing or unrealized;
1781 * this should really be a g_warning() not some kind of runtime
1782 * failure; how can an app possibly recover? Instead it's a bug
1783 * in the app and the app should get an explanatory warning so
1784 * someone can fix it. But for now it's too hard to fix this
1785 * because e.g. ClutterTexture needs reworking.
1787 if (priv->parent == NULL ||
1788 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1792 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1794 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1795 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1797 g_signal_emit (self, actor_signals[REALIZE], 0);
1799 /* Stage actor is allowed to unset the realized flag again in its
1800 * default signal handler, though that is a pathological situation.
1803 /* If realization "failed" we'll have to update child state. */
1804 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1808 clutter_actor_real_unrealize (ClutterActor *self)
1810 /* we must be unmapped (implying our children are also unmapped) */
1811 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1815 * clutter_actor_unrealize:
1816 * @self: A #ClutterActor
1818 * Unrealization informs the actor that it may be being destroyed or
1819 * moved to another stage. The actor may want to destroy any
1820 * underlying graphics resources at this point. However it is
1821 * perfectly acceptable for it to retain the resources until the actor
1822 * is destroyed because Clutter only ever uses a single rendering
1823 * context and all of the graphics resources are valid on any stage.
1825 * Because mapped actors must be realized, actors may not be
1826 * unrealized if they are mapped. This function hides the actor to be
1827 * sure it isn't mapped, an application-visible side effect that you
1828 * may not be expecting.
1830 * This function should not be called by application code.
1833 clutter_actor_unrealize (ClutterActor *self)
1835 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1836 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1838 /* This function should not really be in the public API, because
1839 * there isn't a good reason to call it. ClutterActor will already
1840 * unrealize things for you when it's important to do so.
1842 * If you were using clutter_actor_unrealize() in a dispose
1843 * implementation, then don't, just chain up to ClutterActor's
1846 * If you were using clutter_actor_unrealize() to implement
1847 * unrealizing children of your container, then don't, ClutterActor
1848 * will already take care of that.
1850 * If you were using clutter_actor_unrealize() to re-realize to
1851 * create your resources in a different way, then use
1852 * _clutter_actor_rerealize() (inside Clutter) or just call your
1853 * code that recreates your resources directly (outside Clutter).
1856 #ifdef CLUTTER_ENABLE_DEBUG
1857 clutter_actor_verify_map_state (self);
1860 clutter_actor_hide (self);
1862 clutter_actor_unrealize_not_hiding (self);
1865 static ClutterActorTraverseVisitFlags
1866 unrealize_actor_before_children_cb (ClutterActor *self,
1870 /* If an actor is already unrealized we know its children have also
1871 * already been unrealized... */
1872 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1873 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1875 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1877 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1880 static ClutterActorTraverseVisitFlags
1881 unrealize_actor_after_children_cb (ClutterActor *self,
1885 /* We want to unset the realized flag only _after_
1886 * child actors are unrealized, to maintain invariants.
1888 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1889 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1890 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1894 * clutter_actor_unrealize_not_hiding:
1895 * @self: A #ClutterActor
1897 * Unrealization informs the actor that it may be being destroyed or
1898 * moved to another stage. The actor may want to destroy any
1899 * underlying graphics resources at this point. However it is
1900 * perfectly acceptable for it to retain the resources until the actor
1901 * is destroyed because Clutter only ever uses a single rendering
1902 * context and all of the graphics resources are valid on any stage.
1904 * Because mapped actors must be realized, actors may not be
1905 * unrealized if they are mapped. You must hide the actor or one of
1906 * its parents before attempting to unrealize.
1908 * This function is separate from clutter_actor_unrealize() because it
1909 * does not automatically hide the actor.
1910 * Actors need not be hidden to be unrealized, they just need to
1911 * be unmapped. In fact we don't want to mess up the application's
1912 * setting of the "visible" flag, so hiding is very undesirable.
1914 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1915 * backward compatibility.
1918 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1920 _clutter_actor_traverse (self,
1921 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1922 unrealize_actor_before_children_cb,
1923 unrealize_actor_after_children_cb,
1928 * _clutter_actor_rerealize:
1929 * @self: A #ClutterActor
1930 * @callback: Function to call while unrealized
1931 * @data: data for callback
1933 * If an actor is already unrealized, this just calls the callback.
1935 * If it is realized, it unrealizes temporarily, calls the callback,
1936 * and then re-realizes the actor.
1938 * As a side effect, leaves all children of the actor unrealized if
1939 * the actor was realized but not showing. This is because when we
1940 * unrealize the actor temporarily we must unrealize its children
1941 * (e.g. children of a stage can't be realized if stage window is
1942 * gone). And we aren't clever enough to save the realization state of
1943 * all children. In most cases this should not matter, because
1944 * the children will automatically realize when they next become mapped.
1947 _clutter_actor_rerealize (ClutterActor *self,
1948 ClutterCallback callback,
1951 gboolean was_mapped;
1952 gboolean was_showing;
1953 gboolean was_realized;
1955 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1957 #ifdef CLUTTER_ENABLE_DEBUG
1958 clutter_actor_verify_map_state (self);
1961 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1962 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1963 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1965 /* Must be unmapped to unrealize. Note we only have to hide this
1966 * actor if it was mapped (if all parents were showing). If actor
1967 * is merely visible (but not mapped), then that's fine, we can
1971 clutter_actor_hide (self);
1973 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1975 /* unrealize self and all children */
1976 clutter_actor_unrealize_not_hiding (self);
1978 if (callback != NULL)
1980 (* callback) (self, data);
1984 clutter_actor_show (self); /* will realize only if mapping implies it */
1985 else if (was_realized)
1986 clutter_actor_realize (self); /* realize self and all parents */
1990 clutter_actor_real_pick (ClutterActor *self,
1991 const ClutterColor *color)
1993 /* the default implementation is just to paint a rectangle
1994 * with the same size of the actor using the passed color
1996 if (clutter_actor_should_pick_paint (self))
1998 ClutterActorBox box = { 0, };
1999 float width, height;
2001 clutter_actor_get_allocation_box (self, &box);
2003 width = box.x2 - box.x1;
2004 height = box.y2 - box.y1;
2006 cogl_set_source_color4ub (color->red,
2011 cogl_rectangle (0, 0, width, height);
2014 /* XXX - this thoroughly sucks, but we need to maintain compatibility
2015 * with existing container classes that override the pick() virtual
2016 * and chain up to the default implementation - otherwise we'll end up
2017 * painting our children twice.
2019 * this has to go away for 2.0; hopefully along the pick() itself.
2021 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2025 for (iter = self->priv->first_child;
2027 iter = iter->priv->next_sibling)
2028 clutter_actor_paint (iter);
2033 * clutter_actor_should_pick_paint:
2034 * @self: A #ClutterActor
2036 * Should be called inside the implementation of the
2037 * #ClutterActor::pick virtual function in order to check whether
2038 * the actor should paint itself in pick mode or not.
2040 * This function should never be called directly by applications.
2042 * Return value: %TRUE if the actor should paint its silhouette,
2046 clutter_actor_should_pick_paint (ClutterActor *self)
2048 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2050 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2051 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2052 CLUTTER_ACTOR_IS_REACTIVE (self)))
2059 clutter_actor_real_get_preferred_width (ClutterActor *self,
2061 gfloat *min_width_p,
2062 gfloat *natural_width_p)
2064 ClutterActorPrivate *priv = self->priv;
2066 if (priv->n_children != 0 &&
2067 priv->layout_manager != NULL)
2069 ClutterContainer *container = CLUTTER_CONTAINER (self);
2071 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2072 "for the preferred width",
2073 G_OBJECT_TYPE_NAME (priv->layout_manager),
2074 priv->layout_manager);
2076 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2085 /* Default implementation is always 0x0, usually an actor
2086 * using this default is relying on someone to set the
2089 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2094 if (natural_width_p)
2095 *natural_width_p = 0;
2099 clutter_actor_real_get_preferred_height (ClutterActor *self,
2101 gfloat *min_height_p,
2102 gfloat *natural_height_p)
2104 ClutterActorPrivate *priv = self->priv;
2106 if (priv->n_children != 0 &&
2107 priv->layout_manager != NULL)
2109 ClutterContainer *container = CLUTTER_CONTAINER (self);
2111 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2112 "for the preferred height",
2113 G_OBJECT_TYPE_NAME (priv->layout_manager),
2114 priv->layout_manager);
2116 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2124 /* Default implementation is always 0x0, usually an actor
2125 * using this default is relying on someone to set the
2128 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2133 if (natural_height_p)
2134 *natural_height_p = 0;
2138 clutter_actor_store_old_geometry (ClutterActor *self,
2139 ClutterActorBox *box)
2141 *box = self->priv->allocation;
2145 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2146 const ClutterActorBox *old)
2148 ClutterActorPrivate *priv = self->priv;
2149 GObject *obj = G_OBJECT (self);
2151 g_object_freeze_notify (obj);
2153 /* to avoid excessive requisition or allocation cycles we
2154 * use the cached values.
2156 * - if we don't have an allocation we assume that we need
2158 * - if we don't have a width or a height request we notify
2160 * - if we have a valid allocation then we check the old
2161 * bounding box with the current allocation and we notify
2164 if (priv->needs_allocation)
2166 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2167 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2168 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2169 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2171 else if (priv->needs_width_request || priv->needs_height_request)
2173 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2174 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2179 gfloat width, height;
2181 x = priv->allocation.x1;
2182 y = priv->allocation.y1;
2183 width = priv->allocation.x2 - priv->allocation.x1;
2184 height = priv->allocation.y2 - priv->allocation.y1;
2187 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2190 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2192 if (width != (old->x2 - old->x1))
2193 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2195 if (height != (old->y2 - old->y1))
2196 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2199 g_object_thaw_notify (obj);
2203 * clutter_actor_set_allocation_internal:
2204 * @self: a #ClutterActor
2205 * @box: a #ClutterActorBox
2206 * @flags: allocation flags
2208 * Stores the allocation of @self.
2210 * This function only performs basic storage and property notification.
2212 * This function should be called by clutter_actor_set_allocation()
2213 * and by the default implementation of #ClutterActorClass.allocate().
2215 * Return value: %TRUE if the allocation of the #ClutterActor has been
2216 * changed, and %FALSE otherwise
2218 static inline gboolean
2219 clutter_actor_set_allocation_internal (ClutterActor *self,
2220 const ClutterActorBox *box,
2221 ClutterAllocationFlags flags)
2223 ClutterActorPrivate *priv = self->priv;
2225 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2226 gboolean flags_changed;
2228 ClutterActorBox old_alloc = { 0, };
2230 obj = G_OBJECT (self);
2232 g_object_freeze_notify (obj);
2234 clutter_actor_store_old_geometry (self, &old_alloc);
2236 x1_changed = priv->allocation.x1 != box->x1;
2237 y1_changed = priv->allocation.y1 != box->y1;
2238 x2_changed = priv->allocation.x2 != box->x2;
2239 y2_changed = priv->allocation.y2 != box->y2;
2241 flags_changed = priv->allocation_flags != flags;
2243 priv->allocation = *box;
2244 priv->allocation_flags = flags;
2246 /* allocation is authoritative */
2247 priv->needs_width_request = FALSE;
2248 priv->needs_height_request = FALSE;
2249 priv->needs_allocation = FALSE;
2251 if (x1_changed || y1_changed ||
2252 x2_changed || y2_changed ||
2255 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2256 _clutter_actor_get_debug_name (self));
2258 priv->transform_valid = FALSE;
2260 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2262 /* if the allocation changes, so does the content box */
2263 if (priv->content != NULL)
2265 priv->content_box_valid = FALSE;
2266 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2274 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2276 g_object_thaw_notify (obj);
2281 static void clutter_actor_real_allocate (ClutterActor *self,
2282 const ClutterActorBox *box,
2283 ClutterAllocationFlags flags);
2286 clutter_actor_maybe_layout_children (ClutterActor *self,
2287 const ClutterActorBox *allocation,
2288 ClutterAllocationFlags flags)
2290 ClutterActorPrivate *priv = self->priv;
2292 /* this is going to be a bit hard to follow, so let's put an explanation
2295 * we want ClutterActor to have a default layout manager if the actor was
2296 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2298 * we also want any subclass of ClutterActor that does not override the
2299 * ::allocate() virtual function to delegate to a layout manager.
2301 * finally, we want to allow people subclassing ClutterActor and overriding
2302 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2304 * on the other hand, we want existing actor subclasses overriding the
2305 * ::allocate() virtual function and chaining up to the parent's
2306 * implementation to continue working without allocating their children
2307 * twice, or without entering an allocation loop.
2309 * for the first two points, we check if the class of the actor is
2310 * overridding the ::allocate() virtual function; if it isn't, then we
2311 * follow through with checking whether we have children and a layout
2312 * manager, and eventually calling clutter_layout_manager_allocate().
2314 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2315 * allocation flags that we got passed, and if it is present, we continue
2316 * with the check above.
2318 * if neither of these two checks yields a positive result, we just
2319 * assume that the ::allocate() virtual function that resulted in this
2320 * function being called will also allocate the children of the actor.
2323 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2326 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2332 if (priv->n_children != 0 &&
2333 priv->layout_manager != NULL)
2335 ClutterContainer *container = CLUTTER_CONTAINER (self);
2336 ClutterAllocationFlags children_flags;
2337 ClutterActorBox children_box;
2339 /* normalize the box passed to the layout manager */
2340 children_box.x1 = children_box.y1 = 0.f;
2341 children_box.x2 = (allocation->x2 - allocation->x1);
2342 children_box.y2 = (allocation->y2 - allocation->y1);
2344 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2345 * the actor's children, since it refers only to the current
2346 * actor's allocation.
2348 children_flags = flags;
2349 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2351 CLUTTER_NOTE (LAYOUT,
2352 "Allocating %d children of %s "
2353 "at { %.2f, %.2f - %.2f x %.2f } "
2356 _clutter_actor_get_debug_name (self),
2359 (allocation->x2 - allocation->x1),
2360 (allocation->y2 - allocation->y1),
2361 G_OBJECT_TYPE_NAME (priv->layout_manager));
2363 clutter_layout_manager_allocate (priv->layout_manager,
2371 clutter_actor_real_allocate (ClutterActor *self,
2372 const ClutterActorBox *box,
2373 ClutterAllocationFlags flags)
2375 ClutterActorPrivate *priv = self->priv;
2378 g_object_freeze_notify (G_OBJECT (self));
2380 changed = clutter_actor_set_allocation_internal (self, box, flags);
2382 /* we allocate our children before we notify changes in our geometry,
2383 * so that people connecting to properties will be able to get valid
2384 * data out of the sub-tree of the scene graph that has this actor at
2387 clutter_actor_maybe_layout_children (self, box, flags);
2391 ClutterActorBox signal_box = priv->allocation;
2392 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2394 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2399 g_object_thaw_notify (G_OBJECT (self));
2403 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2404 ClutterActor *origin)
2406 /* no point in queuing a redraw on a destroyed actor */
2407 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2410 /* NB: We can't bail out early here if the actor is hidden in case
2411 * the actor bas been cloned. In this case the clone will need to
2412 * receive the signal so it can queue its own redraw.
2415 /* calls klass->queue_redraw in default handler */
2416 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2420 clutter_actor_real_queue_redraw (ClutterActor *self,
2421 ClutterActor *origin)
2423 ClutterActor *parent;
2425 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2426 _clutter_actor_get_debug_name (self),
2427 origin != NULL ? _clutter_actor_get_debug_name (origin)
2430 /* no point in queuing a redraw on a destroyed actor */
2431 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2434 /* If the queue redraw is coming from a child then the actor has
2435 become dirty and any queued effect is no longer valid */
2438 self->priv->is_dirty = TRUE;
2439 self->priv->effect_to_redraw = NULL;
2442 /* If the actor isn't visible, we still had to emit the signal
2443 * to allow for a ClutterClone, but the appearance of the parent
2444 * won't change so we don't have to propagate up the hierarchy.
2446 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2449 /* Although we could determine here that a full stage redraw
2450 * has already been queued and immediately bail out, we actually
2451 * guarantee that we will propagate a queue-redraw signal to our
2452 * parent at least once so that it's possible to implement a
2453 * container that tracks which of its children have queued a
2456 if (self->priv->propagated_one_redraw)
2458 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2459 if (stage != NULL &&
2460 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2464 self->priv->propagated_one_redraw = TRUE;
2466 /* notify parents, if they are all visible eventually we'll
2467 * queue redraw on the stage, which queues the redraw idle.
2469 parent = clutter_actor_get_parent (self);
2472 /* this will go up recursively */
2473 _clutter_actor_signal_queue_redraw (parent, origin);
2478 clutter_actor_real_queue_relayout (ClutterActor *self)
2480 ClutterActorPrivate *priv = self->priv;
2482 /* no point in queueing a redraw on a destroyed actor */
2483 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2486 priv->needs_width_request = TRUE;
2487 priv->needs_height_request = TRUE;
2488 priv->needs_allocation = TRUE;
2490 /* reset the cached size requests */
2491 memset (priv->width_requests, 0,
2492 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2493 memset (priv->height_requests, 0,
2494 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2496 /* We need to go all the way up the hierarchy */
2497 if (priv->parent != NULL)
2498 _clutter_actor_queue_only_relayout (priv->parent);
2502 * clutter_actor_apply_relative_transform_to_point:
2503 * @self: A #ClutterActor
2504 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2505 * default #ClutterStage
2506 * @point: A point as #ClutterVertex
2507 * @vertex: (out caller-allocates): The translated #ClutterVertex
2509 * Transforms @point in coordinates relative to the actor into
2510 * ancestor-relative coordinates using the relevant transform
2511 * stack (i.e. scale, rotation, etc).
2513 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2514 * this case, the coordinates returned will be the coordinates on
2515 * the stage before the projection is applied. This is different from
2516 * the behaviour of clutter_actor_apply_transform_to_point().
2521 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2522 ClutterActor *ancestor,
2523 const ClutterVertex *point,
2524 ClutterVertex *vertex)
2529 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2530 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2531 g_return_if_fail (point != NULL);
2532 g_return_if_fail (vertex != NULL);
2537 if (ancestor == NULL)
2538 ancestor = _clutter_actor_get_stage_internal (self);
2540 if (ancestor == NULL)
2546 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2547 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2551 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2552 const ClutterVertex *vertices_in,
2553 ClutterVertex *vertices_out,
2556 ClutterActor *stage;
2557 CoglMatrix modelview;
2558 CoglMatrix projection;
2561 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2563 stage = _clutter_actor_get_stage_internal (self);
2565 /* We really can't do anything meaningful in this case so don't try
2566 * to do any transform */
2570 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2571 * that gets us to stage coordinates, we want to go all the way to eye
2573 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2575 /* Fetch the projection and viewport */
2576 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2577 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2583 _clutter_util_fully_transform_vertices (&modelview,
2594 * clutter_actor_apply_transform_to_point:
2595 * @self: A #ClutterActor
2596 * @point: A point as #ClutterVertex
2597 * @vertex: (out caller-allocates): The translated #ClutterVertex
2599 * Transforms @point in coordinates relative to the actor
2600 * into screen-relative coordinates with the current actor
2601 * transformation (i.e. scale, rotation, etc)
2606 clutter_actor_apply_transform_to_point (ClutterActor *self,
2607 const ClutterVertex *point,
2608 ClutterVertex *vertex)
2610 g_return_if_fail (point != NULL);
2611 g_return_if_fail (vertex != NULL);
2612 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2616 * _clutter_actor_get_relative_transformation_matrix:
2617 * @self: The actor whose coordinate space you want to transform from.
2618 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2619 * or %NULL if you want to transform all the way to eye coordinates.
2620 * @matrix: A #CoglMatrix to store the transformation
2622 * This gets a transformation @matrix that will transform coordinates from the
2623 * coordinate space of @self into the coordinate space of @ancestor.
2625 * For example if you need a matrix that can transform the local actor
2626 * coordinates of @self into stage coordinates you would pass the actor's stage
2627 * pointer as the @ancestor.
2629 * If you pass %NULL then the transformation will take you all the way through
2630 * to eye coordinates. This can be useful if you want to extract the entire
2631 * modelview transform that Clutter applies before applying the projection
2632 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2633 * using cogl_set_modelview_matrix() for example then you would want a matrix
2634 * that transforms into eye coordinates.
2636 * <note><para>This function explicitly initializes the given @matrix. If you just
2637 * want clutter to multiply a relative transformation with an existing matrix
2638 * you can use clutter_actor_apply_relative_transformation_matrix()
2639 * instead.</para></note>
2642 /* XXX: We should consider caching the stage relative modelview along with
2643 * the actor itself */
2645 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2646 ClutterActor *ancestor,
2649 cogl_matrix_init_identity (matrix);
2651 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2654 /* Project the given @box into stage window coordinates, writing the
2655 * transformed vertices to @verts[]. */
2657 _clutter_actor_transform_and_project_box (ClutterActor *self,
2658 const ClutterActorBox *box,
2659 ClutterVertex verts[])
2661 ClutterVertex box_vertices[4];
2663 box_vertices[0].x = box->x1;
2664 box_vertices[0].y = box->y1;
2665 box_vertices[0].z = 0;
2666 box_vertices[1].x = box->x2;
2667 box_vertices[1].y = box->y1;
2668 box_vertices[1].z = 0;
2669 box_vertices[2].x = box->x1;
2670 box_vertices[2].y = box->y2;
2671 box_vertices[2].z = 0;
2672 box_vertices[3].x = box->x2;
2673 box_vertices[3].y = box->y2;
2674 box_vertices[3].z = 0;
2677 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2681 * clutter_actor_get_allocation_vertices:
2682 * @self: A #ClutterActor
2683 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2684 * against, or %NULL to use the #ClutterStage
2685 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2686 * location for an array of 4 #ClutterVertex in which to store the result
2688 * Calculates the transformed coordinates of the four corners of the
2689 * actor in the plane of @ancestor. The returned vertices relate to
2690 * the #ClutterActorBox coordinates as follows:
2692 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2693 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2694 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2695 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2698 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2699 * this case, the coordinates returned will be the coordinates on
2700 * the stage before the projection is applied. This is different from
2701 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2706 clutter_actor_get_allocation_vertices (ClutterActor *self,
2707 ClutterActor *ancestor,
2708 ClutterVertex verts[])
2710 ClutterActorPrivate *priv;
2711 ClutterActorBox box;
2712 ClutterVertex vertices[4];
2713 CoglMatrix modelview;
2715 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2716 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2718 if (ancestor == NULL)
2719 ancestor = _clutter_actor_get_stage_internal (self);
2721 /* Fallback to a NOP transform if the actor isn't parented under a
2723 if (ancestor == NULL)
2728 /* if the actor needs to be allocated we force a relayout, so that
2729 * we will have valid values to use in the transformations */
2730 if (priv->needs_allocation)
2732 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2734 _clutter_stage_maybe_relayout (stage);
2737 box.x1 = box.y1 = 0;
2738 /* The result isn't really meaningful in this case but at
2739 * least try to do something *vaguely* reasonable... */
2740 clutter_actor_get_size (self, &box.x2, &box.y2);
2744 clutter_actor_get_allocation_box (self, &box);
2746 vertices[0].x = box.x1;
2747 vertices[0].y = box.y1;
2749 vertices[1].x = box.x2;
2750 vertices[1].y = box.y1;
2752 vertices[2].x = box.x1;
2753 vertices[2].y = box.y2;
2755 vertices[3].x = box.x2;
2756 vertices[3].y = box.y2;
2759 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2762 cogl_matrix_transform_points (&modelview,
2764 sizeof (ClutterVertex),
2766 sizeof (ClutterVertex),
2772 * clutter_actor_get_abs_allocation_vertices:
2773 * @self: A #ClutterActor
2774 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2775 * of 4 #ClutterVertex where to store the result.
2777 * Calculates the transformed screen coordinates of the four corners of
2778 * the actor; the returned vertices relate to the #ClutterActorBox
2779 * coordinates as follows:
2781 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2782 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2783 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2784 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2790 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2791 ClutterVertex verts[])
2793 ClutterActorPrivate *priv;
2794 ClutterActorBox actor_space_allocation;
2796 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2800 /* if the actor needs to be allocated we force a relayout, so that
2801 * the actor allocation box will be valid for
2802 * _clutter_actor_transform_and_project_box()
2804 if (priv->needs_allocation)
2806 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2807 /* There's nothing meaningful we can do now */
2811 _clutter_stage_maybe_relayout (stage);
2814 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2815 * own coordinate space... */
2816 actor_space_allocation.x1 = 0;
2817 actor_space_allocation.y1 = 0;
2818 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2819 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2820 _clutter_actor_transform_and_project_box (self,
2821 &actor_space_allocation,
2826 clutter_actor_real_apply_transform (ClutterActor *self,
2829 ClutterActorPrivate *priv = self->priv;
2831 if (!priv->transform_valid)
2833 CoglMatrix *transform = &priv->transform;
2834 const ClutterTransformInfo *info;
2836 info = _clutter_actor_get_transform_info_or_defaults (self);
2838 cogl_matrix_init_identity (transform);
2840 cogl_matrix_translate (transform,
2841 priv->allocation.x1,
2842 priv->allocation.y1,
2846 cogl_matrix_translate (transform, 0, 0, info->depth);
2849 * because the rotation involves translations, we must scale
2850 * before applying the rotations (if we apply the scale after
2851 * the rotations, the translations included in the rotation are
2852 * not scaled and so the entire object will move on the screen
2853 * as a result of rotating it).
2855 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2857 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2858 &info->scale_center,
2859 cogl_matrix_scale (transform,
2866 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2868 cogl_matrix_rotate (transform,
2873 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2875 cogl_matrix_rotate (transform,
2880 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2882 cogl_matrix_rotate (transform,
2886 if (!clutter_anchor_coord_is_zero (&info->anchor))
2890 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2891 cogl_matrix_translate (transform, -x, -y, -z);
2894 priv->transform_valid = TRUE;
2897 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2900 /* Applies the transforms associated with this actor to the given
2903 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2906 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2910 * clutter_actor_apply_relative_transformation_matrix:
2911 * @self: The actor whose coordinate space you want to transform from.
2912 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2913 * or %NULL if you want to transform all the way to eye coordinates.
2914 * @matrix: A #CoglMatrix to apply the transformation too.
2916 * This multiplies a transform with @matrix that will transform coordinates
2917 * from the coordinate space of @self into the coordinate space of @ancestor.
2919 * For example if you need a matrix that can transform the local actor
2920 * coordinates of @self into stage coordinates you would pass the actor's stage
2921 * pointer as the @ancestor.
2923 * If you pass %NULL then the transformation will take you all the way through
2924 * to eye coordinates. This can be useful if you want to extract the entire
2925 * modelview transform that Clutter applies before applying the projection
2926 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2927 * using cogl_set_modelview_matrix() for example then you would want a matrix
2928 * that transforms into eye coordinates.
2930 * <note>This function doesn't initialize the given @matrix, it simply
2931 * multiplies the requested transformation matrix with the existing contents of
2932 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2933 * before calling this function, or you can use
2934 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2937 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2938 ClutterActor *ancestor,
2941 ClutterActor *parent;
2943 /* Note we terminate before ever calling stage->apply_transform()
2944 * since that would conceptually be relative to the underlying
2945 * window OpenGL coordinates so we'd need a special @ancestor
2946 * value to represent the fake parent of the stage. */
2947 if (self == ancestor)
2950 parent = clutter_actor_get_parent (self);
2953 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2956 _clutter_actor_apply_modelview_transform (self, matrix);
2960 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2961 ClutterPaintVolume *pv,
2963 const CoglColor *color)
2965 static CoglPipeline *outline = NULL;
2966 CoglPrimitive *prim;
2967 ClutterVertex line_ends[12 * 2];
2970 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2971 /* XXX: at some point we'll query this from the stage but we can't
2972 * do that until the osx backend uses Cogl natively. */
2973 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2975 if (outline == NULL)
2976 outline = cogl_pipeline_new (ctx);
2978 _clutter_paint_volume_complete (pv);
2980 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2983 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2984 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2985 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2986 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2991 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2992 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2993 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2994 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2996 /* Lines connecting front face to back face */
2997 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2998 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2999 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3000 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3003 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3005 (CoglVertexP3 *)line_ends);
3007 cogl_pipeline_set_color (outline, color);
3008 cogl_framebuffer_draw_primitive (fb, outline, prim);
3009 cogl_object_unref (prim);
3013 PangoLayout *layout;
3014 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3015 pango_layout_set_text (layout, label, -1);
3016 cogl_pango_render_layout (layout,
3021 g_object_unref (layout);
3026 _clutter_actor_draw_paint_volume (ClutterActor *self)
3028 ClutterPaintVolume *pv;
3031 pv = _clutter_actor_get_paint_volume_mutable (self);
3034 gfloat width, height;
3035 ClutterPaintVolume fake_pv;
3037 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3038 _clutter_paint_volume_init_static (&fake_pv, stage);
3040 clutter_actor_get_size (self, &width, &height);
3041 clutter_paint_volume_set_width (&fake_pv, width);
3042 clutter_paint_volume_set_height (&fake_pv, height);
3044 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3045 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3046 _clutter_actor_get_debug_name (self),
3049 clutter_paint_volume_free (&fake_pv);
3053 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3054 _clutter_actor_draw_paint_volume_full (self, pv,
3055 _clutter_actor_get_debug_name (self),
3061 _clutter_actor_paint_cull_result (ClutterActor *self,
3063 ClutterCullResult result)
3065 ClutterPaintVolume *pv;
3070 if (result == CLUTTER_CULL_RESULT_IN)
3071 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3072 else if (result == CLUTTER_CULL_RESULT_OUT)
3073 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3075 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3078 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3080 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3081 _clutter_actor_draw_paint_volume_full (self, pv,
3082 _clutter_actor_get_debug_name (self),
3086 PangoLayout *layout;
3088 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3089 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3090 cogl_set_source_color (&color);
3092 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3093 pango_layout_set_text (layout, label, -1);
3094 cogl_pango_render_layout (layout,
3100 g_object_unref (layout);
3104 static int clone_paint_level = 0;
3107 _clutter_actor_push_clone_paint (void)
3109 clone_paint_level++;
3113 _clutter_actor_pop_clone_paint (void)
3115 clone_paint_level--;
3119 in_clone_paint (void)
3121 return clone_paint_level > 0;
3124 /* Returns TRUE if the actor can be ignored */
3125 /* FIXME: we should return a ClutterCullResult, and
3126 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3127 * means there's no point in trying to cull descendants of the current
3130 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3132 ClutterActorPrivate *priv = self->priv;
3133 ClutterActor *stage;
3134 const ClutterPlane *stage_clip;
3136 if (!priv->last_paint_volume_valid)
3138 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3139 "->last_paint_volume_valid == FALSE",
3140 _clutter_actor_get_debug_name (self));
3144 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3147 stage = _clutter_actor_get_stage_internal (self);
3148 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3149 if (G_UNLIKELY (!stage_clip))
3151 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3152 "No stage clip set",
3153 _clutter_actor_get_debug_name (self));
3157 if (cogl_get_draw_framebuffer () !=
3158 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3160 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3161 "Current framebuffer doesn't correspond to stage",
3162 _clutter_actor_get_debug_name (self));
3167 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3172 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3174 ClutterActorPrivate *priv = self->priv;
3175 const ClutterPaintVolume *pv;
3177 if (priv->last_paint_volume_valid)
3179 clutter_paint_volume_free (&priv->last_paint_volume);
3180 priv->last_paint_volume_valid = FALSE;
3183 pv = clutter_actor_get_paint_volume (self);
3186 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3187 "Actor failed to report a paint volume",
3188 _clutter_actor_get_debug_name (self));
3192 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3194 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3195 NULL); /* eye coordinates */
3197 priv->last_paint_volume_valid = TRUE;
3200 static inline gboolean
3201 actor_has_shader_data (ClutterActor *self)
3203 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3207 _clutter_actor_get_pick_id (ClutterActor *self)
3209 if (self->priv->pick_id < 0)
3212 return self->priv->pick_id;
3215 /* This is the same as clutter_actor_add_effect except that it doesn't
3216 queue a redraw and it doesn't notify on the effect property */
3218 _clutter_actor_add_effect_internal (ClutterActor *self,
3219 ClutterEffect *effect)
3221 ClutterActorPrivate *priv = self->priv;
3223 if (priv->effects == NULL)
3225 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3226 priv->effects->actor = self;
3229 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3232 /* This is the same as clutter_actor_remove_effect except that it doesn't
3233 queue a redraw and it doesn't notify on the effect property */
3235 _clutter_actor_remove_effect_internal (ClutterActor *self,
3236 ClutterEffect *effect)
3238 ClutterActorPrivate *priv = self->priv;
3240 if (priv->effects == NULL)
3243 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3245 if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3246 g_clear_object (&priv->effects);
3250 needs_flatten_effect (ClutterActor *self)
3252 ClutterActorPrivate *priv = self->priv;
3254 if (G_UNLIKELY (clutter_paint_debug_flags &
3255 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3258 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3260 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3262 if (clutter_actor_get_paint_opacity (self) < 255 &&
3263 clutter_actor_has_overlaps (self))
3271 add_or_remove_flatten_effect (ClutterActor *self)
3273 ClutterActorPrivate *priv = self->priv;
3275 /* Add or remove the flatten effect depending on the
3276 offscreen-redirect property. */
3277 if (needs_flatten_effect (self))
3279 if (priv->flatten_effect == NULL)
3281 ClutterActorMeta *actor_meta;
3284 priv->flatten_effect = _clutter_flatten_effect_new ();
3285 /* Keep a reference to the effect so that we can queue
3287 g_object_ref_sink (priv->flatten_effect);
3289 /* Set the priority of the effect to high so that it will
3290 always be applied to the actor first. It uses an internal
3291 priority so that it won't be visible to applications */
3292 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3293 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3294 _clutter_actor_meta_set_priority (actor_meta, priority);
3296 /* This will add the effect without queueing a redraw */
3297 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3302 if (priv->flatten_effect != NULL)
3304 /* Destroy the effect so that it will lose its fbo cache of
3306 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3307 g_clear_object (&priv->flatten_effect);
3313 clutter_actor_real_paint (ClutterActor *actor)
3315 ClutterActorPrivate *priv = actor->priv;
3318 for (iter = priv->first_child;
3320 iter = iter->priv->next_sibling)
3322 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3323 _clutter_actor_get_debug_name (iter),
3324 _clutter_actor_get_debug_name (actor),
3325 iter->priv->allocation.x1,
3326 iter->priv->allocation.y1,
3327 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3328 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3330 clutter_actor_paint (iter);
3335 clutter_actor_paint_node (ClutterActor *actor,
3336 ClutterPaintNode *root)
3338 ClutterActorPrivate *priv = actor->priv;
3343 if (priv->bg_color_set &&
3344 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3346 ClutterPaintNode *node;
3347 ClutterColor bg_color;
3348 ClutterActorBox box;
3352 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3353 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3355 bg_color = priv->bg_color;
3356 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3357 * priv->bg_color.alpha
3360 node = clutter_color_node_new (&bg_color);
3361 clutter_paint_node_set_name (node, "backgroundColor");
3362 clutter_paint_node_add_rectangle (node, &box);
3363 clutter_paint_node_add_child (root, node);
3364 clutter_paint_node_unref (node);
3367 if (priv->content != NULL)
3368 _clutter_content_paint_content (priv->content, actor, root);
3370 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3371 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3373 if (clutter_paint_node_get_n_children (root) == 0)
3376 #ifdef CLUTTER_ENABLE_DEBUG
3377 if (CLUTTER_HAS_DEBUG (PAINT))
3379 /* dump the tree only if we have one */
3380 _clutter_paint_node_dump_tree (root);
3382 #endif /* CLUTTER_ENABLE_DEBUG */
3384 _clutter_paint_node_paint (root);
3387 /* XXX: Uncomment this when we disable emitting the paint signal */
3388 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3395 * clutter_actor_paint:
3396 * @self: A #ClutterActor
3398 * Renders the actor to display.
3400 * This function should not be called directly by applications.
3401 * Call clutter_actor_queue_redraw() to queue paints, instead.
3403 * This function is context-aware, and will either cause a
3404 * regular paint or a pick paint.
3406 * This function will emit the #ClutterActor::paint signal or
3407 * the #ClutterActor::pick signal, depending on the context.
3409 * This function does not paint the actor if the actor is set to 0,
3410 * unless it is performing a pick paint.
3413 clutter_actor_paint (ClutterActor *self)
3415 ClutterActorPrivate *priv;
3416 ClutterPickMode pick_mode;
3417 gboolean clip_set = FALSE;
3418 gboolean shader_applied = FALSE;
3420 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3421 "Actor real-paint counter",
3422 "Increments each time any actor is painted",
3423 0 /* no application private data */);
3424 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3425 "Actor pick-paint counter",
3426 "Increments each time any actor is painted "
3428 0 /* no application private data */);
3430 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3432 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3437 pick_mode = _clutter_context_get_pick_mode ();
3439 if (pick_mode == CLUTTER_PICK_NONE)
3440 priv->propagated_one_redraw = FALSE;
3442 /* It's an important optimization that we consider painting of
3443 * actors with 0 opacity to be a NOP... */
3444 if (pick_mode == CLUTTER_PICK_NONE &&
3445 /* ignore top-levels, since they might be transparent */
3446 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3447 /* Use the override opacity if its been set */
3448 ((priv->opacity_override >= 0) ?
3449 priv->opacity_override : priv->opacity) == 0)
3452 /* if we aren't paintable (not in a toplevel with all
3453 * parents paintable) then do nothing.
3455 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3458 /* mark that we are in the paint process */
3459 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3463 if (priv->enable_model_view_transform)
3467 /* XXX: It could be better to cache the modelview with the actor
3468 * instead of progressively building up the transformations on
3469 * the matrix stack every time we paint. */
3470 cogl_get_modelview_matrix (&matrix);
3471 _clutter_actor_apply_modelview_transform (self, &matrix);
3473 #ifdef CLUTTER_ENABLE_DEBUG
3474 /* Catch when out-of-band transforms have been made by actors not as part
3475 * of an apply_transform vfunc... */
3476 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3478 CoglMatrix expected_matrix;
3480 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3483 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3485 GString *buf = g_string_sized_new (1024);
3486 ClutterActor *parent;
3489 while (parent != NULL)
3491 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3493 if (parent->priv->parent != NULL)
3494 g_string_append (buf, "->");
3496 parent = parent->priv->parent;
3499 g_warning ("Unexpected transform found when painting actor "
3500 "\"%s\". This will be caused by one of the actor's "
3501 "ancestors (%s) using the Cogl API directly to transform "
3502 "children instead of using ::apply_transform().",
3503 _clutter_actor_get_debug_name (self),
3506 g_string_free (buf, TRUE);
3509 #endif /* CLUTTER_ENABLE_DEBUG */
3511 cogl_set_modelview_matrix (&matrix);
3516 cogl_clip_push_rectangle (priv->clip.x,
3518 priv->clip.x + priv->clip.width,
3519 priv->clip.y + priv->clip.height);
3522 else if (priv->clip_to_allocation)
3524 gfloat width, height;
3526 width = priv->allocation.x2 - priv->allocation.x1;
3527 height = priv->allocation.y2 - priv->allocation.y1;
3529 cogl_clip_push_rectangle (0, 0, width, height);
3533 if (pick_mode == CLUTTER_PICK_NONE)
3535 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3537 /* We check whether we need to add the flatten effect before
3538 each paint so that we can avoid having a mechanism for
3539 applications to notify when the value of the
3540 has_overlaps virtual changes. */
3541 add_or_remove_flatten_effect (self);
3544 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3546 /* We save the current paint volume so that the next time the
3547 * actor queues a redraw we can constrain the redraw to just
3548 * cover the union of the new bounding box and the old.
3550 * We also fetch the current paint volume to perform culling so
3551 * we can avoid painting actors outside the current clip region.
3553 * If we are painting inside a clone, we should neither update
3554 * the paint volume or use it to cull painting, since the paint
3555 * box represents the location of the source actor on the
3558 * XXX: We are starting to do a lot of vertex transforms on
3559 * the CPU in a typical paint, so at some point we should
3560 * audit these and consider caching some things.
3562 * NB: We don't perform culling while picking at this point because
3563 * clutter-stage.c doesn't setup the clipping planes appropriately.
3565 * NB: We don't want to update the last-paint-volume during picking
3566 * because the last-paint-volume is used to determine the old screen
3567 * space location of an actor that has moved so we can know the
3568 * minimal region to redraw to clear an old view of the actor. If we
3569 * update this during picking then by the time we come around to
3570 * paint then the last-paint-volume would likely represent the new
3571 * actor position not the old.
3573 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3576 /* annoyingly gcc warns if uninitialized even though
3577 * the initialization is redundant :-( */
3578 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3580 if (G_LIKELY ((clutter_paint_debug_flags &
3581 (CLUTTER_DEBUG_DISABLE_CULLING |
3582 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3583 (CLUTTER_DEBUG_DISABLE_CULLING |
3584 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3585 _clutter_actor_update_last_paint_volume (self);
3587 success = cull_actor (self, &result);
3589 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3590 _clutter_actor_paint_cull_result (self, success, result);
3591 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3595 if (priv->effects == NULL)
3597 if (pick_mode == CLUTTER_PICK_NONE &&
3598 actor_has_shader_data (self))
3600 _clutter_actor_shader_pre_paint (self, FALSE);
3601 shader_applied = TRUE;
3604 priv->next_effect_to_paint = NULL;
3607 priv->next_effect_to_paint =
3608 _clutter_meta_group_peek_metas (priv->effects);
3610 clutter_actor_continue_paint (self);
3613 _clutter_actor_shader_post_paint (self);
3615 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3616 pick_mode == CLUTTER_PICK_NONE))
3617 _clutter_actor_draw_paint_volume (self);
3620 /* If we make it here then the actor has run through a complete
3621 paint run including all the effects so it's no longer dirty */
3622 if (pick_mode == CLUTTER_PICK_NONE)
3623 priv->is_dirty = FALSE;
3630 /* paint sequence complete */
3631 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3635 * clutter_actor_continue_paint:
3636 * @self: A #ClutterActor
3638 * Run the next stage of the paint sequence. This function should only
3639 * be called within the implementation of the ‘run’ virtual of a
3640 * #ClutterEffect. It will cause the run method of the next effect to
3641 * be applied, or it will paint the actual actor if the current effect
3642 * is the last effect in the chain.
3647 clutter_actor_continue_paint (ClutterActor *self)
3649 ClutterActorPrivate *priv;
3651 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3652 /* This should only be called from with in the ‘run’ implementation
3653 of a ClutterEffect */
3654 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3658 /* Skip any effects that are disabled */
3659 while (priv->next_effect_to_paint &&
3660 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3661 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3663 /* If this has come from the last effect then we'll just paint the
3665 if (priv->next_effect_to_paint == NULL)
3667 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3669 ClutterPaintNode *dummy;
3671 /* XXX - this will go away in 2.0, when we can get rid of this
3672 * stuff and switch to a pure retained render tree of PaintNodes
3673 * for the entire frame, starting from the Stage; the paint()
3674 * virtual function can then be called directly.
3676 dummy = _clutter_dummy_node_new (self);
3677 clutter_paint_node_set_name (dummy, "Root");
3679 /* XXX - for 1.12, we use the return value of paint_node() to
3680 * decide whether we should emit the ::paint signal.
3682 clutter_actor_paint_node (self, dummy);
3683 clutter_paint_node_unref (dummy);
3685 g_signal_emit (self, actor_signals[PAINT], 0);
3689 ClutterColor col = { 0, };
3691 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3693 /* Actor will then paint silhouette of itself in supplied
3694 * color. See clutter_stage_get_actor_at_pos() for where
3695 * picking is enabled.
3697 g_signal_emit (self, actor_signals[PICK], 0, &col);
3702 ClutterEffect *old_current_effect;
3703 ClutterEffectPaintFlags run_flags = 0;
3705 /* Cache the current effect so that we can put it back before
3707 old_current_effect = priv->current_effect;
3709 priv->current_effect = priv->next_effect_to_paint->data;
3710 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3712 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3716 /* If there's an effect queued with this redraw then all
3717 effects up to that one will be considered dirty. It
3718 is expected the queued effect will paint the cached
3719 image and not call clutter_actor_continue_paint again
3720 (although it should work ok if it does) */
3721 if (priv->effect_to_redraw == NULL ||
3722 priv->current_effect != priv->effect_to_redraw)
3723 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3726 _clutter_effect_paint (priv->current_effect, run_flags);
3730 /* We can't determine when an actor has been modified since
3731 its last pick so lets just assume it has always been
3733 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3735 _clutter_effect_pick (priv->current_effect, run_flags);
3738 priv->current_effect = old_current_effect;
3742 static ClutterActorTraverseVisitFlags
3743 invalidate_queue_redraw_entry (ClutterActor *self,
3747 ClutterActorPrivate *priv = self->priv;
3749 if (priv->queue_redraw_entry != NULL)
3751 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3752 priv->queue_redraw_entry = NULL;
3755 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3759 remove_child (ClutterActor *self,
3760 ClutterActor *child)
3762 ClutterActor *prev_sibling, *next_sibling;
3764 prev_sibling = child->priv->prev_sibling;
3765 next_sibling = child->priv->next_sibling;
3767 if (prev_sibling != NULL)
3768 prev_sibling->priv->next_sibling = next_sibling;
3770 if (next_sibling != NULL)
3771 next_sibling->priv->prev_sibling = prev_sibling;
3773 if (self->priv->first_child == child)
3774 self->priv->first_child = next_sibling;
3776 if (self->priv->last_child == child)
3777 self->priv->last_child = prev_sibling;
3779 child->priv->parent = NULL;
3780 child->priv->prev_sibling = NULL;
3781 child->priv->next_sibling = NULL;
3785 REMOVE_CHILD_DESTROY_META = 1 << 0,
3786 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3787 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3788 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3789 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3790 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3792 /* default flags for public API */
3793 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3794 REMOVE_CHILD_EMIT_PARENT_SET |
3795 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3796 REMOVE_CHILD_CHECK_STATE |
3797 REMOVE_CHILD_FLUSH_QUEUE |
3798 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3800 /* flags for legacy/deprecated API */
3801 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3802 REMOVE_CHILD_FLUSH_QUEUE |
3803 REMOVE_CHILD_EMIT_PARENT_SET |
3804 REMOVE_CHILD_NOTIFY_FIRST_LAST
3805 } ClutterActorRemoveChildFlags;
3808 * clutter_actor_remove_child_internal:
3809 * @self: a #ClutterActor
3810 * @child: the child of @self that has to be removed
3811 * @flags: control the removal operations
3813 * Removes @child from the list of children of @self.
3816 clutter_actor_remove_child_internal (ClutterActor *self,
3817 ClutterActor *child,
3818 ClutterActorRemoveChildFlags flags)
3820 ClutterActor *old_first, *old_last;
3821 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3822 gboolean flush_queue;
3823 gboolean notify_first_last;
3824 gboolean was_mapped;
3826 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3827 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3828 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3829 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3830 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3831 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3833 g_object_freeze_notify (G_OBJECT (self));
3836 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3840 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3842 /* we need to unrealize *before* we set parent_actor to NULL,
3843 * because in an unrealize method actors are dissociating from the
3844 * stage, which means they need to be able to
3845 * clutter_actor_get_stage().
3847 * yhis should unmap and unrealize, unless we're reparenting.
3849 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3856 /* We take this opportunity to invalidate any queue redraw entry
3857 * associated with the actor and descendants since we won't be able to
3858 * determine the appropriate stage after this.
3860 * we do this after we updated the mapped state because actors might
3861 * end up queueing redraws inside their mapped/unmapped virtual
3862 * functions, and if we invalidate the redraw entry we could end up
3863 * with an inconsistent state and weird memory corruption. see
3866 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3867 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3869 _clutter_actor_traverse (child,
3871 invalidate_queue_redraw_entry,
3876 old_first = self->priv->first_child;
3877 old_last = self->priv->last_child;
3879 remove_child (self, child);
3881 self->priv->n_children -= 1;
3883 self->priv->age += 1;
3885 /* clutter_actor_reparent() will emit ::parent-set for us */
3886 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3887 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3889 /* if the child was mapped then we need to relayout ourselves to account
3890 * for the removed child
3893 clutter_actor_queue_relayout (self);
3895 /* we need to emit the signal before dropping the reference */
3896 if (emit_actor_removed)
3897 g_signal_emit_by_name (self, "actor-removed", child);
3899 if (notify_first_last)
3901 if (old_first != self->priv->first_child)
3902 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3904 if (old_last != self->priv->last_child)
3905 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3908 g_object_thaw_notify (G_OBJECT (self));
3910 /* remove the reference we acquired in clutter_actor_add_child() */
3911 g_object_unref (child);
3914 static const ClutterTransformInfo default_transform_info = {
3915 0.0, { 0, }, /* rotation-x */
3916 0.0, { 0, }, /* rotation-y */
3917 0.0, { 0, }, /* rotation-z */
3919 1.0, 1.0, { 0, }, /* scale */
3921 { 0, }, /* anchor */
3927 * _clutter_actor_get_transform_info_or_defaults:
3928 * @self: a #ClutterActor
3930 * Retrieves the ClutterTransformInfo structure associated to an actor.
3932 * If the actor does not have a ClutterTransformInfo structure associated
3933 * to it, then the default structure will be returned.
3935 * This function should only be used for getters.
3937 * Return value: a const pointer to the ClutterTransformInfo structure
3939 const ClutterTransformInfo *
3940 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3942 ClutterTransformInfo *info;
3944 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3948 return &default_transform_info;
3952 clutter_transform_info_free (gpointer data)
3955 g_slice_free (ClutterTransformInfo, data);
3959 * _clutter_actor_get_transform_info:
3960 * @self: a #ClutterActor
3962 * Retrieves a pointer to the ClutterTransformInfo structure.
3964 * If the actor does not have a ClutterTransformInfo associated to it, one
3965 * will be created and initialized to the default values.
3967 * This function should be used for setters.
3969 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3972 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3975 ClutterTransformInfo *
3976 _clutter_actor_get_transform_info (ClutterActor *self)
3978 ClutterTransformInfo *info;
3980 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3983 info = g_slice_new (ClutterTransformInfo);
3985 *info = default_transform_info;
3987 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3989 clutter_transform_info_free);
3996 * clutter_actor_set_rotation_angle_internal:
3997 * @self: a #ClutterActor
3998 * @axis: the axis of the angle to change
3999 * @angle: the angle of rotation
4001 * Sets the rotation angle on the given axis without affecting the
4002 * rotation center point.
4005 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
4006 ClutterRotateAxis axis,
4009 GObject *obj = G_OBJECT (self);
4010 ClutterTransformInfo *info;
4012 info = _clutter_actor_get_transform_info (self);
4014 g_object_freeze_notify (obj);
4018 case CLUTTER_X_AXIS:
4019 info->rx_angle = angle;
4020 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4023 case CLUTTER_Y_AXIS:
4024 info->ry_angle = angle;
4025 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4028 case CLUTTER_Z_AXIS:
4029 info->rz_angle = angle;
4030 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4034 self->priv->transform_valid = FALSE;
4036 g_object_thaw_notify (obj);
4038 clutter_actor_queue_redraw (self);
4042 clutter_actor_set_rotation_angle (ClutterActor *self,
4043 ClutterRotateAxis axis,
4046 const ClutterTransformInfo *info;
4047 const double *cur_angle_p = NULL;
4048 GParamSpec *pspec = NULL;
4050 info = _clutter_actor_get_transform_info_or_defaults (self);
4054 case CLUTTER_X_AXIS:
4055 cur_angle_p = &info->rx_angle;
4056 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4059 case CLUTTER_Y_AXIS:
4060 cur_angle_p = &info->ry_angle;
4061 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4064 case CLUTTER_Z_AXIS:
4065 cur_angle_p = &info->rz_angle;
4066 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4070 g_assert (pspec != NULL);
4071 g_assert (cur_angle_p != NULL);
4073 if (_clutter_actor_get_transition (self, pspec) == NULL)
4074 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4076 _clutter_actor_update_transition (self, pspec, angle);
4078 clutter_actor_queue_redraw (self);
4082 * clutter_actor_set_rotation_center_internal:
4083 * @self: a #ClutterActor
4084 * @axis: the axis of the center to change
4085 * @center: the coordinates of the rotation center
4087 * Sets the rotation center on the given axis without affecting the
4091 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4092 ClutterRotateAxis axis,
4093 const ClutterVertex *center)
4095 GObject *obj = G_OBJECT (self);
4096 ClutterTransformInfo *info;
4097 ClutterVertex v = { 0, 0, 0 };
4099 info = _clutter_actor_get_transform_info (self);
4104 g_object_freeze_notify (obj);
4108 case CLUTTER_X_AXIS:
4109 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4110 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4113 case CLUTTER_Y_AXIS:
4114 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4115 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4118 case CLUTTER_Z_AXIS:
4119 /* if the previously set rotation center was fractional, then
4120 * setting explicit coordinates will have to notify the
4121 * :rotation-center-z-gravity property as well
4123 if (info->rz_center.is_fractional)
4124 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4126 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4127 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4131 self->priv->transform_valid = FALSE;
4133 g_object_thaw_notify (obj);
4135 clutter_actor_queue_redraw (self);
4139 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4143 GObject *obj = G_OBJECT (self);
4144 ClutterTransformInfo *info;
4146 info = _clutter_actor_get_transform_info (self);
4148 if (pspec == obj_props[PROP_SCALE_X])
4149 info->scale_x = factor;
4151 info->scale_y = factor;
4153 self->priv->transform_valid = FALSE;
4154 clutter_actor_queue_redraw (self);
4155 g_object_notify_by_pspec (obj, pspec);
4159 clutter_actor_set_scale_factor (ClutterActor *self,
4160 ClutterRotateAxis axis,
4163 const ClutterTransformInfo *info;
4164 const double *scale_p = NULL;
4165 GParamSpec *pspec = NULL;
4167 info = _clutter_actor_get_transform_info_or_defaults (self);
4171 case CLUTTER_X_AXIS:
4172 pspec = obj_props[PROP_SCALE_X];
4173 scale_p = &info->scale_x;
4176 case CLUTTER_Y_AXIS:
4177 pspec = obj_props[PROP_SCALE_Y];
4178 scale_p = &info->scale_y;
4181 case CLUTTER_Z_AXIS:
4185 g_assert (pspec != NULL);
4186 g_assert (scale_p != NULL);
4188 if (_clutter_actor_get_transition (self, pspec) == NULL)
4189 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4191 _clutter_actor_update_transition (self, pspec, factor);
4193 clutter_actor_queue_redraw (self);
4197 clutter_actor_set_scale_center (ClutterActor *self,
4198 ClutterRotateAxis axis,
4201 GObject *obj = G_OBJECT (self);
4202 ClutterTransformInfo *info;
4203 gfloat center_x, center_y;
4205 info = _clutter_actor_get_transform_info (self);
4207 g_object_freeze_notify (obj);
4209 /* get the current scale center coordinates */
4210 clutter_anchor_coord_get_units (self, &info->scale_center,
4215 /* we need to notify this too, because setting explicit coordinates will
4216 * change the gravity as a side effect
4218 if (info->scale_center.is_fractional)
4219 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4223 case CLUTTER_X_AXIS:
4224 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4225 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4228 case CLUTTER_Y_AXIS:
4229 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4230 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4234 g_assert_not_reached ();
4237 self->priv->transform_valid = FALSE;
4239 clutter_actor_queue_redraw (self);
4241 g_object_thaw_notify (obj);
4245 clutter_actor_set_scale_gravity (ClutterActor *self,
4246 ClutterGravity gravity)
4248 ClutterTransformInfo *info;
4251 info = _clutter_actor_get_transform_info (self);
4252 obj = G_OBJECT (self);
4254 if (gravity == CLUTTER_GRAVITY_NONE)
4255 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4257 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4259 self->priv->transform_valid = FALSE;
4261 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4262 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4263 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4265 clutter_actor_queue_redraw (self);
4269 clutter_actor_set_anchor_coord (ClutterActor *self,
4270 ClutterRotateAxis axis,
4273 GObject *obj = G_OBJECT (self);
4274 ClutterTransformInfo *info;
4275 gfloat anchor_x, anchor_y;
4277 info = _clutter_actor_get_transform_info (self);
4279 g_object_freeze_notify (obj);
4281 clutter_anchor_coord_get_units (self, &info->anchor,
4286 if (info->anchor.is_fractional)
4287 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4291 case CLUTTER_X_AXIS:
4292 clutter_anchor_coord_set_units (&info->anchor,
4296 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4299 case CLUTTER_Y_AXIS:
4300 clutter_anchor_coord_set_units (&info->anchor,
4304 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4308 g_assert_not_reached ();
4311 self->priv->transform_valid = FALSE;
4313 clutter_actor_queue_redraw (self);
4315 g_object_thaw_notify (obj);
4319 clutter_actor_set_property (GObject *object,
4321 const GValue *value,
4324 ClutterActor *actor = CLUTTER_ACTOR (object);
4325 ClutterActorPrivate *priv = actor->priv;
4330 clutter_actor_set_x (actor, g_value_get_float (value));
4334 clutter_actor_set_y (actor, g_value_get_float (value));
4338 clutter_actor_set_width (actor, g_value_get_float (value));
4342 clutter_actor_set_height (actor, g_value_get_float (value));
4346 clutter_actor_set_x (actor, g_value_get_float (value));
4350 clutter_actor_set_y (actor, g_value_get_float (value));
4353 case PROP_FIXED_POSITION_SET:
4354 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4357 case PROP_MIN_WIDTH:
4358 clutter_actor_set_min_width (actor, g_value_get_float (value));
4361 case PROP_MIN_HEIGHT:
4362 clutter_actor_set_min_height (actor, g_value_get_float (value));
4365 case PROP_NATURAL_WIDTH:
4366 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4369 case PROP_NATURAL_HEIGHT:
4370 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4373 case PROP_MIN_WIDTH_SET:
4374 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4377 case PROP_MIN_HEIGHT_SET:
4378 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4381 case PROP_NATURAL_WIDTH_SET:
4382 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4385 case PROP_NATURAL_HEIGHT_SET:
4386 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4389 case PROP_REQUEST_MODE:
4390 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4394 clutter_actor_set_depth (actor, g_value_get_float (value));
4398 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4401 case PROP_OFFSCREEN_REDIRECT:
4402 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4406 clutter_actor_set_name (actor, g_value_get_string (value));
4410 if (g_value_get_boolean (value) == TRUE)
4411 clutter_actor_show (actor);
4413 clutter_actor_hide (actor);
4417 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4418 g_value_get_double (value));
4422 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4423 g_value_get_double (value));
4426 case PROP_SCALE_CENTER_X:
4427 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4428 g_value_get_float (value));
4431 case PROP_SCALE_CENTER_Y:
4432 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4433 g_value_get_float (value));
4436 case PROP_SCALE_GRAVITY:
4437 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4442 const ClutterGeometry *geom = g_value_get_boxed (value);
4444 clutter_actor_set_clip (actor,
4446 geom->width, geom->height);
4450 case PROP_CLIP_TO_ALLOCATION:
4451 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4455 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4458 case PROP_ROTATION_ANGLE_X:
4459 clutter_actor_set_rotation_angle (actor,
4461 g_value_get_double (value));
4464 case PROP_ROTATION_ANGLE_Y:
4465 clutter_actor_set_rotation_angle (actor,
4467 g_value_get_double (value));
4470 case PROP_ROTATION_ANGLE_Z:
4471 clutter_actor_set_rotation_angle (actor,
4473 g_value_get_double (value));
4476 case PROP_ROTATION_CENTER_X:
4477 clutter_actor_set_rotation_center_internal (actor,
4479 g_value_get_boxed (value));
4482 case PROP_ROTATION_CENTER_Y:
4483 clutter_actor_set_rotation_center_internal (actor,
4485 g_value_get_boxed (value));
4488 case PROP_ROTATION_CENTER_Z:
4489 clutter_actor_set_rotation_center_internal (actor,
4491 g_value_get_boxed (value));
4494 case PROP_ROTATION_CENTER_Z_GRAVITY:
4496 const ClutterTransformInfo *info;
4498 info = _clutter_actor_get_transform_info_or_defaults (actor);
4499 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4500 g_value_get_enum (value));
4505 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4506 g_value_get_float (value));
4510 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4511 g_value_get_float (value));
4514 case PROP_ANCHOR_GRAVITY:
4515 clutter_actor_set_anchor_point_from_gravity (actor,
4516 g_value_get_enum (value));
4519 case PROP_SHOW_ON_SET_PARENT:
4520 priv->show_on_set_parent = g_value_get_boolean (value);
4523 case PROP_TEXT_DIRECTION:
4524 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4528 clutter_actor_add_action (actor, g_value_get_object (value));
4531 case PROP_CONSTRAINTS:
4532 clutter_actor_add_constraint (actor, g_value_get_object (value));
4536 clutter_actor_add_effect (actor, g_value_get_object (value));
4539 case PROP_LAYOUT_MANAGER:
4540 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4544 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4548 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4551 case PROP_MARGIN_TOP:
4552 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4555 case PROP_MARGIN_BOTTOM:
4556 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4559 case PROP_MARGIN_LEFT:
4560 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4563 case PROP_MARGIN_RIGHT:
4564 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4567 case PROP_BACKGROUND_COLOR:
4568 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4572 clutter_actor_set_content (actor, g_value_get_object (value));
4575 case PROP_CONTENT_GRAVITY:
4576 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4579 case PROP_MINIFICATION_FILTER:
4580 clutter_actor_set_content_scaling_filters (actor,
4581 g_value_get_enum (value),
4582 actor->priv->mag_filter);
4585 case PROP_MAGNIFICATION_FILTER:
4586 clutter_actor_set_content_scaling_filters (actor,
4587 actor->priv->min_filter,
4588 g_value_get_enum (value));
4592 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4598 clutter_actor_get_property (GObject *object,
4603 ClutterActor *actor = CLUTTER_ACTOR (object);
4604 ClutterActorPrivate *priv = actor->priv;
4609 g_value_set_float (value, clutter_actor_get_x (actor));
4613 g_value_set_float (value, clutter_actor_get_y (actor));
4617 g_value_set_float (value, clutter_actor_get_width (actor));
4621 g_value_set_float (value, clutter_actor_get_height (actor));
4626 const ClutterLayoutInfo *info;
4628 info = _clutter_actor_get_layout_info_or_defaults (actor);
4629 g_value_set_float (value, info->fixed_x);
4635 const ClutterLayoutInfo *info;
4637 info = _clutter_actor_get_layout_info_or_defaults (actor);
4638 g_value_set_float (value, info->fixed_y);
4642 case PROP_FIXED_POSITION_SET:
4643 g_value_set_boolean (value, priv->position_set);
4646 case PROP_MIN_WIDTH:
4648 const ClutterLayoutInfo *info;
4650 info = _clutter_actor_get_layout_info_or_defaults (actor);
4651 g_value_set_float (value, info->min_width);
4655 case PROP_MIN_HEIGHT:
4657 const ClutterLayoutInfo *info;
4659 info = _clutter_actor_get_layout_info_or_defaults (actor);
4660 g_value_set_float (value, info->min_height);
4664 case PROP_NATURAL_WIDTH:
4666 const ClutterLayoutInfo *info;
4668 info = _clutter_actor_get_layout_info_or_defaults (actor);
4669 g_value_set_float (value, info->natural_width);
4673 case PROP_NATURAL_HEIGHT:
4675 const ClutterLayoutInfo *info;
4677 info = _clutter_actor_get_layout_info_or_defaults (actor);
4678 g_value_set_float (value, info->natural_height);
4682 case PROP_MIN_WIDTH_SET:
4683 g_value_set_boolean (value, priv->min_width_set);
4686 case PROP_MIN_HEIGHT_SET:
4687 g_value_set_boolean (value, priv->min_height_set);
4690 case PROP_NATURAL_WIDTH_SET:
4691 g_value_set_boolean (value, priv->natural_width_set);
4694 case PROP_NATURAL_HEIGHT_SET:
4695 g_value_set_boolean (value, priv->natural_height_set);
4698 case PROP_REQUEST_MODE:
4699 g_value_set_enum (value, priv->request_mode);
4702 case PROP_ALLOCATION:
4703 g_value_set_boxed (value, &priv->allocation);
4707 g_value_set_float (value, clutter_actor_get_depth (actor));
4711 g_value_set_uint (value, priv->opacity);
4714 case PROP_OFFSCREEN_REDIRECT:
4715 g_value_set_enum (value, priv->offscreen_redirect);
4719 g_value_set_string (value, priv->name);
4723 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4727 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4731 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4735 g_value_set_boolean (value, priv->has_clip);
4740 ClutterGeometry clip;
4742 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4743 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4744 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4745 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4747 g_value_set_boxed (value, &clip);
4751 case PROP_CLIP_TO_ALLOCATION:
4752 g_value_set_boolean (value, priv->clip_to_allocation);
4757 const ClutterTransformInfo *info;
4759 info = _clutter_actor_get_transform_info_or_defaults (actor);
4760 g_value_set_double (value, info->scale_x);
4766 const ClutterTransformInfo *info;
4768 info = _clutter_actor_get_transform_info_or_defaults (actor);
4769 g_value_set_double (value, info->scale_y);
4773 case PROP_SCALE_CENTER_X:
4777 clutter_actor_get_scale_center (actor, ¢er, NULL);
4779 g_value_set_float (value, center);
4783 case PROP_SCALE_CENTER_Y:
4787 clutter_actor_get_scale_center (actor, NULL, ¢er);
4789 g_value_set_float (value, center);
4793 case PROP_SCALE_GRAVITY:
4794 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4798 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4801 case PROP_ROTATION_ANGLE_X:
4803 const ClutterTransformInfo *info;
4805 info = _clutter_actor_get_transform_info_or_defaults (actor);
4806 g_value_set_double (value, info->rx_angle);
4810 case PROP_ROTATION_ANGLE_Y:
4812 const ClutterTransformInfo *info;
4814 info = _clutter_actor_get_transform_info_or_defaults (actor);
4815 g_value_set_double (value, info->ry_angle);
4819 case PROP_ROTATION_ANGLE_Z:
4821 const ClutterTransformInfo *info;
4823 info = _clutter_actor_get_transform_info_or_defaults (actor);
4824 g_value_set_double (value, info->rz_angle);
4828 case PROP_ROTATION_CENTER_X:
4830 ClutterVertex center;
4832 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4837 g_value_set_boxed (value, ¢er);
4841 case PROP_ROTATION_CENTER_Y:
4843 ClutterVertex center;
4845 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4850 g_value_set_boxed (value, ¢er);
4854 case PROP_ROTATION_CENTER_Z:
4856 ClutterVertex center;
4858 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4863 g_value_set_boxed (value, ¢er);
4867 case PROP_ROTATION_CENTER_Z_GRAVITY:
4868 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4873 const ClutterTransformInfo *info;
4876 info = _clutter_actor_get_transform_info_or_defaults (actor);
4877 clutter_anchor_coord_get_units (actor, &info->anchor,
4881 g_value_set_float (value, anchor_x);
4887 const ClutterTransformInfo *info;
4890 info = _clutter_actor_get_transform_info_or_defaults (actor);
4891 clutter_anchor_coord_get_units (actor, &info->anchor,
4895 g_value_set_float (value, anchor_y);
4899 case PROP_ANCHOR_GRAVITY:
4900 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4903 case PROP_SHOW_ON_SET_PARENT:
4904 g_value_set_boolean (value, priv->show_on_set_parent);
4907 case PROP_TEXT_DIRECTION:
4908 g_value_set_enum (value, priv->text_direction);
4911 case PROP_HAS_POINTER:
4912 g_value_set_boolean (value, priv->has_pointer);
4915 case PROP_LAYOUT_MANAGER:
4916 g_value_set_object (value, priv->layout_manager);
4921 const ClutterLayoutInfo *info;
4923 info = _clutter_actor_get_layout_info_or_defaults (actor);
4924 g_value_set_enum (value, info->x_align);
4930 const ClutterLayoutInfo *info;
4932 info = _clutter_actor_get_layout_info_or_defaults (actor);
4933 g_value_set_enum (value, info->y_align);
4937 case PROP_MARGIN_TOP:
4939 const ClutterLayoutInfo *info;
4941 info = _clutter_actor_get_layout_info_or_defaults (actor);
4942 g_value_set_float (value, info->margin.top);
4946 case PROP_MARGIN_BOTTOM:
4948 const ClutterLayoutInfo *info;
4950 info = _clutter_actor_get_layout_info_or_defaults (actor);
4951 g_value_set_float (value, info->margin.bottom);
4955 case PROP_MARGIN_LEFT:
4957 const ClutterLayoutInfo *info;
4959 info = _clutter_actor_get_layout_info_or_defaults (actor);
4960 g_value_set_float (value, info->margin.left);
4964 case PROP_MARGIN_RIGHT:
4966 const ClutterLayoutInfo *info;
4968 info = _clutter_actor_get_layout_info_or_defaults (actor);
4969 g_value_set_float (value, info->margin.right);
4973 case PROP_BACKGROUND_COLOR_SET:
4974 g_value_set_boolean (value, priv->bg_color_set);
4977 case PROP_BACKGROUND_COLOR:
4978 g_value_set_boxed (value, &priv->bg_color);
4981 case PROP_FIRST_CHILD:
4982 g_value_set_object (value, priv->first_child);
4985 case PROP_LAST_CHILD:
4986 g_value_set_object (value, priv->last_child);
4990 g_value_set_object (value, priv->content);
4993 case PROP_CONTENT_GRAVITY:
4994 g_value_set_enum (value, priv->content_gravity);
4997 case PROP_CONTENT_BOX:
4999 ClutterActorBox box = { 0, };
5001 clutter_actor_get_content_box (actor, &box);
5002 g_value_set_boxed (value, &box);
5006 case PROP_MINIFICATION_FILTER:
5007 g_value_set_enum (value, priv->min_filter);
5010 case PROP_MAGNIFICATION_FILTER:
5011 g_value_set_enum (value, priv->mag_filter);
5015 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5021 clutter_actor_dispose (GObject *object)
5023 ClutterActor *self = CLUTTER_ACTOR (object);
5024 ClutterActorPrivate *priv = self->priv;
5026 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5028 g_type_name (G_OBJECT_TYPE (self)),
5031 g_signal_emit (self, actor_signals[DESTROY], 0);
5033 /* avoid recursing when called from clutter_actor_destroy() */
5034 if (priv->parent != NULL)
5036 ClutterActor *parent = priv->parent;
5038 /* go through the Container implementation unless this
5039 * is an internal child and has been marked as such.
5041 * removing the actor from its parent will reset the
5042 * realized and mapped states.
5044 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5045 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5047 clutter_actor_remove_child_internal (parent, self,
5048 REMOVE_CHILD_LEGACY_FLAGS);
5051 /* parent must be gone at this point */
5052 g_assert (priv->parent == NULL);
5054 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5056 /* can't be mapped or realized with no parent */
5057 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5058 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5061 g_clear_object (&priv->pango_context);
5062 g_clear_object (&priv->actions);
5063 g_clear_object (&priv->constraints);
5064 g_clear_object (&priv->effects);
5065 g_clear_object (&priv->flatten_effect);
5067 if (priv->layout_manager != NULL)
5069 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5070 g_clear_object (&priv->layout_manager);
5073 if (priv->content != NULL)
5075 _clutter_content_detached (priv->content, self);
5076 g_clear_object (&priv->content);
5079 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5083 clutter_actor_finalize (GObject *object)
5085 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5087 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5088 priv->name != NULL ? priv->name : "<none>",
5090 g_type_name (G_OBJECT_TYPE (object)));
5092 _clutter_context_release_id (priv->id);
5094 g_free (priv->name);
5096 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5101 * clutter_actor_get_accessible:
5102 * @self: a #ClutterActor
5104 * Returns the accessible object that describes the actor to an
5105 * assistive technology.
5107 * If no class-specific #AtkObject implementation is available for the
5108 * actor instance in question, it will inherit an #AtkObject
5109 * implementation from the first ancestor class for which such an
5110 * implementation is defined.
5112 * The documentation of the <ulink
5113 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5114 * library contains more information about accessible objects and
5117 * Returns: (transfer none): the #AtkObject associated with @actor
5120 clutter_actor_get_accessible (ClutterActor *self)
5122 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5124 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5128 clutter_actor_real_get_accessible (ClutterActor *actor)
5130 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5134 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5136 AtkObject *accessible;
5138 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5139 if (accessible != NULL)
5140 g_object_ref (accessible);
5146 atk_implementor_iface_init (AtkImplementorIface *iface)
5148 iface->ref_accessible = _clutter_actor_ref_accessible;
5152 clutter_actor_update_default_paint_volume (ClutterActor *self,
5153 ClutterPaintVolume *volume)
5155 ClutterActorPrivate *priv = self->priv;
5156 gboolean res = TRUE;
5158 /* we start from the allocation */
5159 clutter_paint_volume_set_width (volume,
5160 priv->allocation.x2 - priv->allocation.x1);
5161 clutter_paint_volume_set_height (volume,
5162 priv->allocation.y2 - priv->allocation.y1);
5164 /* if the actor has a clip set then we have a pretty definite
5165 * size for the paint volume: the actor cannot possibly paint
5166 * outside the clip region.
5168 if (priv->clip_to_allocation)
5170 /* the allocation has already been set, so we just flip the
5177 ClutterActor *child;
5179 if (priv->has_clip &&
5180 priv->clip.width >= 0 &&
5181 priv->clip.height >= 0)
5183 ClutterVertex origin;
5185 origin.x = priv->clip.x;
5186 origin.y = priv->clip.y;
5189 clutter_paint_volume_set_origin (volume, &origin);
5190 clutter_paint_volume_set_width (volume, priv->clip.width);
5191 clutter_paint_volume_set_height (volume, priv->clip.height);
5196 /* if we don't have children we just bail out here... */
5197 if (priv->n_children == 0)
5200 /* ...but if we have children then we ask for their paint volume in
5201 * our coordinates. if any of our children replies that it doesn't
5202 * have a paint volume, we bail out
5204 for (child = priv->first_child;
5206 child = child->priv->next_sibling)
5208 const ClutterPaintVolume *child_volume;
5210 if (!CLUTTER_ACTOR_IS_MAPPED (child))
5213 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5214 if (child_volume == NULL)
5220 clutter_paint_volume_union (volume, child_volume);
5230 clutter_actor_real_get_paint_volume (ClutterActor *self,
5231 ClutterPaintVolume *volume)
5233 ClutterActorClass *klass;
5236 klass = CLUTTER_ACTOR_GET_CLASS (self);
5238 /* XXX - this thoroughly sucks, but we don't want to penalize users
5239 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5240 * redraw. This should go away in 2.0.
5242 if (klass->paint == clutter_actor_real_paint &&
5243 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5249 /* this is the default return value: we cannot know if a class
5250 * is going to paint outside its allocation, so we take the
5251 * conservative approach.
5256 /* update_default_paint_volume() should only fail if one of the children
5257 * reported an invalid, or no, paint volume
5259 if (!clutter_actor_update_default_paint_volume (self, volume))
5266 * clutter_actor_get_default_paint_volume:
5267 * @self: a #ClutterActor
5269 * Retrieves the default paint volume for @self.
5271 * This function provides the same #ClutterPaintVolume that would be
5272 * computed by the default implementation inside #ClutterActor of the
5273 * #ClutterActorClass.get_paint_volume() virtual function.
5275 * This function should only be used by #ClutterActor subclasses that
5276 * cannot chain up to the parent implementation when computing their
5279 * Return value: (transfer none): a pointer to the default
5280 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5281 * the actor could not compute a valid paint volume. The returned value
5282 * is not guaranteed to be stable across multiple frames, so if you
5283 * want to retain it, you will need to copy it using
5284 * clutter_paint_volume_copy().
5288 const ClutterPaintVolume *
5289 clutter_actor_get_default_paint_volume (ClutterActor *self)
5291 ClutterPaintVolume volume;
5292 ClutterPaintVolume *res;
5294 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5297 _clutter_paint_volume_init_static (&volume, self);
5298 if (clutter_actor_update_default_paint_volume (self, &volume))
5300 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5304 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5305 _clutter_paint_volume_copy_static (&volume, res);
5309 clutter_paint_volume_free (&volume);
5315 clutter_actor_real_has_overlaps (ClutterActor *self)
5317 /* By default we'll assume that all actors need an offscreen redirect to get
5318 * the correct opacity. Actors such as ClutterTexture that would never need
5319 * an offscreen redirect can override this to return FALSE. */
5324 clutter_actor_real_destroy (ClutterActor *actor)
5326 ClutterActorIter iter;
5328 g_object_freeze_notify (G_OBJECT (actor));
5330 clutter_actor_iter_init (&iter, actor);
5331 while (clutter_actor_iter_next (&iter, NULL))
5332 clutter_actor_iter_destroy (&iter);
5334 g_object_thaw_notify (G_OBJECT (actor));
5338 clutter_actor_constructor (GType gtype,
5340 GObjectConstructParam *props)
5342 GObjectClass *gobject_class;
5346 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5347 retval = gobject_class->constructor (gtype, n_props, props);
5348 self = CLUTTER_ACTOR (retval);
5350 if (self->priv->layout_manager == NULL)
5352 ClutterLayoutManager *default_layout;
5354 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5356 default_layout = clutter_fixed_layout_new ();
5357 clutter_actor_set_layout_manager (self, default_layout);
5364 clutter_actor_class_init (ClutterActorClass *klass)
5366 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5368 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5369 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5370 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5371 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5373 object_class->constructor = clutter_actor_constructor;
5374 object_class->set_property = clutter_actor_set_property;
5375 object_class->get_property = clutter_actor_get_property;
5376 object_class->dispose = clutter_actor_dispose;
5377 object_class->finalize = clutter_actor_finalize;
5379 klass->show = clutter_actor_real_show;
5380 klass->show_all = clutter_actor_show;
5381 klass->hide = clutter_actor_real_hide;
5382 klass->hide_all = clutter_actor_hide;
5383 klass->map = clutter_actor_real_map;
5384 klass->unmap = clutter_actor_real_unmap;
5385 klass->unrealize = clutter_actor_real_unrealize;
5386 klass->pick = clutter_actor_real_pick;
5387 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5388 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5389 klass->allocate = clutter_actor_real_allocate;
5390 klass->queue_redraw = clutter_actor_real_queue_redraw;
5391 klass->queue_relayout = clutter_actor_real_queue_relayout;
5392 klass->apply_transform = clutter_actor_real_apply_transform;
5393 klass->get_accessible = clutter_actor_real_get_accessible;
5394 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5395 klass->has_overlaps = clutter_actor_real_has_overlaps;
5396 klass->paint = clutter_actor_real_paint;
5397 klass->destroy = clutter_actor_real_destroy;
5399 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5404 * X coordinate of the actor in pixels. If written, forces a fixed
5405 * position for the actor. If read, returns the fixed position if any,
5406 * otherwise the allocation if available, otherwise 0.
5408 * The #ClutterActor:x property is animatable.
5411 g_param_spec_float ("x",
5413 P_("X coordinate of the actor"),
5414 -G_MAXFLOAT, G_MAXFLOAT,
5417 G_PARAM_STATIC_STRINGS |
5418 CLUTTER_PARAM_ANIMATABLE);
5423 * Y coordinate of the actor in pixels. If written, forces a fixed
5424 * position for the actor. If read, returns the fixed position if
5425 * any, otherwise the allocation if available, otherwise 0.
5427 * The #ClutterActor:y property is animatable.
5430 g_param_spec_float ("y",
5432 P_("Y coordinate of the actor"),
5433 -G_MAXFLOAT, G_MAXFLOAT,
5436 G_PARAM_STATIC_STRINGS |
5437 CLUTTER_PARAM_ANIMATABLE);
5440 * ClutterActor:width:
5442 * Width of the actor (in pixels). If written, forces the minimum and
5443 * natural size request of the actor to the given width. If read, returns
5444 * the allocated width if available, otherwise the width request.
5446 * The #ClutterActor:width property is animatable.
5448 obj_props[PROP_WIDTH] =
5449 g_param_spec_float ("width",
5451 P_("Width of the actor"),
5455 G_PARAM_STATIC_STRINGS |
5456 CLUTTER_PARAM_ANIMATABLE);
5459 * ClutterActor:height:
5461 * Height of the actor (in pixels). If written, forces the minimum and
5462 * natural size request of the actor to the given height. If read, returns
5463 * the allocated height if available, otherwise the height request.
5465 * The #ClutterActor:height property is animatable.
5467 obj_props[PROP_HEIGHT] =
5468 g_param_spec_float ("height",
5470 P_("Height of the actor"),
5474 G_PARAM_STATIC_STRINGS |
5475 CLUTTER_PARAM_ANIMATABLE);
5478 * ClutterActor:fixed-x:
5480 * The fixed X position of the actor in pixels.
5482 * Writing this property sets #ClutterActor:fixed-position-set
5483 * property as well, as a side effect
5487 obj_props[PROP_FIXED_X] =
5488 g_param_spec_float ("fixed-x",
5490 P_("Forced X position of the actor"),
5491 -G_MAXFLOAT, G_MAXFLOAT,
5493 CLUTTER_PARAM_READWRITE);
5496 * ClutterActor:fixed-y:
5498 * The fixed Y position of the actor in pixels.
5500 * Writing this property sets the #ClutterActor:fixed-position-set
5501 * property as well, as a side effect
5505 obj_props[PROP_FIXED_Y] =
5506 g_param_spec_float ("fixed-y",
5508 P_("Forced Y position of the actor"),
5509 -G_MAXFLOAT, G_MAXFLOAT,
5511 CLUTTER_PARAM_READWRITE);
5514 * ClutterActor:fixed-position-set:
5516 * This flag controls whether the #ClutterActor:fixed-x and
5517 * #ClutterActor:fixed-y properties are used
5521 obj_props[PROP_FIXED_POSITION_SET] =
5522 g_param_spec_boolean ("fixed-position-set",
5523 P_("Fixed position set"),
5524 P_("Whether to use fixed positioning for the actor"),
5526 CLUTTER_PARAM_READWRITE);
5529 * ClutterActor:min-width:
5531 * A forced minimum width request for the actor, in pixels
5533 * Writing this property sets the #ClutterActor:min-width-set property
5534 * as well, as a side effect.
5536 *This property overrides the usual width request of the actor.
5540 obj_props[PROP_MIN_WIDTH] =
5541 g_param_spec_float ("min-width",
5543 P_("Forced minimum width request for the actor"),
5546 CLUTTER_PARAM_READWRITE);
5549 * ClutterActor:min-height:
5551 * A forced minimum height request for the actor, in pixels
5553 * Writing this property sets the #ClutterActor:min-height-set property
5554 * as well, as a side effect. This property overrides the usual height
5555 * request of the actor.
5559 obj_props[PROP_MIN_HEIGHT] =
5560 g_param_spec_float ("min-height",
5562 P_("Forced minimum height request for the actor"),
5565 CLUTTER_PARAM_READWRITE);
5568 * ClutterActor:natural-width:
5570 * A forced natural width request for the actor, in pixels
5572 * Writing this property sets the #ClutterActor:natural-width-set
5573 * property as well, as a side effect. This property overrides the
5574 * usual width request of the actor
5578 obj_props[PROP_NATURAL_WIDTH] =
5579 g_param_spec_float ("natural-width",
5580 P_("Natural Width"),
5581 P_("Forced natural width request for the actor"),
5584 CLUTTER_PARAM_READWRITE);
5587 * ClutterActor:natural-height:
5589 * A forced natural height request for the actor, in pixels
5591 * Writing this property sets the #ClutterActor:natural-height-set
5592 * property as well, as a side effect. This property overrides the
5593 * usual height request of the actor
5597 obj_props[PROP_NATURAL_HEIGHT] =
5598 g_param_spec_float ("natural-height",
5599 P_("Natural Height"),
5600 P_("Forced natural height request for the actor"),
5603 CLUTTER_PARAM_READWRITE);
5606 * ClutterActor:min-width-set:
5608 * This flag controls whether the #ClutterActor:min-width property
5613 obj_props[PROP_MIN_WIDTH_SET] =
5614 g_param_spec_boolean ("min-width-set",
5615 P_("Minimum width set"),
5616 P_("Whether to use the min-width property"),
5618 CLUTTER_PARAM_READWRITE);
5621 * ClutterActor:min-height-set:
5623 * This flag controls whether the #ClutterActor:min-height property
5628 obj_props[PROP_MIN_HEIGHT_SET] =
5629 g_param_spec_boolean ("min-height-set",
5630 P_("Minimum height set"),
5631 P_("Whether to use the min-height property"),
5633 CLUTTER_PARAM_READWRITE);
5636 * ClutterActor:natural-width-set:
5638 * This flag controls whether the #ClutterActor:natural-width property
5643 obj_props[PROP_NATURAL_WIDTH_SET] =
5644 g_param_spec_boolean ("natural-width-set",
5645 P_("Natural width set"),
5646 P_("Whether to use the natural-width property"),
5648 CLUTTER_PARAM_READWRITE);
5651 * ClutterActor:natural-height-set:
5653 * This flag controls whether the #ClutterActor:natural-height property
5658 obj_props[PROP_NATURAL_HEIGHT_SET] =
5659 g_param_spec_boolean ("natural-height-set",
5660 P_("Natural height set"),
5661 P_("Whether to use the natural-height property"),
5663 CLUTTER_PARAM_READWRITE);
5666 * ClutterActor:allocation:
5668 * The allocation for the actor, in pixels
5670 * This is property is read-only, but you might monitor it to know when an
5671 * actor moves or resizes
5675 obj_props[PROP_ALLOCATION] =
5676 g_param_spec_boxed ("allocation",
5678 P_("The actor's allocation"),
5679 CLUTTER_TYPE_ACTOR_BOX,
5680 CLUTTER_PARAM_READABLE);
5683 * ClutterActor:request-mode:
5685 * Request mode for the #ClutterActor. The request mode determines the
5686 * type of geometry management used by the actor, either height for width
5687 * (the default) or width for height.
5689 * For actors implementing height for width, the parent container should get
5690 * the preferred width first, and then the preferred height for that width.
5692 * For actors implementing width for height, the parent container should get
5693 * the preferred height first, and then the preferred width for that height.
5698 * ClutterRequestMode mode;
5699 * gfloat natural_width, min_width;
5700 * gfloat natural_height, min_height;
5702 * mode = clutter_actor_get_request_mode (child);
5703 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5705 * clutter_actor_get_preferred_width (child, -1,
5707 * &natural_width);
5708 * clutter_actor_get_preferred_height (child, natural_width,
5710 * &natural_height);
5714 * clutter_actor_get_preferred_height (child, -1,
5716 * &natural_height);
5717 * clutter_actor_get_preferred_width (child, natural_height,
5719 * &natural_width);
5723 * will retrieve the minimum and natural width and height depending on the
5724 * preferred request mode of the #ClutterActor "child".
5726 * The clutter_actor_get_preferred_size() function will implement this
5731 obj_props[PROP_REQUEST_MODE] =
5732 g_param_spec_enum ("request-mode",
5734 P_("The actor's request mode"),
5735 CLUTTER_TYPE_REQUEST_MODE,
5736 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5737 CLUTTER_PARAM_READWRITE);
5740 * ClutterActor:depth:
5742 * The position of the actor on the Z axis.
5744 * The #ClutterActor:depth property is relative to the parent's
5747 * The #ClutterActor:depth property is animatable.
5751 obj_props[PROP_DEPTH] =
5752 g_param_spec_float ("depth",
5754 P_("Position on the Z axis"),
5755 -G_MAXFLOAT, G_MAXFLOAT,
5758 G_PARAM_STATIC_STRINGS |
5759 CLUTTER_PARAM_ANIMATABLE);
5762 * ClutterActor:opacity:
5764 * Opacity of an actor, between 0 (fully transparent) and
5765 * 255 (fully opaque)
5767 * The #ClutterActor:opacity property is animatable.
5769 obj_props[PROP_OPACITY] =
5770 g_param_spec_uint ("opacity",
5772 P_("Opacity of an actor"),
5776 G_PARAM_STATIC_STRINGS |
5777 CLUTTER_PARAM_ANIMATABLE);
5780 * ClutterActor:offscreen-redirect:
5782 * Determines the conditions in which the actor will be redirected
5783 * to an offscreen framebuffer while being painted. For example this
5784 * can be used to cache an actor in a framebuffer or for improved
5785 * handling of transparent actors. See
5786 * clutter_actor_set_offscreen_redirect() for details.
5790 obj_props[PROP_OFFSCREEN_REDIRECT] =
5791 g_param_spec_flags ("offscreen-redirect",
5792 P_("Offscreen redirect"),
5793 P_("Flags controlling when to flatten the actor into a single image"),
5794 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5796 CLUTTER_PARAM_READWRITE);
5799 * ClutterActor:visible:
5801 * Whether the actor is set to be visible or not
5803 * See also #ClutterActor:mapped
5805 obj_props[PROP_VISIBLE] =
5806 g_param_spec_boolean ("visible",
5808 P_("Whether the actor is visible or not"),
5810 CLUTTER_PARAM_READWRITE);
5813 * ClutterActor:mapped:
5815 * Whether the actor is mapped (will be painted when the stage
5816 * to which it belongs is mapped)
5820 obj_props[PROP_MAPPED] =
5821 g_param_spec_boolean ("mapped",
5823 P_("Whether the actor will be painted"),
5825 CLUTTER_PARAM_READABLE);
5828 * ClutterActor:realized:
5830 * Whether the actor has been realized
5834 obj_props[PROP_REALIZED] =
5835 g_param_spec_boolean ("realized",
5837 P_("Whether the actor has been realized"),
5839 CLUTTER_PARAM_READABLE);
5842 * ClutterActor:reactive:
5844 * Whether the actor is reactive to events or not
5846 * Only reactive actors will emit event-related signals
5850 obj_props[PROP_REACTIVE] =
5851 g_param_spec_boolean ("reactive",
5853 P_("Whether the actor is reactive to events"),
5855 CLUTTER_PARAM_READWRITE);
5858 * ClutterActor:has-clip:
5860 * Whether the actor has the #ClutterActor:clip property set or not
5862 obj_props[PROP_HAS_CLIP] =
5863 g_param_spec_boolean ("has-clip",
5865 P_("Whether the actor has a clip set"),
5867 CLUTTER_PARAM_READABLE);
5870 * ClutterActor:clip:
5872 * The clip region for the actor, in actor-relative coordinates
5874 * Every part of the actor outside the clip region will not be
5877 obj_props[PROP_CLIP] =
5878 g_param_spec_boxed ("clip",
5880 P_("The clip region for the actor"),
5881 CLUTTER_TYPE_GEOMETRY,
5882 CLUTTER_PARAM_READWRITE);
5885 * ClutterActor:name:
5887 * The name of the actor
5891 obj_props[PROP_NAME] =
5892 g_param_spec_string ("name",
5894 P_("Name of the actor"),
5896 CLUTTER_PARAM_READWRITE);
5899 * ClutterActor:scale-x:
5901 * The horizontal scale of the actor.
5903 * The #ClutterActor:scale-x property is animatable.
5907 obj_props[PROP_SCALE_X] =
5908 g_param_spec_double ("scale-x",
5910 P_("Scale factor on the X axis"),
5914 G_PARAM_STATIC_STRINGS |
5915 CLUTTER_PARAM_ANIMATABLE);
5918 * ClutterActor:scale-y:
5920 * The vertical scale of the actor.
5922 * The #ClutterActor:scale-y property is animatable.
5926 obj_props[PROP_SCALE_Y] =
5927 g_param_spec_double ("scale-y",
5929 P_("Scale factor on the Y axis"),
5933 G_PARAM_STATIC_STRINGS |
5934 CLUTTER_PARAM_ANIMATABLE);
5937 * ClutterActor:scale-center-x:
5939 * The horizontal center point for scaling
5943 obj_props[PROP_SCALE_CENTER_X] =
5944 g_param_spec_float ("scale-center-x",
5945 P_("Scale Center X"),
5946 P_("Horizontal scale center"),
5947 -G_MAXFLOAT, G_MAXFLOAT,
5949 CLUTTER_PARAM_READWRITE);
5952 * ClutterActor:scale-center-y:
5954 * The vertical center point for scaling
5958 obj_props[PROP_SCALE_CENTER_Y] =
5959 g_param_spec_float ("scale-center-y",
5960 P_("Scale Center Y"),
5961 P_("Vertical scale center"),
5962 -G_MAXFLOAT, G_MAXFLOAT,
5964 CLUTTER_PARAM_READWRITE);
5967 * ClutterActor:scale-gravity:
5969 * The center point for scaling expressed as a #ClutterGravity
5973 obj_props[PROP_SCALE_GRAVITY] =
5974 g_param_spec_enum ("scale-gravity",
5975 P_("Scale Gravity"),
5976 P_("The center of scaling"),
5977 CLUTTER_TYPE_GRAVITY,
5978 CLUTTER_GRAVITY_NONE,
5979 CLUTTER_PARAM_READWRITE);
5982 * ClutterActor:rotation-angle-x:
5984 * The rotation angle on the X axis.
5986 * The #ClutterActor:rotation-angle-x property is animatable.
5990 obj_props[PROP_ROTATION_ANGLE_X] =
5991 g_param_spec_double ("rotation-angle-x",
5992 P_("Rotation Angle X"),
5993 P_("The rotation angle on the X axis"),
5994 -G_MAXDOUBLE, G_MAXDOUBLE,
5997 G_PARAM_STATIC_STRINGS |
5998 CLUTTER_PARAM_ANIMATABLE);
6001 * ClutterActor:rotation-angle-y:
6003 * The rotation angle on the Y axis
6005 * The #ClutterActor:rotation-angle-y property is animatable.
6009 obj_props[PROP_ROTATION_ANGLE_Y] =
6010 g_param_spec_double ("rotation-angle-y",
6011 P_("Rotation Angle Y"),
6012 P_("The rotation angle on the Y axis"),
6013 -G_MAXDOUBLE, G_MAXDOUBLE,
6016 G_PARAM_STATIC_STRINGS |
6017 CLUTTER_PARAM_ANIMATABLE);
6020 * ClutterActor:rotation-angle-z:
6022 * The rotation angle on the Z axis
6024 * The #ClutterActor:rotation-angle-z property is animatable.
6028 obj_props[PROP_ROTATION_ANGLE_Z] =
6029 g_param_spec_double ("rotation-angle-z",
6030 P_("Rotation Angle Z"),
6031 P_("The rotation angle on the Z axis"),
6032 -G_MAXDOUBLE, G_MAXDOUBLE,
6035 G_PARAM_STATIC_STRINGS |
6036 CLUTTER_PARAM_ANIMATABLE);
6039 * ClutterActor:rotation-center-x:
6041 * The rotation center on the X axis.
6045 obj_props[PROP_ROTATION_CENTER_X] =
6046 g_param_spec_boxed ("rotation-center-x",
6047 P_("Rotation Center X"),
6048 P_("The rotation center on the X axis"),
6049 CLUTTER_TYPE_VERTEX,
6050 CLUTTER_PARAM_READWRITE);
6053 * ClutterActor:rotation-center-y:
6055 * The rotation center on the Y axis.
6059 obj_props[PROP_ROTATION_CENTER_Y] =
6060 g_param_spec_boxed ("rotation-center-y",
6061 P_("Rotation Center Y"),
6062 P_("The rotation center on the Y axis"),
6063 CLUTTER_TYPE_VERTEX,
6064 CLUTTER_PARAM_READWRITE);
6067 * ClutterActor:rotation-center-z:
6069 * The rotation center on the Z axis.
6073 obj_props[PROP_ROTATION_CENTER_Z] =
6074 g_param_spec_boxed ("rotation-center-z",
6075 P_("Rotation Center Z"),
6076 P_("The rotation center on the Z axis"),
6077 CLUTTER_TYPE_VERTEX,
6078 CLUTTER_PARAM_READWRITE);
6081 * ClutterActor:rotation-center-z-gravity:
6083 * The rotation center on the Z axis expressed as a #ClutterGravity.
6087 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6088 g_param_spec_enum ("rotation-center-z-gravity",
6089 P_("Rotation Center Z Gravity"),
6090 P_("Center point for rotation around the Z axis"),
6091 CLUTTER_TYPE_GRAVITY,
6092 CLUTTER_GRAVITY_NONE,
6093 CLUTTER_PARAM_READWRITE);
6096 * ClutterActor:anchor-x:
6098 * The X coordinate of an actor's anchor point, relative to
6099 * the actor coordinate space, in pixels
6103 obj_props[PROP_ANCHOR_X] =
6104 g_param_spec_float ("anchor-x",
6106 P_("X coordinate of the anchor point"),
6107 -G_MAXFLOAT, G_MAXFLOAT,
6109 CLUTTER_PARAM_READWRITE);
6112 * ClutterActor:anchor-y:
6114 * The Y coordinate of an actor's anchor point, relative to
6115 * the actor coordinate space, in pixels
6119 obj_props[PROP_ANCHOR_Y] =
6120 g_param_spec_float ("anchor-y",
6122 P_("Y coordinate of the anchor point"),
6123 -G_MAXFLOAT, G_MAXFLOAT,
6125 CLUTTER_PARAM_READWRITE);
6128 * ClutterActor:anchor-gravity:
6130 * The anchor point expressed as a #ClutterGravity
6134 obj_props[PROP_ANCHOR_GRAVITY] =
6135 g_param_spec_enum ("anchor-gravity",
6136 P_("Anchor Gravity"),
6137 P_("The anchor point as a ClutterGravity"),
6138 CLUTTER_TYPE_GRAVITY,
6139 CLUTTER_GRAVITY_NONE,
6140 CLUTTER_PARAM_READWRITE);
6143 * ClutterActor:show-on-set-parent:
6145 * If %TRUE, the actor is automatically shown when parented.
6147 * Calling clutter_actor_hide() on an actor which has not been
6148 * parented will set this property to %FALSE as a side effect.
6152 obj_props[PROP_SHOW_ON_SET_PARENT] =
6153 g_param_spec_boolean ("show-on-set-parent",
6154 P_("Show on set parent"),
6155 P_("Whether the actor is shown when parented"),
6157 CLUTTER_PARAM_READWRITE);
6160 * ClutterActor:clip-to-allocation:
6162 * Whether the clip region should track the allocated area
6165 * This property is ignored if a clip area has been explicitly
6166 * set using clutter_actor_set_clip().
6170 obj_props[PROP_CLIP_TO_ALLOCATION] =
6171 g_param_spec_boolean ("clip-to-allocation",
6172 P_("Clip to Allocation"),
6173 P_("Sets the clip region to track the actor's allocation"),
6175 CLUTTER_PARAM_READWRITE);
6178 * ClutterActor:text-direction:
6180 * The direction of the text inside a #ClutterActor.
6184 obj_props[PROP_TEXT_DIRECTION] =
6185 g_param_spec_enum ("text-direction",
6186 P_("Text Direction"),
6187 P_("Direction of the text"),
6188 CLUTTER_TYPE_TEXT_DIRECTION,
6189 CLUTTER_TEXT_DIRECTION_LTR,
6190 CLUTTER_PARAM_READWRITE);
6193 * ClutterActor:has-pointer:
6195 * Whether the actor contains the pointer of a #ClutterInputDevice
6200 obj_props[PROP_HAS_POINTER] =
6201 g_param_spec_boolean ("has-pointer",
6203 P_("Whether the actor contains the pointer of an input device"),
6205 CLUTTER_PARAM_READABLE);
6208 * ClutterActor:actions:
6210 * Adds a #ClutterAction to the actor
6214 obj_props[PROP_ACTIONS] =
6215 g_param_spec_object ("actions",
6217 P_("Adds an action to the actor"),
6218 CLUTTER_TYPE_ACTION,
6219 CLUTTER_PARAM_WRITABLE);
6222 * ClutterActor:constraints:
6224 * Adds a #ClutterConstraint to the actor
6228 obj_props[PROP_CONSTRAINTS] =
6229 g_param_spec_object ("constraints",
6231 P_("Adds a constraint to the actor"),
6232 CLUTTER_TYPE_CONSTRAINT,
6233 CLUTTER_PARAM_WRITABLE);
6236 * ClutterActor:effect:
6238 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6242 obj_props[PROP_EFFECT] =
6243 g_param_spec_object ("effect",
6245 P_("Add an effect to be applied on the actor"),
6246 CLUTTER_TYPE_EFFECT,
6247 CLUTTER_PARAM_WRITABLE);
6250 * ClutterActor:layout-manager:
6252 * A delegate object for controlling the layout of the children of
6257 obj_props[PROP_LAYOUT_MANAGER] =
6258 g_param_spec_object ("layout-manager",
6259 P_("Layout Manager"),
6260 P_("The object controlling the layout of an actor's children"),
6261 CLUTTER_TYPE_LAYOUT_MANAGER,
6262 CLUTTER_PARAM_READWRITE);
6266 * ClutterActor:x-align:
6268 * The alignment of an actor on the X axis, if the actor has been given
6269 * extra space for its allocation.
6273 obj_props[PROP_X_ALIGN] =
6274 g_param_spec_enum ("x-align",
6276 P_("The alignment of the actor on the X axis within its allocation"),
6277 CLUTTER_TYPE_ACTOR_ALIGN,
6278 CLUTTER_ACTOR_ALIGN_FILL,
6279 CLUTTER_PARAM_READWRITE);
6282 * ClutterActor:y-align:
6284 * The alignment of an actor on the Y axis, if the actor has been given
6285 * extra space for its allocation.
6289 obj_props[PROP_Y_ALIGN] =
6290 g_param_spec_enum ("y-align",
6292 P_("The alignment of the actor on the Y axis within its allocation"),
6293 CLUTTER_TYPE_ACTOR_ALIGN,
6294 CLUTTER_ACTOR_ALIGN_FILL,
6295 CLUTTER_PARAM_READWRITE);
6298 * ClutterActor:margin-top:
6300 * The margin (in pixels) from the top of the actor.
6302 * This property adds a margin to the actor's preferred size; the margin
6303 * will be automatically taken into account when allocating the actor.
6307 obj_props[PROP_MARGIN_TOP] =
6308 g_param_spec_float ("margin-top",
6310 P_("Extra space at the top"),
6313 CLUTTER_PARAM_READWRITE);
6316 * ClutterActor:margin-bottom:
6318 * The margin (in pixels) from the bottom of the actor.
6320 * This property adds a margin to the actor's preferred size; the margin
6321 * will be automatically taken into account when allocating the actor.
6325 obj_props[PROP_MARGIN_BOTTOM] =
6326 g_param_spec_float ("margin-bottom",
6327 P_("Margin Bottom"),
6328 P_("Extra space at the bottom"),
6331 CLUTTER_PARAM_READWRITE);
6334 * ClutterActor:margin-left:
6336 * The margin (in pixels) from the left of the actor.
6338 * This property adds a margin to the actor's preferred size; the margin
6339 * will be automatically taken into account when allocating the actor.
6343 obj_props[PROP_MARGIN_LEFT] =
6344 g_param_spec_float ("margin-left",
6346 P_("Extra space at the left"),
6349 CLUTTER_PARAM_READWRITE);
6352 * ClutterActor:margin-right:
6354 * The margin (in pixels) from the right of the actor.
6356 * This property adds a margin to the actor's preferred size; the margin
6357 * will be automatically taken into account when allocating the actor.
6361 obj_props[PROP_MARGIN_RIGHT] =
6362 g_param_spec_float ("margin-right",
6364 P_("Extra space at the right"),
6367 CLUTTER_PARAM_READWRITE);
6370 * ClutterActor:background-color-set:
6372 * Whether the #ClutterActor:background-color property has been set.
6376 obj_props[PROP_BACKGROUND_COLOR_SET] =
6377 g_param_spec_boolean ("background-color-set",
6378 P_("Background Color Set"),
6379 P_("Whether the background color is set"),
6381 CLUTTER_PARAM_READABLE);
6384 * ClutterActor:background-color:
6386 * Paints a solid fill of the actor's allocation using the specified
6389 * The #ClutterActor:background-color property is animatable.
6393 obj_props[PROP_BACKGROUND_COLOR] =
6394 clutter_param_spec_color ("background-color",
6395 P_("Background color"),
6396 P_("The actor's background color"),
6397 CLUTTER_COLOR_Transparent,
6399 G_PARAM_STATIC_STRINGS |
6400 CLUTTER_PARAM_ANIMATABLE);
6403 * ClutterActor:first-child:
6405 * The actor's first child.
6409 obj_props[PROP_FIRST_CHILD] =
6410 g_param_spec_object ("first-child",
6412 P_("The actor's first child"),
6414 CLUTTER_PARAM_READABLE);
6417 * ClutterActor:last-child:
6419 * The actor's last child.
6423 obj_props[PROP_LAST_CHILD] =
6424 g_param_spec_object ("last-child",
6426 P_("The actor's last child"),
6428 CLUTTER_PARAM_READABLE);
6431 * ClutterActor:content:
6433 * The #ClutterContent implementation that controls the content
6438 obj_props[PROP_CONTENT] =
6439 g_param_spec_object ("content",
6441 P_("Delegate object for painting the actor's content"),
6442 CLUTTER_TYPE_CONTENT,
6443 CLUTTER_PARAM_READWRITE);
6446 * ClutterActor:content-gravity:
6448 * The alignment that should be honoured by the #ClutterContent
6449 * set with the #ClutterActor:content property.
6451 * Changing the value of this property will change the bounding box of
6452 * the content; you can use the #ClutterActor:content-box property to
6453 * get the position and size of the content within the actor's
6456 * This property is meaningful only for #ClutterContent implementations
6457 * that have a preferred size, and if the preferred size is smaller than
6458 * the actor's allocation.
6460 * The #ClutterActor:content-gravity property is animatable.
6464 obj_props[PROP_CONTENT_GRAVITY] =
6465 g_param_spec_enum ("content-gravity",
6466 P_("Content Gravity"),
6467 P_("Alignment of the actor's content"),
6468 CLUTTER_TYPE_CONTENT_GRAVITY,
6469 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6470 CLUTTER_PARAM_READWRITE);
6473 * ClutterActor:content-box:
6475 * The bounding box for the #ClutterContent used by the actor.
6477 * The value of this property is controlled by the #ClutterActor:allocation
6478 * and #ClutterActor:content-gravity properties of #ClutterActor.
6480 * The bounding box for the content is guaranteed to never exceed the
6481 * allocation's of the actor.
6485 obj_props[PROP_CONTENT_BOX] =
6486 g_param_spec_boxed ("content-box",
6488 P_("The bounding box of the actor's content"),
6489 CLUTTER_TYPE_ACTOR_BOX,
6491 G_PARAM_STATIC_STRINGS |
6492 CLUTTER_PARAM_ANIMATABLE);
6494 obj_props[PROP_MINIFICATION_FILTER] =
6495 g_param_spec_enum ("minification-filter",
6496 P_("Minification Filter"),
6497 P_("The filter used when reducing the size of the content"),
6498 CLUTTER_TYPE_SCALING_FILTER,
6499 CLUTTER_SCALING_FILTER_LINEAR,
6500 CLUTTER_PARAM_READWRITE);
6502 obj_props[PROP_MAGNIFICATION_FILTER] =
6503 g_param_spec_enum ("magnification-filter",
6504 P_("Magnification Filter"),
6505 P_("The filter used when increasing the size of the content"),
6506 CLUTTER_TYPE_SCALING_FILTER,
6507 CLUTTER_SCALING_FILTER_LINEAR,
6508 CLUTTER_PARAM_READWRITE);
6510 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6513 * ClutterActor::destroy:
6514 * @actor: the #ClutterActor which emitted the signal
6516 * The ::destroy signal notifies that all references held on the
6517 * actor which emitted it should be released.
6519 * The ::destroy signal should be used by all holders of a reference
6522 * This signal might result in the finalization of the #ClutterActor
6523 * if all references are released.
6525 * Composite actors and actors implementing the #ClutterContainer
6526 * interface should override the default implementation of the
6527 * class handler of this signal and call clutter_actor_destroy() on
6528 * their children. When overriding the default class handler, it is
6529 * required to chain up to the parent's implementation.
6533 actor_signals[DESTROY] =
6534 g_signal_new (I_("destroy"),
6535 G_TYPE_FROM_CLASS (object_class),
6536 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6537 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6539 _clutter_marshal_VOID__VOID,
6542 * ClutterActor::show:
6543 * @actor: the object which received the signal
6545 * The ::show signal is emitted when an actor is visible and
6546 * rendered on the stage.
6550 actor_signals[SHOW] =
6551 g_signal_new (I_("show"),
6552 G_TYPE_FROM_CLASS (object_class),
6554 G_STRUCT_OFFSET (ClutterActorClass, show),
6556 _clutter_marshal_VOID__VOID,
6559 * ClutterActor::hide:
6560 * @actor: the object which received the signal
6562 * The ::hide signal is emitted when an actor is no longer rendered
6567 actor_signals[HIDE] =
6568 g_signal_new (I_("hide"),
6569 G_TYPE_FROM_CLASS (object_class),
6571 G_STRUCT_OFFSET (ClutterActorClass, hide),
6573 _clutter_marshal_VOID__VOID,
6576 * ClutterActor::parent-set:
6577 * @actor: the object which received the signal
6578 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6580 * This signal is emitted when the parent of the actor changes.
6584 actor_signals[PARENT_SET] =
6585 g_signal_new (I_("parent-set"),
6586 G_TYPE_FROM_CLASS (object_class),
6588 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6590 _clutter_marshal_VOID__OBJECT,
6592 CLUTTER_TYPE_ACTOR);
6595 * ClutterActor::queue-redraw:
6596 * @actor: the actor we're bubbling the redraw request through
6597 * @origin: the actor which initiated the redraw request
6599 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6600 * is called on @origin.
6602 * The default implementation for #ClutterActor chains up to the
6603 * parent actor and queues a redraw on the parent, thus "bubbling"
6604 * the redraw queue up through the actor graph. The default
6605 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6606 * in a main loop idle handler.
6608 * Note that the @origin actor may be the stage, or a container; it
6609 * does not have to be a leaf node in the actor graph.
6611 * Toolkits embedding a #ClutterStage which require a redraw and
6612 * relayout cycle can stop the emission of this signal using the
6613 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6618 * on_redraw_complete (gpointer data)
6620 * ClutterStage *stage = data;
6622 * /* execute the Clutter drawing pipeline */
6623 * clutter_stage_ensure_redraw (stage);
6627 * on_stage_queue_redraw (ClutterStage *stage)
6629 * /* this prevents the default handler to run */
6630 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6632 * /* queue a redraw with the host toolkit and call
6633 * * a function when the redraw has been completed
6635 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6639 * <note><para>This signal is emitted before the Clutter paint
6640 * pipeline is executed. If you want to know when the pipeline has
6641 * been completed you should connect to the ::paint signal on the
6642 * Stage with g_signal_connect_after().</para></note>
6646 actor_signals[QUEUE_REDRAW] =
6647 g_signal_new (I_("queue-redraw"),
6648 G_TYPE_FROM_CLASS (object_class),
6651 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6653 _clutter_marshal_VOID__OBJECT,
6655 CLUTTER_TYPE_ACTOR);
6658 * ClutterActor::queue-relayout
6659 * @actor: the actor being queued for relayout
6661 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6662 * is called on an actor.
6664 * The default implementation for #ClutterActor chains up to the
6665 * parent actor and queues a relayout on the parent, thus "bubbling"
6666 * the relayout queue up through the actor graph.
6668 * The main purpose of this signal is to allow relayout to be propagated
6669 * properly in the procense of #ClutterClone actors. Applications will
6670 * not normally need to connect to this signal.
6674 actor_signals[QUEUE_RELAYOUT] =
6675 g_signal_new (I_("queue-relayout"),
6676 G_TYPE_FROM_CLASS (object_class),
6679 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6681 _clutter_marshal_VOID__VOID,
6685 * ClutterActor::event:
6686 * @actor: the actor which received the event
6687 * @event: a #ClutterEvent
6689 * The ::event signal is emitted each time an event is received
6690 * by the @actor. This signal will be emitted on every actor,
6691 * following the hierarchy chain, until it reaches the top-level
6692 * container (the #ClutterStage).
6694 * Return value: %TRUE if the event has been handled by the actor,
6695 * or %FALSE to continue the emission.
6699 actor_signals[EVENT] =
6700 g_signal_new (I_("event"),
6701 G_TYPE_FROM_CLASS (object_class),
6703 G_STRUCT_OFFSET (ClutterActorClass, event),
6704 _clutter_boolean_handled_accumulator, NULL,
6705 _clutter_marshal_BOOLEAN__BOXED,
6707 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6709 * ClutterActor::button-press-event:
6710 * @actor: the actor which received the event
6711 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6713 * The ::button-press-event signal is emitted each time a mouse button
6714 * is pressed on @actor.
6716 * Return value: %TRUE if the event has been handled by the actor,
6717 * or %FALSE to continue the emission.
6721 actor_signals[BUTTON_PRESS_EVENT] =
6722 g_signal_new (I_("button-press-event"),
6723 G_TYPE_FROM_CLASS (object_class),
6725 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6726 _clutter_boolean_handled_accumulator, NULL,
6727 _clutter_marshal_BOOLEAN__BOXED,
6729 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6731 * ClutterActor::button-release-event:
6732 * @actor: the actor which received the event
6733 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6735 * The ::button-release-event signal is emitted each time a mouse button
6736 * is released on @actor.
6738 * Return value: %TRUE if the event has been handled by the actor,
6739 * or %FALSE to continue the emission.
6743 actor_signals[BUTTON_RELEASE_EVENT] =
6744 g_signal_new (I_("button-release-event"),
6745 G_TYPE_FROM_CLASS (object_class),
6747 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6748 _clutter_boolean_handled_accumulator, NULL,
6749 _clutter_marshal_BOOLEAN__BOXED,
6751 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6753 * ClutterActor::scroll-event:
6754 * @actor: the actor which received the event
6755 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6757 * The ::scroll-event signal is emitted each time the mouse is
6758 * scrolled on @actor
6760 * Return value: %TRUE if the event has been handled by the actor,
6761 * or %FALSE to continue the emission.
6765 actor_signals[SCROLL_EVENT] =
6766 g_signal_new (I_("scroll-event"),
6767 G_TYPE_FROM_CLASS (object_class),
6769 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6770 _clutter_boolean_handled_accumulator, NULL,
6771 _clutter_marshal_BOOLEAN__BOXED,
6773 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6775 * ClutterActor::key-press-event:
6776 * @actor: the actor which received the event
6777 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6779 * The ::key-press-event signal is emitted each time a keyboard button
6780 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6782 * Return value: %TRUE if the event has been handled by the actor,
6783 * or %FALSE to continue the emission.
6787 actor_signals[KEY_PRESS_EVENT] =
6788 g_signal_new (I_("key-press-event"),
6789 G_TYPE_FROM_CLASS (object_class),
6791 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6792 _clutter_boolean_handled_accumulator, NULL,
6793 _clutter_marshal_BOOLEAN__BOXED,
6795 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6797 * ClutterActor::key-release-event:
6798 * @actor: the actor which received the event
6799 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6801 * The ::key-release-event signal is emitted each time a keyboard button
6802 * is released while @actor has key focus (see
6803 * clutter_stage_set_key_focus()).
6805 * Return value: %TRUE if the event has been handled by the actor,
6806 * or %FALSE to continue the emission.
6810 actor_signals[KEY_RELEASE_EVENT] =
6811 g_signal_new (I_("key-release-event"),
6812 G_TYPE_FROM_CLASS (object_class),
6814 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6815 _clutter_boolean_handled_accumulator, NULL,
6816 _clutter_marshal_BOOLEAN__BOXED,
6818 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6820 * ClutterActor::motion-event:
6821 * @actor: the actor which received the event
6822 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6824 * The ::motion-event signal is emitted each time the mouse pointer is
6825 * moved over @actor.
6827 * Return value: %TRUE if the event has been handled by the actor,
6828 * or %FALSE to continue the emission.
6832 actor_signals[MOTION_EVENT] =
6833 g_signal_new (I_("motion-event"),
6834 G_TYPE_FROM_CLASS (object_class),
6836 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6837 _clutter_boolean_handled_accumulator, NULL,
6838 _clutter_marshal_BOOLEAN__BOXED,
6840 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6843 * ClutterActor::key-focus-in:
6844 * @actor: the actor which now has key focus
6846 * The ::key-focus-in signal is emitted when @actor receives key focus.
6850 actor_signals[KEY_FOCUS_IN] =
6851 g_signal_new (I_("key-focus-in"),
6852 G_TYPE_FROM_CLASS (object_class),
6854 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6856 _clutter_marshal_VOID__VOID,
6860 * ClutterActor::key-focus-out:
6861 * @actor: the actor which now has key focus
6863 * The ::key-focus-out signal is emitted when @actor loses key focus.
6867 actor_signals[KEY_FOCUS_OUT] =
6868 g_signal_new (I_("key-focus-out"),
6869 G_TYPE_FROM_CLASS (object_class),
6871 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6873 _clutter_marshal_VOID__VOID,
6877 * ClutterActor::enter-event:
6878 * @actor: the actor which the pointer has entered.
6879 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6881 * The ::enter-event signal is emitted when the pointer enters the @actor
6883 * Return value: %TRUE if the event has been handled by the actor,
6884 * or %FALSE to continue the emission.
6888 actor_signals[ENTER_EVENT] =
6889 g_signal_new (I_("enter-event"),
6890 G_TYPE_FROM_CLASS (object_class),
6892 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6893 _clutter_boolean_handled_accumulator, NULL,
6894 _clutter_marshal_BOOLEAN__BOXED,
6896 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6899 * ClutterActor::leave-event:
6900 * @actor: the actor which the pointer has left
6901 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6903 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6905 * Return value: %TRUE if the event has been handled by the actor,
6906 * or %FALSE to continue the emission.
6910 actor_signals[LEAVE_EVENT] =
6911 g_signal_new (I_("leave-event"),
6912 G_TYPE_FROM_CLASS (object_class),
6914 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6915 _clutter_boolean_handled_accumulator, NULL,
6916 _clutter_marshal_BOOLEAN__BOXED,
6918 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6921 * ClutterActor::captured-event:
6922 * @actor: the actor which received the signal
6923 * @event: a #ClutterEvent
6925 * The ::captured-event signal is emitted when an event is captured
6926 * by Clutter. This signal will be emitted starting from the top-level
6927 * container (the #ClutterStage) to the actor which received the event
6928 * going down the hierarchy. This signal can be used to intercept every
6929 * event before the specialized events (like
6930 * ClutterActor::button-press-event or ::key-released-event) are
6933 * Return value: %TRUE if the event has been handled by the actor,
6934 * or %FALSE to continue the emission.
6938 actor_signals[CAPTURED_EVENT] =
6939 g_signal_new (I_("captured-event"),
6940 G_TYPE_FROM_CLASS (object_class),
6942 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6943 _clutter_boolean_handled_accumulator, NULL,
6944 _clutter_marshal_BOOLEAN__BOXED,
6946 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6949 * ClutterActor::paint:
6950 * @actor: the #ClutterActor that received the signal
6952 * The ::paint signal is emitted each time an actor is being painted.
6954 * Subclasses of #ClutterActor should override the class signal handler
6955 * and paint themselves in that function.
6957 * It is possible to connect a handler to the ::paint signal in order
6958 * to set up some custom aspect of a paint.
6962 actor_signals[PAINT] =
6963 g_signal_new (I_("paint"),
6964 G_TYPE_FROM_CLASS (object_class),
6967 G_STRUCT_OFFSET (ClutterActorClass, paint),
6969 _clutter_marshal_VOID__VOID,
6972 * ClutterActor::realize:
6973 * @actor: the #ClutterActor that received the signal
6975 * The ::realize signal is emitted each time an actor is being
6980 actor_signals[REALIZE] =
6981 g_signal_new (I_("realize"),
6982 G_TYPE_FROM_CLASS (object_class),
6984 G_STRUCT_OFFSET (ClutterActorClass, realize),
6986 _clutter_marshal_VOID__VOID,
6989 * ClutterActor::unrealize:
6990 * @actor: the #ClutterActor that received the signal
6992 * The ::unrealize signal is emitted each time an actor is being
6997 actor_signals[UNREALIZE] =
6998 g_signal_new (I_("unrealize"),
6999 G_TYPE_FROM_CLASS (object_class),
7001 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7003 _clutter_marshal_VOID__VOID,
7007 * ClutterActor::pick:
7008 * @actor: the #ClutterActor that received the signal
7009 * @color: the #ClutterColor to be used when picking
7011 * The ::pick signal is emitted each time an actor is being painted
7012 * in "pick mode". The pick mode is used to identify the actor during
7013 * the event handling phase, or by clutter_stage_get_actor_at_pos().
7014 * The actor should paint its shape using the passed @pick_color.
7016 * Subclasses of #ClutterActor should override the class signal handler
7017 * and paint themselves in that function.
7019 * It is possible to connect a handler to the ::pick signal in order
7020 * to set up some custom aspect of a paint in pick mode.
7024 actor_signals[PICK] =
7025 g_signal_new (I_("pick"),
7026 G_TYPE_FROM_CLASS (object_class),
7028 G_STRUCT_OFFSET (ClutterActorClass, pick),
7030 _clutter_marshal_VOID__BOXED,
7032 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7035 * ClutterActor::allocation-changed:
7036 * @actor: the #ClutterActor that emitted the signal
7037 * @box: a #ClutterActorBox with the new allocation
7038 * @flags: #ClutterAllocationFlags for the allocation
7040 * The ::allocation-changed signal is emitted when the
7041 * #ClutterActor:allocation property changes. Usually, application
7042 * code should just use the notifications for the :allocation property
7043 * but if you want to track the allocation flags as well, for instance
7044 * to know whether the absolute origin of @actor changed, then you might
7045 * want use this signal instead.
7049 actor_signals[ALLOCATION_CHANGED] =
7050 g_signal_new (I_("allocation-changed"),
7051 G_TYPE_FROM_CLASS (object_class),
7055 _clutter_marshal_VOID__BOXED_FLAGS,
7057 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7058 CLUTTER_TYPE_ALLOCATION_FLAGS);
7061 * ClutterActor::transitions-completed:
7062 * @actor: a #ClutterActor
7064 * The ::transitions-completed signal is emitted once all transitions
7065 * involving @actor are complete.
7069 actor_signals[TRANSITIONS_COMPLETED] =
7070 g_signal_new (I_("transitions-completed"),
7071 G_TYPE_FROM_CLASS (object_class),
7075 _clutter_marshal_VOID__VOID,
7080 clutter_actor_init (ClutterActor *self)
7082 ClutterActorPrivate *priv;
7084 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7086 priv->id = _clutter_context_acquire_id (self);
7089 priv->opacity = 0xff;
7090 priv->show_on_set_parent = TRUE;
7092 priv->needs_width_request = TRUE;
7093 priv->needs_height_request = TRUE;
7094 priv->needs_allocation = TRUE;
7096 priv->cached_width_age = 1;
7097 priv->cached_height_age = 1;
7099 priv->opacity_override = -1;
7100 priv->enable_model_view_transform = TRUE;
7102 /* Initialize an empty paint volume to start with */
7103 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7104 priv->last_paint_volume_valid = TRUE;
7106 priv->transform_valid = FALSE;
7108 /* the default is to stretch the content, to match the
7109 * current behaviour of basically all actors. also, it's
7110 * the easiest thing to compute.
7112 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7113 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7114 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7118 * clutter_actor_new:
7120 * Creates a new #ClutterActor.
7122 * A newly created actor has a floating reference, which will be sunk
7123 * when it is added to another actor.
7125 * Return value: (transfer full): the newly created #ClutterActor
7130 clutter_actor_new (void)
7132 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7136 * clutter_actor_destroy:
7137 * @self: a #ClutterActor
7139 * Destroys an actor. When an actor is destroyed, it will break any
7140 * references it holds to other objects. If the actor is inside a
7141 * container, the actor will be removed.
7143 * When you destroy a container, its children will be destroyed as well.
7145 * Note: you cannot destroy the #ClutterStage returned by
7146 * clutter_stage_get_default().
7149 clutter_actor_destroy (ClutterActor *self)
7151 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7153 g_object_ref (self);
7155 /* avoid recursion while destroying */
7156 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7158 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7160 g_object_run_dispose (G_OBJECT (self));
7162 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7165 g_object_unref (self);
7169 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7170 ClutterPaintVolume *clip)
7172 ClutterActorPrivate *priv = self->priv;
7173 ClutterPaintVolume *pv;
7176 /* Remove queue entry early in the process, otherwise a new
7177 queue_redraw() during signal handling could put back this
7178 object in the stage redraw list (but the entry is freed as
7179 soon as we return from this function, causing a segfault
7182 priv->queue_redraw_entry = NULL;
7184 /* If we've been explicitly passed a clip volume then there's
7185 * nothing more to calculate, but otherwise the only thing we know
7186 * is that the change is constrained to the given actor.
7188 * The idea is that if we know the paint volume for where the actor
7189 * was last drawn (in eye coordinates) and we also have the paint
7190 * volume for where it will be drawn next (in actor coordinates)
7191 * then if we queue a redraw for both these volumes that will cover
7192 * everything that needs to be redrawn to clear the old view and
7193 * show the latest view of the actor.
7195 * Don't clip this redraw if we don't know what position we had for
7196 * the previous redraw since we don't know where to set the clip so
7197 * it will clear the actor as it is currently.
7201 _clutter_actor_set_queue_redraw_clip (self, clip);
7204 else if (G_LIKELY (priv->last_paint_volume_valid))
7206 pv = _clutter_actor_get_paint_volume_mutable (self);
7209 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7211 /* make sure we redraw the actors old position... */
7212 _clutter_actor_set_queue_redraw_clip (stage,
7213 &priv->last_paint_volume);
7214 _clutter_actor_signal_queue_redraw (stage, stage);
7215 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7217 /* XXX: Ideally the redraw signal would take a clip volume
7218 * argument, but that would be an ABI break. Until we can
7219 * break the ABI we pass the argument out-of-band
7222 /* setup the clip for the actors new position... */
7223 _clutter_actor_set_queue_redraw_clip (self, pv);
7232 _clutter_actor_signal_queue_redraw (self, self);
7234 /* Just in case anyone is manually firing redraw signals without
7235 * using the public queue_redraw() API we are careful to ensure that
7236 * our out-of-band clip member is cleared before returning...
7238 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7240 if (G_LIKELY (clipped))
7241 _clutter_actor_set_queue_redraw_clip (self, NULL);
7245 _clutter_actor_get_allocation_clip (ClutterActor *self,
7246 ClutterActorBox *clip)
7248 ClutterActorBox allocation;
7250 /* XXX: we don't care if we get an out of date allocation here
7251 * because clutter_actor_queue_redraw_with_clip knows to ignore
7252 * the clip if the actor's allocation is invalid.
7254 * This is noted because clutter_actor_get_allocation_box does some
7255 * unnecessary work to support buggy code with a comment suggesting
7256 * that it could be changed later which would be good for this use
7259 clutter_actor_get_allocation_box (self, &allocation);
7261 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7262 * actor's own coordinate space but the allocation is in parent
7266 clip->x2 = allocation.x2 - allocation.x1;
7267 clip->y2 = allocation.y2 - allocation.y1;
7271 _clutter_actor_queue_redraw_full (ClutterActor *self,
7272 ClutterRedrawFlags flags,
7273 ClutterPaintVolume *volume,
7274 ClutterEffect *effect)
7276 ClutterActorPrivate *priv = self->priv;
7277 ClutterPaintVolume allocation_pv;
7278 ClutterPaintVolume *pv;
7279 gboolean should_free_pv;
7280 ClutterActor *stage;
7282 /* Here's an outline of the actor queue redraw mechanism:
7284 * The process starts in one of the following two functions which
7285 * are wrappers for this function:
7286 * clutter_actor_queue_redraw
7287 * _clutter_actor_queue_redraw_with_clip
7289 * additionally, an effect can queue a redraw by wrapping this
7290 * function in clutter_effect_queue_rerun
7292 * This functions queues an entry in a list associated with the
7293 * stage which is a list of actors that queued a redraw while
7294 * updating the timelines, performing layouting and processing other
7295 * mainloop sources before the next paint starts.
7297 * We aim to minimize the processing done at this point because
7298 * there is a good chance other events will happen while updating
7299 * the scenegraph that would invalidate any expensive work we might
7300 * otherwise try to do here. For example we don't try and resolve
7301 * the screen space bounding box of an actor at this stage so as to
7302 * minimize how much of the screen redraw because it's possible
7303 * something else will happen which will force a full redraw anyway.
7305 * When all updates are complete and we come to paint the stage then
7306 * we iterate this list and actually emit the "queue-redraw" signals
7307 * for each of the listed actors which will bubble up to the stage
7308 * for each actor and at that point we will transform the actors
7309 * paint volume into screen coordinates to determine the clip region
7310 * for what needs to be redrawn in the next paint.
7312 * Besides minimizing redundant work another reason for this
7313 * deferred design is that it's more likely we will be able to
7314 * determine the paint volume of an actor once we've finished
7315 * updating the scenegraph because its allocation should be up to
7316 * date. NB: If we can't determine an actors paint volume then we
7317 * can't automatically queue a clipped redraw which can make a big
7318 * difference to performance.
7320 * So the control flow goes like this:
7321 * One of clutter_actor_queue_redraw,
7322 * _clutter_actor_queue_redraw_with_clip
7323 * or clutter_effect_queue_rerun
7325 * then control moves to:
7326 * _clutter_stage_queue_actor_redraw
7328 * later during _clutter_stage_do_update, once relayouting is done
7329 * and the scenegraph has been updated we will call:
7330 * _clutter_stage_finish_queue_redraws
7332 * _clutter_stage_finish_queue_redraws will call
7333 * _clutter_actor_finish_queue_redraw for each listed actor.
7334 * Note: actors *are* allowed to queue further redraws during this
7335 * process (considering clone actors or texture_new_from_actor which
7336 * respond to their source queueing a redraw by queuing a redraw
7337 * themselves). We repeat the process until the list is empty.
7339 * This will result in the "queue-redraw" signal being fired for
7340 * each actor which will pass control to the default signal handler:
7341 * clutter_actor_real_queue_redraw
7343 * This will bubble up to the stages handler:
7344 * clutter_stage_real_queue_redraw
7346 * clutter_stage_real_queue_redraw will transform the actors paint
7347 * volume into screen space and add it as a clip region for the next
7351 /* ignore queueing a redraw for actors being destroyed */
7352 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7355 stage = _clutter_actor_get_stage_internal (self);
7357 /* Ignore queueing a redraw for actors not descended from a stage */
7361 /* ignore queueing a redraw on stages that are being destroyed */
7362 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7365 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7367 ClutterActorBox allocation_clip;
7368 ClutterVertex origin;
7370 /* If the actor doesn't have a valid allocation then we will
7371 * queue a full stage redraw. */
7372 if (priv->needs_allocation)
7374 /* NB: NULL denotes an undefined clip which will result in a
7376 _clutter_actor_set_queue_redraw_clip (self, NULL);
7377 _clutter_actor_signal_queue_redraw (self, self);
7381 _clutter_paint_volume_init_static (&allocation_pv, self);
7382 pv = &allocation_pv;
7384 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7386 origin.x = allocation_clip.x1;
7387 origin.y = allocation_clip.y1;
7389 clutter_paint_volume_set_origin (pv, &origin);
7390 clutter_paint_volume_set_width (pv,
7391 allocation_clip.x2 - allocation_clip.x1);
7392 clutter_paint_volume_set_height (pv,
7393 allocation_clip.y2 -
7394 allocation_clip.y1);
7395 should_free_pv = TRUE;
7400 should_free_pv = FALSE;
7403 self->priv->queue_redraw_entry =
7404 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7405 priv->queue_redraw_entry,
7410 clutter_paint_volume_free (pv);
7412 /* If this is the first redraw queued then we can directly use the
7414 if (!priv->is_dirty)
7415 priv->effect_to_redraw = effect;
7416 /* Otherwise we need to merge it with the existing effect parameter */
7417 else if (effect != NULL)
7419 /* If there's already an effect then we need to use whichever is
7420 later in the chain of actors. Otherwise a full redraw has
7421 already been queued on the actor so we need to ignore the
7423 if (priv->effect_to_redraw != NULL)
7425 if (priv->effects == NULL)
7426 g_warning ("Redraw queued with an effect that is "
7427 "not applied to the actor");
7432 for (l = _clutter_meta_group_peek_metas (priv->effects);
7436 if (l->data == priv->effect_to_redraw ||
7438 priv->effect_to_redraw = l->data;
7445 /* If no effect is specified then we need to redraw the whole
7447 priv->effect_to_redraw = NULL;
7450 priv->is_dirty = TRUE;
7454 * clutter_actor_queue_redraw:
7455 * @self: A #ClutterActor
7457 * Queues up a redraw of an actor and any children. The redraw occurs
7458 * once the main loop becomes idle (after the current batch of events
7459 * has been processed, roughly).
7461 * Applications rarely need to call this, as redraws are handled
7462 * automatically by modification functions.
7464 * This function will not do anything if @self is not visible, or
7465 * if the actor is inside an invisible part of the scenegraph.
7467 * Also be aware that painting is a NOP for actors with an opacity of
7470 * When you are implementing a custom actor you must queue a redraw
7471 * whenever some private state changes that will affect painting or
7472 * picking of your actor.
7475 clutter_actor_queue_redraw (ClutterActor *self)
7477 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7479 _clutter_actor_queue_redraw_full (self,
7481 NULL, /* clip volume */
7486 * _clutter_actor_queue_redraw_with_clip:
7487 * @self: A #ClutterActor
7488 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7489 * this queue redraw.
7490 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7491 * redrawn or %NULL if you are just using a @flag to state your
7494 * Queues up a clipped redraw of an actor and any children. The redraw
7495 * occurs once the main loop becomes idle (after the current batch of
7496 * events has been processed, roughly).
7498 * If no flags are given the clip volume is defined by @volume
7499 * specified in actor coordinates and tells Clutter that only content
7500 * within this volume has been changed so Clutter can optionally
7501 * optimize the redraw.
7503 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7504 * should be %NULL and this tells Clutter to use the actor's current
7505 * allocation as a clip box. This flag can only be used for 2D actors,
7506 * because any actor with depth may be projected outside its
7509 * Applications rarely need to call this, as redraws are handled
7510 * automatically by modification functions.
7512 * This function will not do anything if @self is not visible, or if
7513 * the actor is inside an invisible part of the scenegraph.
7515 * Also be aware that painting is a NOP for actors with an opacity of
7518 * When you are implementing a custom actor you must queue a redraw
7519 * whenever some private state changes that will affect painting or
7520 * picking of your actor.
7523 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7524 ClutterRedrawFlags flags,
7525 ClutterPaintVolume *volume)
7527 _clutter_actor_queue_redraw_full (self,
7529 volume, /* clip volume */
7534 _clutter_actor_queue_only_relayout (ClutterActor *self)
7536 ClutterActorPrivate *priv = self->priv;
7538 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7541 if (priv->needs_width_request &&
7542 priv->needs_height_request &&
7543 priv->needs_allocation)
7544 return; /* save some cpu cycles */
7546 #if CLUTTER_ENABLE_DEBUG
7547 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7549 g_warning ("The actor '%s' is currently inside an allocation "
7550 "cycle; calling clutter_actor_queue_relayout() is "
7552 _clutter_actor_get_debug_name (self));
7554 #endif /* CLUTTER_ENABLE_DEBUG */
7556 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7560 * clutter_actor_queue_redraw_with_clip:
7561 * @self: a #ClutterActor
7562 * @clip: (allow-none): a rectangular clip region, or %NULL
7564 * Queues a redraw on @self limited to a specific, actor-relative
7567 * If @clip is %NULL this function is equivalent to
7568 * clutter_actor_queue_redraw().
7573 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7574 const cairo_rectangle_int_t *clip)
7576 ClutterPaintVolume volume;
7577 ClutterVertex origin;
7579 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7583 clutter_actor_queue_redraw (self);
7587 _clutter_paint_volume_init_static (&volume, self);
7593 clutter_paint_volume_set_origin (&volume, &origin);
7594 clutter_paint_volume_set_width (&volume, clip->width);
7595 clutter_paint_volume_set_height (&volume, clip->height);
7597 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7599 clutter_paint_volume_free (&volume);
7603 * clutter_actor_queue_relayout:
7604 * @self: A #ClutterActor
7606 * Indicates that the actor's size request or other layout-affecting
7607 * properties may have changed. This function is used inside #ClutterActor
7608 * subclass implementations, not by applications directly.
7610 * Queueing a new layout automatically queues a redraw as well.
7615 clutter_actor_queue_relayout (ClutterActor *self)
7617 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7619 _clutter_actor_queue_only_relayout (self);
7620 clutter_actor_queue_redraw (self);
7624 * clutter_actor_get_preferred_size:
7625 * @self: a #ClutterActor
7626 * @min_width_p: (out) (allow-none): return location for the minimum
7628 * @min_height_p: (out) (allow-none): return location for the minimum
7630 * @natural_width_p: (out) (allow-none): return location for the natural
7632 * @natural_height_p: (out) (allow-none): return location for the natural
7635 * Computes the preferred minimum and natural size of an actor, taking into
7636 * account the actor's geometry management (either height-for-width
7637 * or width-for-height).
7639 * The width and height used to compute the preferred height and preferred
7640 * width are the actor's natural ones.
7642 * If you need to control the height for the preferred width, or the width for
7643 * the preferred height, you should use clutter_actor_get_preferred_width()
7644 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7645 * geometry management using the #ClutterActor:request-mode property.
7650 clutter_actor_get_preferred_size (ClutterActor *self,
7651 gfloat *min_width_p,
7652 gfloat *min_height_p,
7653 gfloat *natural_width_p,
7654 gfloat *natural_height_p)
7656 ClutterActorPrivate *priv;
7657 gfloat min_width, min_height;
7658 gfloat natural_width, natural_height;
7660 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7664 min_width = min_height = 0;
7665 natural_width = natural_height = 0;
7667 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7669 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7670 clutter_actor_get_preferred_width (self, -1,
7673 clutter_actor_get_preferred_height (self, natural_width,
7679 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7680 clutter_actor_get_preferred_height (self, -1,
7683 clutter_actor_get_preferred_width (self, natural_height,
7689 *min_width_p = min_width;
7692 *min_height_p = min_height;
7694 if (natural_width_p)
7695 *natural_width_p = natural_width;
7697 if (natural_height_p)
7698 *natural_height_p = natural_height;
7703 * @align: a #ClutterActorAlign
7704 * @direction: a #ClutterTextDirection
7706 * Retrieves the correct alignment depending on the text direction
7708 * Return value: the effective alignment
7710 static ClutterActorAlign
7711 effective_align (ClutterActorAlign align,
7712 ClutterTextDirection direction)
7714 ClutterActorAlign res;
7718 case CLUTTER_ACTOR_ALIGN_START:
7719 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7720 ? CLUTTER_ACTOR_ALIGN_END
7721 : CLUTTER_ACTOR_ALIGN_START;
7724 case CLUTTER_ACTOR_ALIGN_END:
7725 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7726 ? CLUTTER_ACTOR_ALIGN_START
7727 : CLUTTER_ACTOR_ALIGN_END;
7739 adjust_for_margin (float margin_start,
7741 float *minimum_size,
7742 float *natural_size,
7743 float *allocated_start,
7744 float *allocated_end)
7746 *minimum_size -= (margin_start + margin_end);
7747 *natural_size -= (margin_start + margin_end);
7748 *allocated_start += margin_start;
7749 *allocated_end -= margin_end;
7753 adjust_for_alignment (ClutterActorAlign alignment,
7755 float *allocated_start,
7756 float *allocated_end)
7758 float allocated_size = *allocated_end - *allocated_start;
7762 case CLUTTER_ACTOR_ALIGN_FILL:
7766 case CLUTTER_ACTOR_ALIGN_START:
7768 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7771 case CLUTTER_ACTOR_ALIGN_END:
7772 if (allocated_size > natural_size)
7774 *allocated_start += (allocated_size - natural_size);
7775 *allocated_end = *allocated_start + natural_size;
7779 case CLUTTER_ACTOR_ALIGN_CENTER:
7780 if (allocated_size > natural_size)
7782 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7783 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7790 * clutter_actor_adjust_width:
7791 * @self: a #ClutterActor
7792 * @minimum_width: (inout): the actor's preferred minimum width, which
7793 * will be adjusted depending on the margin
7794 * @natural_width: (inout): the actor's preferred natural width, which
7795 * will be adjusted depending on the margin
7796 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7797 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7799 * Adjusts the preferred and allocated position and size of an actor,
7800 * depending on the margin and alignment properties.
7803 clutter_actor_adjust_width (ClutterActor *self,
7804 gfloat *minimum_width,
7805 gfloat *natural_width,
7806 gfloat *adjusted_x1,
7807 gfloat *adjusted_x2)
7809 ClutterTextDirection text_dir;
7810 const ClutterLayoutInfo *info;
7812 info = _clutter_actor_get_layout_info_or_defaults (self);
7813 text_dir = clutter_actor_get_text_direction (self);
7815 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7817 /* this will tweak natural_width to remove the margin, so that
7818 * adjust_for_alignment() will use the correct size
7820 adjust_for_margin (info->margin.left, info->margin.right,
7821 minimum_width, natural_width,
7822 adjusted_x1, adjusted_x2);
7824 adjust_for_alignment (effective_align (info->x_align, text_dir),
7826 adjusted_x1, adjusted_x2);
7830 * clutter_actor_adjust_height:
7831 * @self: a #ClutterActor
7832 * @minimum_height: (inout): the actor's preferred minimum height, which
7833 * will be adjusted depending on the margin
7834 * @natural_height: (inout): the actor's preferred natural height, which
7835 * will be adjusted depending on the margin
7836 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7837 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7839 * Adjusts the preferred and allocated position and size of an actor,
7840 * depending on the margin and alignment properties.
7843 clutter_actor_adjust_height (ClutterActor *self,
7844 gfloat *minimum_height,
7845 gfloat *natural_height,
7846 gfloat *adjusted_y1,
7847 gfloat *adjusted_y2)
7849 const ClutterLayoutInfo *info;
7851 info = _clutter_actor_get_layout_info_or_defaults (self);
7853 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7855 /* this will tweak natural_height to remove the margin, so that
7856 * adjust_for_alignment() will use the correct size
7858 adjust_for_margin (info->margin.top, info->margin.bottom,
7859 minimum_height, natural_height,
7863 /* we don't use effective_align() here, because text direction
7864 * only affects the horizontal axis
7866 adjust_for_alignment (info->y_align,
7873 /* looks for a cached size request for this for_size. If not
7874 * found, returns the oldest entry so it can be overwritten */
7876 _clutter_actor_get_cached_size_request (gfloat for_size,
7877 SizeRequest *cached_size_requests,
7878 SizeRequest **result)
7882 *result = &cached_size_requests[0];
7884 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7888 sr = &cached_size_requests[i];
7891 sr->for_size == for_size)
7893 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7897 else if (sr->age < (*result)->age)
7903 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7909 * clutter_actor_get_preferred_width:
7910 * @self: A #ClutterActor
7911 * @for_height: available height when computing the preferred width,
7912 * or a negative value to indicate that no height is defined
7913 * @min_width_p: (out) (allow-none): return location for minimum width,
7915 * @natural_width_p: (out) (allow-none): return location for the natural
7918 * Computes the requested minimum and natural widths for an actor,
7919 * optionally depending on the specified height, or if they are
7920 * already computed, returns the cached values.
7922 * An actor may not get its request - depending on the layout
7923 * manager that's in effect.
7925 * A request should not incorporate the actor's scale or anchor point;
7926 * those transformations do not affect layout, only rendering.
7931 clutter_actor_get_preferred_width (ClutterActor *self,
7933 gfloat *min_width_p,
7934 gfloat *natural_width_p)
7936 float request_min_width, request_natural_width;
7937 SizeRequest *cached_size_request;
7938 const ClutterLayoutInfo *info;
7939 ClutterActorPrivate *priv;
7940 gboolean found_in_cache;
7942 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7946 info = _clutter_actor_get_layout_info_or_defaults (self);
7948 /* we shortcircuit the case of a fixed size set using set_width() */
7949 if (priv->min_width_set && priv->natural_width_set)
7951 if (min_width_p != NULL)
7952 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7954 if (natural_width_p != NULL)
7955 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7960 /* the remaining cases are:
7962 * - either min_width or natural_width have been set
7963 * - neither min_width or natural_width have been set
7965 * in both cases, we go through the cache (and through the actor in case
7966 * of cache misses) and determine the authoritative value depending on
7970 if (!priv->needs_width_request)
7973 _clutter_actor_get_cached_size_request (for_height,
7974 priv->width_requests,
7975 &cached_size_request);
7979 /* if the actor needs a width request we use the first slot */
7980 found_in_cache = FALSE;
7981 cached_size_request = &priv->width_requests[0];
7984 if (!found_in_cache)
7986 gfloat minimum_width, natural_width;
7987 ClutterActorClass *klass;
7989 minimum_width = natural_width = 0;
7991 /* adjust for the margin */
7992 if (for_height >= 0)
7994 for_height -= (info->margin.top + info->margin.bottom);
7999 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8001 klass = CLUTTER_ACTOR_GET_CLASS (self);
8002 klass->get_preferred_width (self, for_height,
8006 /* adjust for the margin */
8007 minimum_width += (info->margin.left + info->margin.right);
8008 natural_width += (info->margin.left + info->margin.right);
8010 /* Due to accumulated float errors, it's better not to warn
8011 * on this, but just fix it.
8013 if (natural_width < minimum_width)
8014 natural_width = minimum_width;
8016 cached_size_request->min_size = minimum_width;
8017 cached_size_request->natural_size = natural_width;
8018 cached_size_request->for_size = for_height;
8019 cached_size_request->age = priv->cached_width_age;
8021 priv->cached_width_age += 1;
8022 priv->needs_width_request = FALSE;
8025 if (!priv->min_width_set)
8026 request_min_width = cached_size_request->min_size;
8028 request_min_width = info->min_width;
8030 if (!priv->natural_width_set)
8031 request_natural_width = cached_size_request->natural_size;
8033 request_natural_width = info->natural_width;
8036 *min_width_p = request_min_width;
8038 if (natural_width_p)
8039 *natural_width_p = request_natural_width;
8043 * clutter_actor_get_preferred_height:
8044 * @self: A #ClutterActor
8045 * @for_width: available width to assume in computing desired height,
8046 * or a negative value to indicate that no width is defined
8047 * @min_height_p: (out) (allow-none): return location for minimum height,
8049 * @natural_height_p: (out) (allow-none): return location for natural
8052 * Computes the requested minimum and natural heights for an actor,
8053 * or if they are already computed, returns the cached values.
8055 * An actor may not get its request - depending on the layout
8056 * manager that's in effect.
8058 * A request should not incorporate the actor's scale or anchor point;
8059 * those transformations do not affect layout, only rendering.
8064 clutter_actor_get_preferred_height (ClutterActor *self,
8066 gfloat *min_height_p,
8067 gfloat *natural_height_p)
8069 float request_min_height, request_natural_height;
8070 SizeRequest *cached_size_request;
8071 const ClutterLayoutInfo *info;
8072 ClutterActorPrivate *priv;
8073 gboolean found_in_cache;
8075 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8079 info = _clutter_actor_get_layout_info_or_defaults (self);
8081 /* we shortcircuit the case of a fixed size set using set_height() */
8082 if (priv->min_height_set && priv->natural_height_set)
8084 if (min_height_p != NULL)
8085 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8087 if (natural_height_p != NULL)
8088 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8093 /* the remaining cases are:
8095 * - either min_height or natural_height have been set
8096 * - neither min_height or natural_height have been set
8098 * in both cases, we go through the cache (and through the actor in case
8099 * of cache misses) and determine the authoritative value depending on
8103 if (!priv->needs_height_request)
8106 _clutter_actor_get_cached_size_request (for_width,
8107 priv->height_requests,
8108 &cached_size_request);
8112 found_in_cache = FALSE;
8113 cached_size_request = &priv->height_requests[0];
8116 if (!found_in_cache)
8118 gfloat minimum_height, natural_height;
8119 ClutterActorClass *klass;
8121 minimum_height = natural_height = 0;
8123 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8125 /* adjust for margin */
8128 for_width -= (info->margin.left + info->margin.right);
8133 klass = CLUTTER_ACTOR_GET_CLASS (self);
8134 klass->get_preferred_height (self, for_width,
8138 /* adjust for margin */
8139 minimum_height += (info->margin.top + info->margin.bottom);
8140 natural_height += (info->margin.top + info->margin.bottom);
8142 /* Due to accumulated float errors, it's better not to warn
8143 * on this, but just fix it.
8145 if (natural_height < minimum_height)
8146 natural_height = minimum_height;
8148 cached_size_request->min_size = minimum_height;
8149 cached_size_request->natural_size = natural_height;
8150 cached_size_request->for_size = for_width;
8151 cached_size_request->age = priv->cached_height_age;
8153 priv->cached_height_age += 1;
8154 priv->needs_height_request = FALSE;
8157 if (!priv->min_height_set)
8158 request_min_height = cached_size_request->min_size;
8160 request_min_height = info->min_height;
8162 if (!priv->natural_height_set)
8163 request_natural_height = cached_size_request->natural_size;
8165 request_natural_height = info->natural_height;
8168 *min_height_p = request_min_height;
8170 if (natural_height_p)
8171 *natural_height_p = request_natural_height;
8175 * clutter_actor_get_allocation_box:
8176 * @self: A #ClutterActor
8177 * @box: (out): the function fills this in with the actor's allocation
8179 * Gets the layout box an actor has been assigned. The allocation can
8180 * only be assumed valid inside a paint() method; anywhere else, it
8181 * may be out-of-date.
8183 * An allocation does not incorporate the actor's scale or anchor point;
8184 * those transformations do not affect layout, only rendering.
8186 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8187 * of functions inside the implementation of the get_preferred_width()
8188 * or get_preferred_height() virtual functions.</note>
8193 clutter_actor_get_allocation_box (ClutterActor *self,
8194 ClutterActorBox *box)
8196 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8198 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8199 * which limits calling get_allocation to inside paint() basically; or
8200 * we can 2) force a layout, which could be expensive if someone calls
8201 * get_allocation somewhere silly; or we can 3) just return the latest
8202 * value, allowing it to be out-of-date, and assume people know what
8205 * The least-surprises approach that keeps existing code working is
8206 * likely to be 2). People can end up doing some inefficient things,
8207 * though, and in general code that requires 2) is probably broken.
8210 /* this implements 2) */
8211 if (G_UNLIKELY (self->priv->needs_allocation))
8213 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8215 /* do not queue a relayout on an unparented actor */
8217 _clutter_stage_maybe_relayout (stage);
8220 /* commenting out the code above and just keeping this assigment
8223 *box = self->priv->allocation;
8227 * clutter_actor_get_allocation_geometry:
8228 * @self: A #ClutterActor
8229 * @geom: (out): allocation geometry in pixels
8231 * Gets the layout box an actor has been assigned. The allocation can
8232 * only be assumed valid inside a paint() method; anywhere else, it
8233 * may be out-of-date.
8235 * An allocation does not incorporate the actor's scale or anchor point;
8236 * those transformations do not affect layout, only rendering.
8238 * The returned rectangle is in pixels.
8243 clutter_actor_get_allocation_geometry (ClutterActor *self,
8244 ClutterGeometry *geom)
8246 ClutterActorBox box;
8248 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8249 g_return_if_fail (geom != NULL);
8251 clutter_actor_get_allocation_box (self, &box);
8253 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8254 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8255 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8256 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8260 clutter_actor_update_constraints (ClutterActor *self,
8261 ClutterActorBox *allocation)
8263 ClutterActorPrivate *priv = self->priv;
8264 const GList *constraints, *l;
8266 if (priv->constraints == NULL)
8269 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8270 for (l = constraints; l != NULL; l = l->next)
8272 ClutterConstraint *constraint = l->data;
8273 ClutterActorMeta *meta = l->data;
8275 if (clutter_actor_meta_get_enabled (meta))
8277 _clutter_constraint_update_allocation (constraint,
8281 CLUTTER_NOTE (LAYOUT,
8282 "Allocation of '%s' after constraint '%s': "
8283 "{ %.2f, %.2f, %.2f, %.2f }",
8284 _clutter_actor_get_debug_name (self),
8285 _clutter_actor_meta_get_debug_name (meta),
8295 * clutter_actor_adjust_allocation:
8296 * @self: a #ClutterActor
8297 * @allocation: (inout): the allocation to adjust
8299 * Adjusts the passed allocation box taking into account the actor's
8300 * layout information, like alignment, expansion, and margin.
8303 clutter_actor_adjust_allocation (ClutterActor *self,
8304 ClutterActorBox *allocation)
8306 ClutterActorBox adj_allocation;
8307 float alloc_width, alloc_height;
8308 float min_width, min_height;
8309 float nat_width, nat_height;
8310 ClutterRequestMode req_mode;
8312 adj_allocation = *allocation;
8314 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8316 /* we want to hit the cache, so we use the public API */
8317 req_mode = clutter_actor_get_request_mode (self);
8319 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8321 clutter_actor_get_preferred_width (self, -1,
8324 clutter_actor_get_preferred_height (self, alloc_width,
8328 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8330 clutter_actor_get_preferred_height (self, -1,
8333 clutter_actor_get_preferred_height (self, alloc_height,
8338 #ifdef CLUTTER_ENABLE_DEBUG
8339 /* warn about underallocations */
8340 if (_clutter_diagnostic_enabled () &&
8341 (floorf (min_width - alloc_width) > 0 ||
8342 floorf (min_height - alloc_height) > 0))
8344 ClutterActor *parent = clutter_actor_get_parent (self);
8346 /* the only actors that are allowed to be underallocated are the Stage,
8347 * as it doesn't have an implicit size, and Actors that specifically
8348 * told us that they want to opt-out from layout control mechanisms
8349 * through the NO_LAYOUT escape hatch.
8351 if (parent != NULL &&
8352 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8354 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8355 "of %.2f x %.2f from its parent actor '%s', but its "
8356 "requested minimum size is of %.2f x %.2f",
8357 _clutter_actor_get_debug_name (self),
8358 alloc_width, alloc_height,
8359 _clutter_actor_get_debug_name (parent),
8360 min_width, min_height);
8365 clutter_actor_adjust_width (self,
8369 &adj_allocation.x2);
8371 clutter_actor_adjust_height (self,
8375 &adj_allocation.y2);
8377 /* we maintain the invariant that an allocation cannot be adjusted
8378 * to be outside the parent-given box
8380 if (adj_allocation.x1 < allocation->x1 ||
8381 adj_allocation.y1 < allocation->y1 ||
8382 adj_allocation.x2 > allocation->x2 ||
8383 adj_allocation.y2 > allocation->y2)
8385 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8386 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8387 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8388 _clutter_actor_get_debug_name (self),
8389 adj_allocation.x1, adj_allocation.y1,
8390 adj_allocation.x2 - adj_allocation.x1,
8391 adj_allocation.y2 - adj_allocation.y1,
8392 allocation->x1, allocation->y1,
8393 allocation->x2 - allocation->x1,
8394 allocation->y2 - allocation->y1);
8398 *allocation = adj_allocation;
8402 * clutter_actor_allocate:
8403 * @self: A #ClutterActor
8404 * @box: new allocation of the actor, in parent-relative coordinates
8405 * @flags: flags that control the allocation
8407 * Called by the parent of an actor to assign the actor its size.
8408 * Should never be called by applications (except when implementing
8409 * a container or layout manager).
8411 * Actors can know from their allocation box whether they have moved
8412 * with respect to their parent actor. The @flags parameter describes
8413 * additional information about the allocation, for instance whether
8414 * the parent has moved with respect to the stage, for example because
8415 * a grandparent's origin has moved.
8420 clutter_actor_allocate (ClutterActor *self,
8421 const ClutterActorBox *box,
8422 ClutterAllocationFlags flags)
8424 ClutterActorPrivate *priv;
8425 ClutterActorClass *klass;
8426 ClutterActorBox old_allocation, real_allocation;
8427 gboolean origin_changed, child_moved, size_changed;
8428 gboolean stage_allocation_changed;
8430 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8431 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8433 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8434 "which isn't a descendent of the stage!\n",
8435 self, _clutter_actor_get_debug_name (self));
8441 old_allocation = priv->allocation;
8442 real_allocation = *box;
8444 /* constraints are allowed to modify the allocation only here; we do
8445 * this prior to all the other checks so that we can bail out if the
8446 * allocation did not change
8448 clutter_actor_update_constraints (self, &real_allocation);
8450 /* adjust the allocation depending on the align/margin properties */
8451 clutter_actor_adjust_allocation (self, &real_allocation);
8453 if (real_allocation.x2 < real_allocation.x1 ||
8454 real_allocation.y2 < real_allocation.y1)
8456 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8457 _clutter_actor_get_debug_name (self),
8458 real_allocation.x2 - real_allocation.x1,
8459 real_allocation.y2 - real_allocation.y1);
8462 /* we allow 0-sized actors, but not negative-sized ones */
8463 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8464 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8466 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8468 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8469 real_allocation.y1 != old_allocation.y1);
8471 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8472 real_allocation.y2 != old_allocation.y2);
8474 if (origin_changed || child_moved || size_changed)
8475 stage_allocation_changed = TRUE;
8477 stage_allocation_changed = FALSE;
8479 /* If we get an allocation "out of the blue"
8480 * (we did not queue relayout), then we want to
8481 * ignore it. But if we have needs_allocation set,
8482 * we want to guarantee that allocate() virtual
8483 * method is always called, i.e. that queue_relayout()
8484 * always results in an allocate() invocation on
8487 * The optimization here is to avoid re-allocating
8488 * actors that did not queue relayout and were
8491 if (!priv->needs_allocation && !stage_allocation_changed)
8493 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8497 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8498 * clutter_actor_allocate(), it indicates whether the parent has its
8499 * absolute origin moved; when passed in to ClutterActor::allocate()
8500 * virtual method though, it indicates whether the child has its
8501 * absolute origin moved. So we set it when child_moved is TRUE
8504 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8506 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8508 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8509 _clutter_actor_get_debug_name (self));
8511 klass = CLUTTER_ACTOR_GET_CLASS (self);
8512 klass->allocate (self, &real_allocation, flags);
8514 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8516 if (stage_allocation_changed)
8517 clutter_actor_queue_redraw (self);
8521 * clutter_actor_set_allocation:
8522 * @self: a #ClutterActor
8523 * @box: a #ClutterActorBox
8524 * @flags: allocation flags
8526 * Stores the allocation of @self as defined by @box.
8528 * This function can only be called from within the implementation of
8529 * the #ClutterActorClass.allocate() virtual function.
8531 * The allocation should have been adjusted to take into account constraints,
8532 * alignment, and margin properties. If you are implementing a #ClutterActor
8533 * subclass that provides its own layout management policy for its children
8534 * instead of using a #ClutterLayoutManager delegate, you should not call
8535 * this function on the children of @self; instead, you should call
8536 * clutter_actor_allocate(), which will adjust the allocation box for
8539 * This function should only be used by subclasses of #ClutterActor
8540 * that wish to store their allocation but cannot chain up to the
8541 * parent's implementation; the default implementation of the
8542 * #ClutterActorClass.allocate() virtual function will call this
8545 * It is important to note that, while chaining up was the recommended
8546 * behaviour for #ClutterActor subclasses prior to the introduction of
8547 * this function, it is recommended to call clutter_actor_set_allocation()
8550 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8551 * to handle the allocation of its children, this function will call
8552 * the clutter_layout_manager_allocate() function only if the
8553 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8554 * expected that the subclass will call clutter_layout_manager_allocate()
8555 * by itself. For instance, the following code:
8559 * my_actor_allocate (ClutterActor *actor,
8560 * const ClutterActorBox *allocation,
8561 * ClutterAllocationFlags flags)
8563 * ClutterActorBox new_alloc;
8564 * ClutterAllocationFlags new_flags;
8566 * adjust_allocation (allocation, &new_alloc);
8568 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8570 * /* this will use the layout manager set on the actor */
8571 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8575 * is equivalent to this:
8579 * my_actor_allocate (ClutterActor *actor,
8580 * const ClutterActorBox *allocation,
8581 * ClutterAllocationFlags flags)
8583 * ClutterLayoutManager *layout;
8584 * ClutterActorBox new_alloc;
8586 * adjust_allocation (allocation, &new_alloc);
8588 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8590 * layout = clutter_actor_get_layout_manager (actor);
8591 * clutter_layout_manager_allocate (layout,
8592 * CLUTTER_CONTAINER (actor),
8601 clutter_actor_set_allocation (ClutterActor *self,
8602 const ClutterActorBox *box,
8603 ClutterAllocationFlags flags)
8605 ClutterActorPrivate *priv;
8608 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8609 g_return_if_fail (box != NULL);
8611 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8613 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8614 "can only be called from within the implementation of "
8615 "the ClutterActor::allocate() virtual function.");
8621 g_object_freeze_notify (G_OBJECT (self));
8623 changed = clutter_actor_set_allocation_internal (self, box, flags);
8625 /* we allocate our children before we notify changes in our geometry,
8626 * so that people connecting to properties will be able to get valid
8627 * data out of the sub-tree of the scene graph that has this actor at
8630 clutter_actor_maybe_layout_children (self, box, flags);
8634 ClutterActorBox signal_box = priv->allocation;
8635 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8637 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8642 g_object_thaw_notify (G_OBJECT (self));
8646 * clutter_actor_set_geometry:
8647 * @self: A #ClutterActor
8648 * @geometry: A #ClutterGeometry
8650 * Sets the actor's fixed position and forces its minimum and natural
8651 * size, in pixels. This means the untransformed actor will have the
8652 * given geometry. This is the same as calling clutter_actor_set_position()
8653 * and clutter_actor_set_size().
8655 * Deprecated: 1.10: Use clutter_actor_set_position() and
8656 * clutter_actor_set_size() instead.
8659 clutter_actor_set_geometry (ClutterActor *self,
8660 const ClutterGeometry *geometry)
8662 g_object_freeze_notify (G_OBJECT (self));
8664 clutter_actor_set_position (self, geometry->x, geometry->y);
8665 clutter_actor_set_size (self, geometry->width, geometry->height);
8667 g_object_thaw_notify (G_OBJECT (self));
8671 * clutter_actor_get_geometry:
8672 * @self: A #ClutterActor
8673 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8675 * Gets the size and position of an actor relative to its parent
8676 * actor. This is the same as calling clutter_actor_get_position() and
8677 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8678 * requested size and position if the actor's allocation is invalid.
8680 * Deprecated: 1.10: Use clutter_actor_get_position() and
8681 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8685 clutter_actor_get_geometry (ClutterActor *self,
8686 ClutterGeometry *geometry)
8688 gfloat x, y, width, height;
8690 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8691 g_return_if_fail (geometry != NULL);
8693 clutter_actor_get_position (self, &x, &y);
8694 clutter_actor_get_size (self, &width, &height);
8696 geometry->x = (int) x;
8697 geometry->y = (int) y;
8698 geometry->width = (int) width;
8699 geometry->height = (int) height;
8703 * clutter_actor_set_position:
8704 * @self: A #ClutterActor
8705 * @x: New left position of actor in pixels.
8706 * @y: New top position of actor in pixels.
8708 * Sets the actor's fixed position in pixels relative to any parent
8711 * If a layout manager is in use, this position will override the
8712 * layout manager and force a fixed position.
8715 clutter_actor_set_position (ClutterActor *self,
8719 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8721 g_object_freeze_notify (G_OBJECT (self));
8723 clutter_actor_set_x (self, x);
8724 clutter_actor_set_y (self, y);
8726 g_object_thaw_notify (G_OBJECT (self));
8730 * clutter_actor_get_fixed_position_set:
8731 * @self: A #ClutterActor
8733 * Checks whether an actor has a fixed position set (and will thus be
8734 * unaffected by any layout manager).
8736 * Return value: %TRUE if the fixed position is set on the actor
8741 clutter_actor_get_fixed_position_set (ClutterActor *self)
8743 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8745 return self->priv->position_set;
8749 * clutter_actor_set_fixed_position_set:
8750 * @self: A #ClutterActor
8751 * @is_set: whether to use fixed position
8753 * Sets whether an actor has a fixed position set (and will thus be
8754 * unaffected by any layout manager).
8759 clutter_actor_set_fixed_position_set (ClutterActor *self,
8762 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8764 if (self->priv->position_set == (is_set != FALSE))
8767 self->priv->position_set = is_set != FALSE;
8768 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8770 clutter_actor_queue_relayout (self);
8774 * clutter_actor_move_by:
8775 * @self: A #ClutterActor
8776 * @dx: Distance to move Actor on X axis.
8777 * @dy: Distance to move Actor on Y axis.
8779 * Moves an actor by the specified distance relative to its current
8780 * position in pixels.
8782 * This function modifies the fixed position of an actor and thus removes
8783 * it from any layout management. Another way to move an actor is with an
8784 * anchor point, see clutter_actor_set_anchor_point().
8789 clutter_actor_move_by (ClutterActor *self,
8793 const ClutterLayoutInfo *info;
8796 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8798 info = _clutter_actor_get_layout_info_or_defaults (self);
8802 clutter_actor_set_position (self, x + dx, y + dy);
8806 clutter_actor_set_min_width (ClutterActor *self,
8809 ClutterActorPrivate *priv = self->priv;
8810 ClutterActorBox old = { 0, };
8811 ClutterLayoutInfo *info;
8813 /* if we are setting the size on a top-level actor and the
8814 * backend only supports static top-levels (e.g. framebuffers)
8815 * then we ignore the passed value and we override it with
8816 * the stage implementation's preferred size.
8818 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8819 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8822 info = _clutter_actor_get_layout_info (self);
8824 if (priv->min_width_set && min_width == info->min_width)
8827 g_object_freeze_notify (G_OBJECT (self));
8829 clutter_actor_store_old_geometry (self, &old);
8831 info->min_width = min_width;
8832 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8833 clutter_actor_set_min_width_set (self, TRUE);
8835 clutter_actor_notify_if_geometry_changed (self, &old);
8837 g_object_thaw_notify (G_OBJECT (self));
8839 clutter_actor_queue_relayout (self);
8843 clutter_actor_set_min_height (ClutterActor *self,
8847 ClutterActorPrivate *priv = self->priv;
8848 ClutterActorBox old = { 0, };
8849 ClutterLayoutInfo *info;
8851 /* if we are setting the size on a top-level actor and the
8852 * backend only supports static top-levels (e.g. framebuffers)
8853 * then we ignore the passed value and we override it with
8854 * the stage implementation's preferred size.
8856 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8857 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8860 info = _clutter_actor_get_layout_info (self);
8862 if (priv->min_height_set && min_height == info->min_height)
8865 g_object_freeze_notify (G_OBJECT (self));
8867 clutter_actor_store_old_geometry (self, &old);
8869 info->min_height = min_height;
8870 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8871 clutter_actor_set_min_height_set (self, TRUE);
8873 clutter_actor_notify_if_geometry_changed (self, &old);
8875 g_object_thaw_notify (G_OBJECT (self));
8877 clutter_actor_queue_relayout (self);
8881 clutter_actor_set_natural_width (ClutterActor *self,
8882 gfloat natural_width)
8884 ClutterActorPrivate *priv = self->priv;
8885 ClutterActorBox old = { 0, };
8886 ClutterLayoutInfo *info;
8888 /* if we are setting the size on a top-level actor and the
8889 * backend only supports static top-levels (e.g. framebuffers)
8890 * then we ignore the passed value and we override it with
8891 * the stage implementation's preferred size.
8893 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8894 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8897 info = _clutter_actor_get_layout_info (self);
8899 if (priv->natural_width_set && natural_width == info->natural_width)
8902 g_object_freeze_notify (G_OBJECT (self));
8904 clutter_actor_store_old_geometry (self, &old);
8906 info->natural_width = natural_width;
8907 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8908 clutter_actor_set_natural_width_set (self, TRUE);
8910 clutter_actor_notify_if_geometry_changed (self, &old);
8912 g_object_thaw_notify (G_OBJECT (self));
8914 clutter_actor_queue_relayout (self);
8918 clutter_actor_set_natural_height (ClutterActor *self,
8919 gfloat natural_height)
8921 ClutterActorPrivate *priv = self->priv;
8922 ClutterActorBox old = { 0, };
8923 ClutterLayoutInfo *info;
8925 /* if we are setting the size on a top-level actor and the
8926 * backend only supports static top-levels (e.g. framebuffers)
8927 * then we ignore the passed value and we override it with
8928 * the stage implementation's preferred size.
8930 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8931 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8934 info = _clutter_actor_get_layout_info (self);
8936 if (priv->natural_height_set && natural_height == info->natural_height)
8939 g_object_freeze_notify (G_OBJECT (self));
8941 clutter_actor_store_old_geometry (self, &old);
8943 info->natural_height = natural_height;
8944 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8945 clutter_actor_set_natural_height_set (self, TRUE);
8947 clutter_actor_notify_if_geometry_changed (self, &old);
8949 g_object_thaw_notify (G_OBJECT (self));
8951 clutter_actor_queue_relayout (self);
8955 clutter_actor_set_min_width_set (ClutterActor *self,
8956 gboolean use_min_width)
8958 ClutterActorPrivate *priv = self->priv;
8959 ClutterActorBox old = { 0, };
8961 if (priv->min_width_set == (use_min_width != FALSE))
8964 clutter_actor_store_old_geometry (self, &old);
8966 priv->min_width_set = use_min_width != FALSE;
8967 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8969 clutter_actor_notify_if_geometry_changed (self, &old);
8971 clutter_actor_queue_relayout (self);
8975 clutter_actor_set_min_height_set (ClutterActor *self,
8976 gboolean use_min_height)
8978 ClutterActorPrivate *priv = self->priv;
8979 ClutterActorBox old = { 0, };
8981 if (priv->min_height_set == (use_min_height != FALSE))
8984 clutter_actor_store_old_geometry (self, &old);
8986 priv->min_height_set = use_min_height != FALSE;
8987 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8989 clutter_actor_notify_if_geometry_changed (self, &old);
8991 clutter_actor_queue_relayout (self);
8995 clutter_actor_set_natural_width_set (ClutterActor *self,
8996 gboolean use_natural_width)
8998 ClutterActorPrivate *priv = self->priv;
8999 ClutterActorBox old = { 0, };
9001 if (priv->natural_width_set == (use_natural_width != FALSE))
9004 clutter_actor_store_old_geometry (self, &old);
9006 priv->natural_width_set = use_natural_width != FALSE;
9007 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9009 clutter_actor_notify_if_geometry_changed (self, &old);
9011 clutter_actor_queue_relayout (self);
9015 clutter_actor_set_natural_height_set (ClutterActor *self,
9016 gboolean use_natural_height)
9018 ClutterActorPrivate *priv = self->priv;
9019 ClutterActorBox old = { 0, };
9021 if (priv->natural_height_set == (use_natural_height != FALSE))
9024 clutter_actor_store_old_geometry (self, &old);
9026 priv->natural_height_set = use_natural_height != FALSE;
9027 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9029 clutter_actor_notify_if_geometry_changed (self, &old);
9031 clutter_actor_queue_relayout (self);
9035 * clutter_actor_set_request_mode:
9036 * @self: a #ClutterActor
9037 * @mode: the request mode
9039 * Sets the geometry request mode of @self.
9041 * The @mode determines the order for invoking
9042 * clutter_actor_get_preferred_width() and
9043 * clutter_actor_get_preferred_height()
9048 clutter_actor_set_request_mode (ClutterActor *self,
9049 ClutterRequestMode mode)
9051 ClutterActorPrivate *priv;
9053 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9057 if (priv->request_mode == mode)
9060 priv->request_mode = mode;
9062 priv->needs_width_request = TRUE;
9063 priv->needs_height_request = TRUE;
9065 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9067 clutter_actor_queue_relayout (self);
9071 * clutter_actor_get_request_mode:
9072 * @self: a #ClutterActor
9074 * Retrieves the geometry request mode of @self
9076 * Return value: the request mode for the actor
9081 clutter_actor_get_request_mode (ClutterActor *self)
9083 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9084 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9086 return self->priv->request_mode;
9089 /* variant of set_width() without checks and without notification
9090 * freeze+thaw, for internal usage only
9093 clutter_actor_set_width_internal (ClutterActor *self,
9098 /* the Stage will use the :min-width to control the minimum
9099 * width to be resized to, so we should not be setting it
9100 * along with the :natural-width
9102 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9103 clutter_actor_set_min_width (self, width);
9105 clutter_actor_set_natural_width (self, width);
9109 /* we only unset the :natural-width for the Stage */
9110 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9111 clutter_actor_set_min_width_set (self, FALSE);
9113 clutter_actor_set_natural_width_set (self, FALSE);
9117 /* variant of set_height() without checks and without notification
9118 * freeze+thaw, for internal usage only
9121 clutter_actor_set_height_internal (ClutterActor *self,
9126 /* see the comment above in set_width_internal() */
9127 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9128 clutter_actor_set_min_height (self, height);
9130 clutter_actor_set_natural_height (self, height);
9134 /* see the comment above in set_width_internal() */
9135 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9136 clutter_actor_set_min_height_set (self, FALSE);
9138 clutter_actor_set_natural_height_set (self, FALSE);
9143 * clutter_actor_set_size:
9144 * @self: A #ClutterActor
9145 * @width: New width of actor in pixels, or -1
9146 * @height: New height of actor in pixels, or -1
9148 * Sets the actor's size request in pixels. This overrides any
9149 * "normal" size request the actor would have. For example
9150 * a text actor might normally request the size of the text;
9151 * this function would force a specific size instead.
9153 * If @width and/or @height are -1 the actor will use its
9154 * "normal" size request instead of overriding it, i.e.
9155 * you can "unset" the size with -1.
9157 * This function sets or unsets both the minimum and natural size.
9160 clutter_actor_set_size (ClutterActor *self,
9164 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9166 g_object_freeze_notify (G_OBJECT (self));
9168 clutter_actor_set_width (self, width);
9169 clutter_actor_set_height (self, height);
9171 g_object_thaw_notify (G_OBJECT (self));
9175 * clutter_actor_get_size:
9176 * @self: A #ClutterActor
9177 * @width: (out) (allow-none): return location for the width, or %NULL.
9178 * @height: (out) (allow-none): return location for the height, or %NULL.
9180 * This function tries to "do what you mean" and return
9181 * the size an actor will have. If the actor has a valid
9182 * allocation, the allocation will be returned; otherwise,
9183 * the actors natural size request will be returned.
9185 * If you care whether you get the request vs. the allocation, you
9186 * should probably call a different function like
9187 * clutter_actor_get_allocation_box() or
9188 * clutter_actor_get_preferred_width().
9193 clutter_actor_get_size (ClutterActor *self,
9197 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9200 *width = clutter_actor_get_width (self);
9203 *height = clutter_actor_get_height (self);
9207 * clutter_actor_get_position:
9208 * @self: a #ClutterActor
9209 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9210 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9212 * This function tries to "do what you mean" and tell you where the
9213 * actor is, prior to any transformations. Retrieves the fixed
9214 * position of an actor in pixels, if one has been set; otherwise, if
9215 * the allocation is valid, returns the actor's allocated position;
9216 * otherwise, returns 0,0.
9218 * The returned position is in pixels.
9223 clutter_actor_get_position (ClutterActor *self,
9227 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9230 *x = clutter_actor_get_x (self);
9233 *y = clutter_actor_get_y (self);
9237 * clutter_actor_get_transformed_position:
9238 * @self: A #ClutterActor
9239 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9240 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9242 * Gets the absolute position of an actor, in pixels relative to the stage.
9247 clutter_actor_get_transformed_position (ClutterActor *self,
9254 v1.x = v1.y = v1.z = 0;
9255 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9265 * clutter_actor_get_transformed_size:
9266 * @self: A #ClutterActor
9267 * @width: (out) (allow-none): return location for the width, or %NULL
9268 * @height: (out) (allow-none): return location for the height, or %NULL
9270 * Gets the absolute size of an actor in pixels, taking into account the
9273 * If the actor has a valid allocation, the allocated size will be used.
9274 * If the actor has not a valid allocation then the preferred size will
9275 * be transformed and returned.
9277 * If you want the transformed allocation, see
9278 * clutter_actor_get_abs_allocation_vertices() instead.
9280 * <note>When the actor (or one of its ancestors) is rotated around the
9281 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9282 * as a generic quadrangle; in that case this function returns the size
9283 * of the smallest rectangle that encapsulates the entire quad. Please
9284 * note that in this case no assumptions can be made about the relative
9285 * position of this envelope to the absolute position of the actor, as
9286 * returned by clutter_actor_get_transformed_position(); if you need this
9287 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9288 * to get the coords of the actual quadrangle.</note>
9293 clutter_actor_get_transformed_size (ClutterActor *self,
9297 ClutterActorPrivate *priv;
9299 gfloat x_min, x_max, y_min, y_max;
9302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9306 /* if the actor hasn't been allocated yet, get the preferred
9307 * size and transform that
9309 if (priv->needs_allocation)
9311 gfloat natural_width, natural_height;
9312 ClutterActorBox box;
9314 /* Make a fake allocation to transform.
9316 * NB: _clutter_actor_transform_and_project_box expects a box in
9317 * the actor's coordinate space... */
9322 natural_width = natural_height = 0;
9323 clutter_actor_get_preferred_size (self, NULL, NULL,
9327 box.x2 = natural_width;
9328 box.y2 = natural_height;
9330 _clutter_actor_transform_and_project_box (self, &box, v);
9333 clutter_actor_get_abs_allocation_vertices (self, v);
9335 x_min = x_max = v[0].x;
9336 y_min = y_max = v[0].y;
9338 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9354 *width = x_max - x_min;
9357 *height = y_max - y_min;
9361 * clutter_actor_get_width:
9362 * @self: A #ClutterActor
9364 * Retrieves the width of a #ClutterActor.
9366 * If the actor has a valid allocation, this function will return the
9367 * width of the allocated area given to the actor.
9369 * If the actor does not have a valid allocation, this function will
9370 * return the actor's natural width, that is the preferred width of
9373 * If you care whether you get the preferred width or the width that
9374 * has been assigned to the actor, you should probably call a different
9375 * function like clutter_actor_get_allocation_box() to retrieve the
9376 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9379 * If an actor has a fixed width, for instance a width that has been
9380 * assigned using clutter_actor_set_width(), the width returned will
9381 * be the same value.
9383 * Return value: the width of the actor, in pixels
9386 clutter_actor_get_width (ClutterActor *self)
9388 ClutterActorPrivate *priv;
9390 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9394 if (priv->needs_allocation)
9396 gfloat natural_width = 0;
9398 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9399 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9402 gfloat natural_height = 0;
9404 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9405 clutter_actor_get_preferred_width (self, natural_height,
9410 return natural_width;
9413 return priv->allocation.x2 - priv->allocation.x1;
9417 * clutter_actor_get_height:
9418 * @self: A #ClutterActor
9420 * Retrieves the height of a #ClutterActor.
9422 * If the actor has a valid allocation, this function will return the
9423 * height of the allocated area given to the actor.
9425 * If the actor does not have a valid allocation, this function will
9426 * return the actor's natural height, that is the preferred height of
9429 * If you care whether you get the preferred height or the height that
9430 * has been assigned to the actor, you should probably call a different
9431 * function like clutter_actor_get_allocation_box() to retrieve the
9432 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9435 * If an actor has a fixed height, for instance a height that has been
9436 * assigned using clutter_actor_set_height(), the height returned will
9437 * be the same value.
9439 * Return value: the height of the actor, in pixels
9442 clutter_actor_get_height (ClutterActor *self)
9444 ClutterActorPrivate *priv;
9446 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9450 if (priv->needs_allocation)
9452 gfloat natural_height = 0;
9454 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9456 gfloat natural_width = 0;
9458 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9459 clutter_actor_get_preferred_height (self, natural_width,
9460 NULL, &natural_height);
9463 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9465 return natural_height;
9468 return priv->allocation.y2 - priv->allocation.y1;
9472 * clutter_actor_set_width:
9473 * @self: A #ClutterActor
9474 * @width: Requested new width for the actor, in pixels, or -1
9476 * Forces a width on an actor, causing the actor's preferred width
9477 * and height (if any) to be ignored.
9479 * If @width is -1 the actor will use its preferred width request
9480 * instead of overriding it, i.e. you can "unset" the width with -1.
9482 * This function sets both the minimum and natural size of the actor.
9487 clutter_actor_set_width (ClutterActor *self,
9490 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9492 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9496 /* minor optimization: if we don't have a duration
9497 * then we can skip the get_width() below, to avoid
9498 * the chance of going through get_preferred_width()
9499 * just to jump to a new desired width.
9501 if (clutter_actor_get_easing_duration (self) == 0)
9503 g_object_freeze_notify (G_OBJECT (self));
9505 clutter_actor_set_width_internal (self, width);
9507 g_object_thaw_notify (G_OBJECT (self));
9512 cur_size = clutter_actor_get_width (self);
9514 _clutter_actor_create_transition (self,
9515 obj_props[PROP_WIDTH],
9520 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9524 * clutter_actor_set_height:
9525 * @self: A #ClutterActor
9526 * @height: Requested new height for the actor, in pixels, or -1
9528 * Forces a height on an actor, causing the actor's preferred width
9529 * and height (if any) to be ignored.
9531 * If @height is -1 the actor will use its preferred height instead of
9532 * overriding it, i.e. you can "unset" the height with -1.
9534 * This function sets both the minimum and natural size of the actor.
9539 clutter_actor_set_height (ClutterActor *self,
9542 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9544 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9548 /* see the comment in clutter_actor_set_width() above */
9549 if (clutter_actor_get_easing_duration (self) == 0)
9551 g_object_freeze_notify (G_OBJECT (self));
9553 clutter_actor_set_height_internal (self, height);
9555 g_object_thaw_notify (G_OBJECT (self));
9560 cur_size = clutter_actor_get_height (self);
9562 _clutter_actor_create_transition (self,
9563 obj_props[PROP_HEIGHT],
9568 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9572 clutter_actor_set_x_internal (ClutterActor *self,
9575 ClutterActorPrivate *priv = self->priv;
9576 ClutterLayoutInfo *linfo;
9577 ClutterActorBox old = { 0, };
9579 linfo = _clutter_actor_get_layout_info (self);
9581 if (priv->position_set && linfo->fixed_x == x)
9584 clutter_actor_store_old_geometry (self, &old);
9587 clutter_actor_set_fixed_position_set (self, TRUE);
9589 clutter_actor_notify_if_geometry_changed (self, &old);
9591 clutter_actor_queue_relayout (self);
9595 clutter_actor_set_y_internal (ClutterActor *self,
9598 ClutterActorPrivate *priv = self->priv;
9599 ClutterLayoutInfo *linfo;
9600 ClutterActorBox old = { 0, };
9602 linfo = _clutter_actor_get_layout_info (self);
9604 if (priv->position_set && linfo->fixed_y == y)
9607 clutter_actor_store_old_geometry (self, &old);
9610 clutter_actor_set_fixed_position_set (self, TRUE);
9612 clutter_actor_notify_if_geometry_changed (self, &old);
9614 clutter_actor_queue_relayout (self);
9618 * clutter_actor_set_x:
9619 * @self: a #ClutterActor
9620 * @x: the actor's position on the X axis
9622 * Sets the actor's X coordinate, relative to its parent, in pixels.
9624 * Overrides any layout manager and forces a fixed position for
9627 * The #ClutterActor:x property is animatable.
9632 clutter_actor_set_x (ClutterActor *self,
9635 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9637 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9639 float cur_position = clutter_actor_get_x (self);
9641 _clutter_actor_create_transition (self, obj_props[PROP_X],
9646 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9650 * clutter_actor_set_y:
9651 * @self: a #ClutterActor
9652 * @y: the actor's position on the Y axis
9654 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9656 * Overrides any layout manager and forces a fixed position for
9659 * The #ClutterActor:y property is animatable.
9664 clutter_actor_set_y (ClutterActor *self,
9667 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9669 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9671 float cur_position = clutter_actor_get_y (self);
9673 _clutter_actor_create_transition (self, obj_props[PROP_Y],
9678 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9682 * clutter_actor_get_x:
9683 * @self: A #ClutterActor
9685 * Retrieves the X coordinate of a #ClutterActor.
9687 * This function tries to "do what you mean", by returning the
9688 * correct value depending on the actor's state.
9690 * If the actor has a valid allocation, this function will return
9691 * the X coordinate of the origin of the allocation box.
9693 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9694 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9695 * function will return that coordinate.
9697 * If both the allocation and a fixed position are missing, this function
9700 * Return value: the X coordinate, in pixels, ignoring any
9701 * transformation (i.e. scaling, rotation)
9704 clutter_actor_get_x (ClutterActor *self)
9706 ClutterActorPrivate *priv;
9708 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9712 if (priv->needs_allocation)
9714 if (priv->position_set)
9716 const ClutterLayoutInfo *info;
9718 info = _clutter_actor_get_layout_info_or_defaults (self);
9720 return info->fixed_x;
9726 return priv->allocation.x1;
9730 * clutter_actor_get_y:
9731 * @self: A #ClutterActor
9733 * Retrieves the Y coordinate of a #ClutterActor.
9735 * This function tries to "do what you mean", by returning the
9736 * correct value depending on the actor's state.
9738 * If the actor has a valid allocation, this function will return
9739 * the Y coordinate of the origin of the allocation box.
9741 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9742 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9743 * function will return that coordinate.
9745 * If both the allocation and a fixed position are missing, this function
9748 * Return value: the Y coordinate, in pixels, ignoring any
9749 * transformation (i.e. scaling, rotation)
9752 clutter_actor_get_y (ClutterActor *self)
9754 ClutterActorPrivate *priv;
9756 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9760 if (priv->needs_allocation)
9762 if (priv->position_set)
9764 const ClutterLayoutInfo *info;
9766 info = _clutter_actor_get_layout_info_or_defaults (self);
9768 return info->fixed_y;
9774 return priv->allocation.y1;
9778 * clutter_actor_set_scale:
9779 * @self: A #ClutterActor
9780 * @scale_x: double factor to scale actor by horizontally.
9781 * @scale_y: double factor to scale actor by vertically.
9783 * Scales an actor with the given factors. The scaling is relative to
9784 * the scale center and the anchor point. The scale center is
9785 * unchanged by this function and defaults to 0,0.
9787 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9793 clutter_actor_set_scale (ClutterActor *self,
9797 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9799 g_object_freeze_notify (G_OBJECT (self));
9801 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9802 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9804 g_object_thaw_notify (G_OBJECT (self));
9808 * clutter_actor_set_scale_full:
9809 * @self: A #ClutterActor
9810 * @scale_x: double factor to scale actor by horizontally.
9811 * @scale_y: double factor to scale actor by vertically.
9812 * @center_x: X coordinate of the center of the scale.
9813 * @center_y: Y coordinate of the center of the scale
9815 * Scales an actor with the given factors around the given center
9816 * point. The center point is specified in pixels relative to the
9817 * anchor point (usually the top left corner of the actor).
9819 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9825 clutter_actor_set_scale_full (ClutterActor *self,
9831 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9833 g_object_freeze_notify (G_OBJECT (self));
9835 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9836 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9837 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9838 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9840 g_object_thaw_notify (G_OBJECT (self));
9844 * clutter_actor_set_scale_with_gravity:
9845 * @self: A #ClutterActor
9846 * @scale_x: double factor to scale actor by horizontally.
9847 * @scale_y: double factor to scale actor by vertically.
9848 * @gravity: the location of the scale center expressed as a compass
9851 * Scales an actor with the given factors around the given
9852 * center point. The center point is specified as one of the compass
9853 * directions in #ClutterGravity. For example, setting it to north
9854 * will cause the top of the actor to remain unchanged and the rest of
9855 * the actor to expand left, right and downwards.
9857 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9863 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9866 ClutterGravity gravity)
9868 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9870 g_object_freeze_notify (G_OBJECT (self));
9872 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9873 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9874 clutter_actor_set_scale_gravity (self, gravity);
9876 g_object_thaw_notify (G_OBJECT (self));
9880 * clutter_actor_get_scale:
9881 * @self: A #ClutterActor
9882 * @scale_x: (out) (allow-none): Location to store horizonal
9883 * scale factor, or %NULL.
9884 * @scale_y: (out) (allow-none): Location to store vertical
9885 * scale factor, or %NULL.
9887 * Retrieves an actors scale factors.
9892 clutter_actor_get_scale (ClutterActor *self,
9896 const ClutterTransformInfo *info;
9898 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9900 info = _clutter_actor_get_transform_info_or_defaults (self);
9903 *scale_x = info->scale_x;
9906 *scale_y = info->scale_y;
9910 * clutter_actor_get_scale_center:
9911 * @self: A #ClutterActor
9912 * @center_x: (out) (allow-none): Location to store the X position
9913 * of the scale center, or %NULL.
9914 * @center_y: (out) (allow-none): Location to store the Y position
9915 * of the scale center, or %NULL.
9917 * Retrieves the scale center coordinate in pixels relative to the top
9918 * left corner of the actor. If the scale center was specified using a
9919 * #ClutterGravity this will calculate the pixel offset using the
9920 * current size of the actor.
9925 clutter_actor_get_scale_center (ClutterActor *self,
9929 const ClutterTransformInfo *info;
9931 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9933 info = _clutter_actor_get_transform_info_or_defaults (self);
9935 clutter_anchor_coord_get_units (self, &info->scale_center,
9942 * clutter_actor_get_scale_gravity:
9943 * @self: A #ClutterActor
9945 * Retrieves the scale center as a compass direction. If the scale
9946 * center was specified in pixels or units this will return
9947 * %CLUTTER_GRAVITY_NONE.
9949 * Return value: the scale gravity
9954 clutter_actor_get_scale_gravity (ClutterActor *self)
9956 const ClutterTransformInfo *info;
9958 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9960 info = _clutter_actor_get_transform_info_or_defaults (self);
9962 return clutter_anchor_coord_get_gravity (&info->scale_center);
9966 clutter_actor_set_opacity_internal (ClutterActor *self,
9969 ClutterActorPrivate *priv = self->priv;
9971 if (priv->opacity != opacity)
9973 priv->opacity = opacity;
9975 /* Queue a redraw from the flatten effect so that it can use
9976 its cached image if available instead of having to redraw the
9977 actual actor. If it doesn't end up using the FBO then the
9978 effect is still able to continue the paint anyway. If there
9979 is no flatten effect yet then this is equivalent to queueing
9981 _clutter_actor_queue_redraw_full (self,
9984 priv->flatten_effect);
9986 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9991 * clutter_actor_set_opacity:
9992 * @self: A #ClutterActor
9993 * @opacity: New opacity value for the actor.
9995 * Sets the actor's opacity, with zero being completely transparent and
9996 * 255 (0xff) being fully opaque.
9998 * The #ClutterActor:opacity property is animatable.
10001 clutter_actor_set_opacity (ClutterActor *self,
10004 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10006 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10008 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10009 self->priv->opacity,
10013 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10017 * clutter_actor_get_paint_opacity_internal:
10018 * @self: a #ClutterActor
10020 * Retrieves the absolute opacity of the actor, as it appears on the stage
10022 * This function does not do type checks
10024 * Return value: the absolute opacity of the actor
10027 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10029 ClutterActorPrivate *priv = self->priv;
10030 ClutterActor *parent;
10032 /* override the top-level opacity to always be 255; even in
10033 * case of ClutterStage:use-alpha being TRUE we want the rest
10034 * of the scene to be painted
10036 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10039 if (priv->opacity_override >= 0)
10040 return priv->opacity_override;
10042 parent = priv->parent;
10044 /* Factor in the actual actors opacity with parents */
10045 if (parent != NULL)
10047 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10049 if (opacity != 0xff)
10050 return (opacity * priv->opacity) / 0xff;
10053 return priv->opacity;
10058 * clutter_actor_get_paint_opacity:
10059 * @self: A #ClutterActor
10061 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10063 * This function traverses the hierarchy chain and composites the opacity of
10064 * the actor with that of its parents.
10066 * This function is intended for subclasses to use in the paint virtual
10067 * function, to paint themselves with the correct opacity.
10069 * Return value: The actor opacity value.
10074 clutter_actor_get_paint_opacity (ClutterActor *self)
10076 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10078 return clutter_actor_get_paint_opacity_internal (self);
10082 * clutter_actor_get_opacity:
10083 * @self: a #ClutterActor
10085 * Retrieves the opacity value of an actor, as set by
10086 * clutter_actor_set_opacity().
10088 * For retrieving the absolute opacity of the actor inside a paint
10089 * virtual function, see clutter_actor_get_paint_opacity().
10091 * Return value: the opacity of the actor
10094 clutter_actor_get_opacity (ClutterActor *self)
10096 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10098 return self->priv->opacity;
10102 * clutter_actor_set_offscreen_redirect:
10103 * @self: A #ClutterActor
10104 * @redirect: New offscreen redirect flags for the actor.
10106 * Defines the circumstances where the actor should be redirected into
10107 * an offscreen image. The offscreen image is used to flatten the
10108 * actor into a single image while painting for two main reasons.
10109 * Firstly, when the actor is painted a second time without any of its
10110 * contents changing it can simply repaint the cached image without
10111 * descending further down the actor hierarchy. Secondly, it will make
10112 * the opacity look correct even if there are overlapping primitives
10115 * Caching the actor could in some cases be a performance win and in
10116 * some cases be a performance lose so it is important to determine
10117 * which value is right for an actor before modifying this value. For
10118 * example, there is never any reason to flatten an actor that is just
10119 * a single texture (such as a #ClutterTexture) because it is
10120 * effectively already cached in an image so the offscreen would be
10121 * redundant. Also if the actor contains primitives that are far apart
10122 * with a large transparent area in the middle (such as a large
10123 * CluterGroup with a small actor in the top left and a small actor in
10124 * the bottom right) then the cached image will contain the entire
10125 * image of the large area and the paint will waste time blending all
10126 * of the transparent pixels in the middle.
10128 * The default method of implementing opacity on a container simply
10129 * forwards on the opacity to all of the children. If the children are
10130 * overlapping then it will appear as if they are two separate glassy
10131 * objects and there will be a break in the color where they
10132 * overlap. By redirecting to an offscreen buffer it will be as if the
10133 * two opaque objects are combined into one and then made transparent
10134 * which is usually what is expected.
10136 * The image below demonstrates the difference between redirecting and
10137 * not. The image shows two Clutter groups, each containing a red and
10138 * a green rectangle which overlap. The opacity on the group is set to
10139 * 128 (which is 50%). When the offscreen redirect is not used, the
10140 * red rectangle can be seen through the blue rectangle as if the two
10141 * rectangles were separately transparent. When the redirect is used
10142 * the group as a whole is transparent instead so the red rectangle is
10143 * not visible where they overlap.
10145 * <figure id="offscreen-redirect">
10146 * <title>Sample of using an offscreen redirect for transparency</title>
10147 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10150 * The default value for this property is 0, so we effectively will
10151 * never redirect an actor offscreen by default. This means that there
10152 * are times that transparent actors may look glassy as described
10153 * above. The reason this is the default is because there is a
10154 * performance trade off between quality and performance here. In many
10155 * cases the default form of glassy opacity looks good enough, but if
10156 * it's not you will need to set the
10157 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10158 * redirection for opacity.
10160 * Custom actors that don't contain any overlapping primitives are
10161 * recommended to override the has_overlaps() virtual to return %FALSE
10162 * for maximum efficiency.
10167 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10168 ClutterOffscreenRedirect redirect)
10170 ClutterActorPrivate *priv;
10172 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10176 if (priv->offscreen_redirect != redirect)
10178 priv->offscreen_redirect = redirect;
10180 /* Queue a redraw from the effect so that it can use its cached
10181 image if available instead of having to redraw the actual
10182 actor. If it doesn't end up using the FBO then the effect is
10183 still able to continue the paint anyway. If there is no
10184 effect then this is equivalent to queuing a full redraw */
10185 _clutter_actor_queue_redraw_full (self,
10188 priv->flatten_effect);
10190 g_object_notify_by_pspec (G_OBJECT (self),
10191 obj_props[PROP_OFFSCREEN_REDIRECT]);
10196 * clutter_actor_get_offscreen_redirect:
10197 * @self: a #ClutterActor
10199 * Retrieves whether to redirect the actor to an offscreen buffer, as
10200 * set by clutter_actor_set_offscreen_redirect().
10202 * Return value: the value of the offscreen-redirect property of the actor
10206 ClutterOffscreenRedirect
10207 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10209 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10211 return self->priv->offscreen_redirect;
10215 * clutter_actor_set_name:
10216 * @self: A #ClutterActor
10217 * @name: Textual tag to apply to actor
10219 * Sets the given name to @self. The name can be used to identify
10223 clutter_actor_set_name (ClutterActor *self,
10226 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10228 g_free (self->priv->name);
10229 self->priv->name = g_strdup (name);
10231 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10235 * clutter_actor_get_name:
10236 * @self: A #ClutterActor
10238 * Retrieves the name of @self.
10240 * Return value: the name of the actor, or %NULL. The returned string is
10241 * owned by the actor and should not be modified or freed.
10244 clutter_actor_get_name (ClutterActor *self)
10246 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10248 return self->priv->name;
10252 * clutter_actor_get_gid:
10253 * @self: A #ClutterActor
10255 * Retrieves the unique id for @self.
10257 * Return value: Globally unique value for this object instance.
10261 * Deprecated: 1.8: The id is not used any longer.
10264 clutter_actor_get_gid (ClutterActor *self)
10266 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10268 return self->priv->id;
10272 clutter_actor_set_depth_internal (ClutterActor *self,
10275 ClutterTransformInfo *info;
10277 info = _clutter_actor_get_transform_info (self);
10279 if (info->depth != depth)
10281 /* Sets Z value - XXX 2.0: should we invert? */
10282 info->depth = depth;
10284 self->priv->transform_valid = FALSE;
10286 /* FIXME - remove this crap; sadly, there are still containers
10287 * in Clutter that depend on this utter brain damage
10289 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10291 clutter_actor_queue_redraw (self);
10293 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10298 * clutter_actor_set_depth:
10299 * @self: a #ClutterActor
10302 * Sets the Z coordinate of @self to @depth.
10304 * The unit used by @depth is dependant on the perspective setup. See
10305 * also clutter_stage_set_perspective().
10308 clutter_actor_set_depth (ClutterActor *self,
10311 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10313 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10315 const ClutterTransformInfo *info;
10317 info = _clutter_actor_get_transform_info_or_defaults (self);
10319 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10324 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10326 clutter_actor_queue_redraw (self);
10330 * clutter_actor_get_depth:
10331 * @self: a #ClutterActor
10333 * Retrieves the depth of @self.
10335 * Return value: the depth of the actor
10338 clutter_actor_get_depth (ClutterActor *self)
10340 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10342 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10346 * clutter_actor_set_rotation:
10347 * @self: a #ClutterActor
10348 * @axis: the axis of rotation
10349 * @angle: the angle of rotation
10350 * @x: X coordinate of the rotation center
10351 * @y: Y coordinate of the rotation center
10352 * @z: Z coordinate of the rotation center
10354 * Sets the rotation angle of @self around the given axis.
10356 * The rotation center coordinates used depend on the value of @axis:
10358 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10359 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10360 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10363 * The rotation coordinates are relative to the anchor point of the
10364 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10365 * point is set, the upper left corner is assumed as the origin.
10370 clutter_actor_set_rotation (ClutterActor *self,
10371 ClutterRotateAxis axis,
10379 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10385 g_object_freeze_notify (G_OBJECT (self));
10387 clutter_actor_set_rotation_angle (self, axis, angle);
10388 clutter_actor_set_rotation_center_internal (self, axis, &v);
10390 g_object_thaw_notify (G_OBJECT (self));
10394 * clutter_actor_set_z_rotation_from_gravity:
10395 * @self: a #ClutterActor
10396 * @angle: the angle of rotation
10397 * @gravity: the center point of the rotation
10399 * Sets the rotation angle of @self around the Z axis using the center
10400 * point specified as a compass point. For example to rotate such that
10401 * the center of the actor remains static you can use
10402 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10403 * will move accordingly.
10408 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10410 ClutterGravity gravity)
10412 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10414 if (gravity == CLUTTER_GRAVITY_NONE)
10415 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10418 GObject *obj = G_OBJECT (self);
10419 ClutterTransformInfo *info;
10421 info = _clutter_actor_get_transform_info (self);
10423 g_object_freeze_notify (obj);
10425 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10427 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10428 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10429 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10431 g_object_thaw_notify (obj);
10436 * clutter_actor_get_rotation:
10437 * @self: a #ClutterActor
10438 * @axis: the axis of rotation
10439 * @x: (out): return value for the X coordinate of the center of rotation
10440 * @y: (out): return value for the Y coordinate of the center of rotation
10441 * @z: (out): return value for the Z coordinate of the center of rotation
10443 * Retrieves the angle and center of rotation on the given axis,
10444 * set using clutter_actor_set_rotation().
10446 * Return value: the angle of rotation
10451 clutter_actor_get_rotation (ClutterActor *self,
10452 ClutterRotateAxis axis,
10457 const ClutterTransformInfo *info;
10458 const AnchorCoord *anchor_coord;
10459 gdouble retval = 0;
10461 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10463 info = _clutter_actor_get_transform_info_or_defaults (self);
10467 case CLUTTER_X_AXIS:
10468 anchor_coord = &info->rx_center;
10469 retval = info->rx_angle;
10472 case CLUTTER_Y_AXIS:
10473 anchor_coord = &info->ry_center;
10474 retval = info->ry_angle;
10477 case CLUTTER_Z_AXIS:
10478 anchor_coord = &info->rz_center;
10479 retval = info->rz_angle;
10483 anchor_coord = NULL;
10488 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10494 * clutter_actor_get_z_rotation_gravity:
10495 * @self: A #ClutterActor
10497 * Retrieves the center for the rotation around the Z axis as a
10498 * compass direction. If the center was specified in pixels or units
10499 * this will return %CLUTTER_GRAVITY_NONE.
10501 * Return value: the Z rotation center
10506 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10508 const ClutterTransformInfo *info;
10510 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10512 info = _clutter_actor_get_transform_info_or_defaults (self);
10514 return clutter_anchor_coord_get_gravity (&info->rz_center);
10518 * clutter_actor_set_clip:
10519 * @self: A #ClutterActor
10520 * @xoff: X offset of the clip rectangle
10521 * @yoff: Y offset of the clip rectangle
10522 * @width: Width of the clip rectangle
10523 * @height: Height of the clip rectangle
10525 * Sets clip area for @self. The clip area is always computed from the
10526 * upper left corner of the actor, even if the anchor point is set
10532 clutter_actor_set_clip (ClutterActor *self,
10538 ClutterActorPrivate *priv;
10540 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10544 if (priv->has_clip &&
10545 priv->clip.x == xoff &&
10546 priv->clip.y == yoff &&
10547 priv->clip.width == width &&
10548 priv->clip.height == height)
10551 priv->clip.x = xoff;
10552 priv->clip.y = yoff;
10553 priv->clip.width = width;
10554 priv->clip.height = height;
10556 priv->has_clip = TRUE;
10558 clutter_actor_queue_redraw (self);
10560 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10561 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10565 * clutter_actor_remove_clip:
10566 * @self: A #ClutterActor
10568 * Removes clip area from @self.
10571 clutter_actor_remove_clip (ClutterActor *self)
10573 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10575 if (!self->priv->has_clip)
10578 self->priv->has_clip = FALSE;
10580 clutter_actor_queue_redraw (self);
10582 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10586 * clutter_actor_has_clip:
10587 * @self: a #ClutterActor
10589 * Determines whether the actor has a clip area set or not.
10591 * Return value: %TRUE if the actor has a clip area set.
10596 clutter_actor_has_clip (ClutterActor *self)
10598 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10600 return self->priv->has_clip;
10604 * clutter_actor_get_clip:
10605 * @self: a #ClutterActor
10606 * @xoff: (out) (allow-none): return location for the X offset of
10607 * the clip rectangle, or %NULL
10608 * @yoff: (out) (allow-none): return location for the Y offset of
10609 * the clip rectangle, or %NULL
10610 * @width: (out) (allow-none): return location for the width of
10611 * the clip rectangle, or %NULL
10612 * @height: (out) (allow-none): return location for the height of
10613 * the clip rectangle, or %NULL
10615 * Gets the clip area for @self, if any is set
10620 clutter_actor_get_clip (ClutterActor *self,
10626 ClutterActorPrivate *priv;
10628 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10632 if (!priv->has_clip)
10636 *xoff = priv->clip.x;
10639 *yoff = priv->clip.y;
10642 *width = priv->clip.width;
10644 if (height != NULL)
10645 *height = priv->clip.height;
10649 * clutter_actor_get_children:
10650 * @self: a #ClutterActor
10652 * Retrieves the list of children of @self.
10654 * Return value: (transfer container) (element-type ClutterActor): A newly
10655 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10661 clutter_actor_get_children (ClutterActor *self)
10663 ClutterActor *iter;
10666 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10668 /* we walk the list backward so that we can use prepend(),
10671 for (iter = self->priv->last_child, res = NULL;
10673 iter = iter->priv->prev_sibling)
10675 res = g_list_prepend (res, iter);
10682 * insert_child_at_depth:
10683 * @self: a #ClutterActor
10684 * @child: a #ClutterActor
10686 * Inserts @child inside the list of children held by @self, using
10687 * the depth as the insertion criteria.
10689 * This sadly makes the insertion not O(1), but we can keep the
10690 * list sorted so that the painters algorithm we use for painting
10691 * the children will work correctly.
10694 insert_child_at_depth (ClutterActor *self,
10695 ClutterActor *child,
10696 gpointer dummy G_GNUC_UNUSED)
10698 ClutterActor *iter;
10701 child->priv->parent = self;
10704 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10706 /* special-case the first child */
10707 if (self->priv->n_children == 0)
10709 self->priv->first_child = child;
10710 self->priv->last_child = child;
10712 child->priv->next_sibling = NULL;
10713 child->priv->prev_sibling = NULL;
10718 /* Find the right place to insert the child so that it will still be
10719 sorted and the child will be after all of the actors at the same
10721 for (iter = self->priv->first_child;
10723 iter = iter->priv->next_sibling)
10728 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10730 if (iter_depth > child_depth)
10736 ClutterActor *tmp = iter->priv->prev_sibling;
10739 tmp->priv->next_sibling = child;
10741 /* Insert the node before the found one */
10742 child->priv->prev_sibling = iter->priv->prev_sibling;
10743 child->priv->next_sibling = iter;
10744 iter->priv->prev_sibling = child;
10748 ClutterActor *tmp = self->priv->last_child;
10751 tmp->priv->next_sibling = child;
10753 /* insert the node at the end of the list */
10754 child->priv->prev_sibling = self->priv->last_child;
10755 child->priv->next_sibling = NULL;
10758 if (child->priv->prev_sibling == NULL)
10759 self->priv->first_child = child;
10761 if (child->priv->next_sibling == NULL)
10762 self->priv->last_child = child;
10766 insert_child_at_index (ClutterActor *self,
10767 ClutterActor *child,
10770 gint index_ = GPOINTER_TO_INT (data_);
10772 child->priv->parent = self;
10776 ClutterActor *tmp = self->priv->first_child;
10779 tmp->priv->prev_sibling = child;
10781 child->priv->prev_sibling = NULL;
10782 child->priv->next_sibling = tmp;
10784 else if (index_ < 0 || index_ >= self->priv->n_children)
10786 ClutterActor *tmp = self->priv->last_child;
10789 tmp->priv->next_sibling = child;
10791 child->priv->prev_sibling = tmp;
10792 child->priv->next_sibling = NULL;
10796 ClutterActor *iter;
10799 for (iter = self->priv->first_child, i = 0;
10801 iter = iter->priv->next_sibling, i += 1)
10805 ClutterActor *tmp = iter->priv->prev_sibling;
10807 child->priv->prev_sibling = tmp;
10808 child->priv->next_sibling = iter;
10810 iter->priv->prev_sibling = child;
10813 tmp->priv->next_sibling = child;
10820 if (child->priv->prev_sibling == NULL)
10821 self->priv->first_child = child;
10823 if (child->priv->next_sibling == NULL)
10824 self->priv->last_child = child;
10828 insert_child_above (ClutterActor *self,
10829 ClutterActor *child,
10832 ClutterActor *sibling = data;
10834 child->priv->parent = self;
10836 if (sibling == NULL)
10837 sibling = self->priv->last_child;
10839 child->priv->prev_sibling = sibling;
10841 if (sibling != NULL)
10843 ClutterActor *tmp = sibling->priv->next_sibling;
10845 child->priv->next_sibling = tmp;
10848 tmp->priv->prev_sibling = child;
10850 sibling->priv->next_sibling = child;
10853 child->priv->next_sibling = NULL;
10855 if (child->priv->prev_sibling == NULL)
10856 self->priv->first_child = child;
10858 if (child->priv->next_sibling == NULL)
10859 self->priv->last_child = child;
10863 insert_child_below (ClutterActor *self,
10864 ClutterActor *child,
10867 ClutterActor *sibling = data;
10869 child->priv->parent = self;
10871 if (sibling == NULL)
10872 sibling = self->priv->first_child;
10874 child->priv->next_sibling = sibling;
10876 if (sibling != NULL)
10878 ClutterActor *tmp = sibling->priv->prev_sibling;
10880 child->priv->prev_sibling = tmp;
10883 tmp->priv->next_sibling = child;
10885 sibling->priv->prev_sibling = child;
10888 child->priv->prev_sibling = NULL;
10890 if (child->priv->prev_sibling == NULL)
10891 self->priv->first_child = child;
10893 if (child->priv->next_sibling == NULL)
10894 self->priv->last_child = child;
10897 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10898 ClutterActor *child,
10902 ADD_CHILD_CREATE_META = 1 << 0,
10903 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10904 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10905 ADD_CHILD_CHECK_STATE = 1 << 3,
10906 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10907 ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
10909 /* default flags for public API */
10910 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10911 ADD_CHILD_EMIT_PARENT_SET |
10912 ADD_CHILD_EMIT_ACTOR_ADDED |
10913 ADD_CHILD_CHECK_STATE |
10914 ADD_CHILD_NOTIFY_FIRST_LAST |
10915 ADD_CHILD_SHOW_ON_SET_PARENT,
10917 /* flags for legacy/deprecated API */
10918 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10919 ADD_CHILD_CHECK_STATE |
10920 ADD_CHILD_NOTIFY_FIRST_LAST |
10921 ADD_CHILD_SHOW_ON_SET_PARENT
10922 } ClutterActorAddChildFlags;
10925 * clutter_actor_add_child_internal:
10926 * @self: a #ClutterActor
10927 * @child: a #ClutterActor
10928 * @flags: control flags for actions
10929 * @add_func: delegate function
10930 * @data: (closure): data to pass to @add_func
10932 * Adds @child to the list of children of @self.
10934 * The actual insertion inside the list is delegated to @add_func: this
10935 * function will just set up the state, perform basic checks, and emit
10938 * The @flags argument is used to perform additional operations.
10941 clutter_actor_add_child_internal (ClutterActor *self,
10942 ClutterActor *child,
10943 ClutterActorAddChildFlags flags,
10944 ClutterActorAddChildFunc add_func,
10947 ClutterTextDirection text_dir;
10948 gboolean create_meta;
10949 gboolean emit_parent_set, emit_actor_added;
10950 gboolean check_state;
10951 gboolean notify_first_last;
10952 gboolean show_on_set_parent;
10953 ClutterActor *old_first_child, *old_last_child;
10955 if (child->priv->parent != NULL)
10957 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10958 "use clutter_actor_remove_child() first.",
10959 _clutter_actor_get_debug_name (child),
10960 _clutter_actor_get_debug_name (child->priv->parent));
10964 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10966 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10967 "a child of another actor.",
10968 _clutter_actor_get_debug_name (child));
10973 /* XXX - this check disallows calling methods that change the stacking
10974 * order within the destruction sequence, by triggering a critical
10975 * warning first, and leaving the actor in an undefined state, which
10976 * then ends up being caught by an assertion.
10978 * the reproducible sequence is:
10980 * - actor gets destroyed;
10981 * - another actor, linked to the first, will try to change the
10982 * stacking order of the first actor;
10983 * - changing the stacking order is a composite operation composed
10984 * by the following steps:
10985 * 1. ref() the child;
10986 * 2. remove_child_internal(), which removes the reference;
10987 * 3. add_child_internal(), which adds a reference;
10988 * - the state of the actor is not changed between (2) and (3), as
10989 * it could be an expensive recomputation;
10990 * - if (3) bails out, then the actor is in an undefined state, but
10992 * - the destruction sequence terminates, but the actor is unparented
10993 * while its state indicates being parented instead.
10994 * - assertion failure.
10996 * the obvious fix would be to decompose each set_child_*_sibling()
10997 * method into proper remove_child()/add_child(), with state validation;
10998 * this may cause excessive work, though, and trigger a cascade of other
10999 * bugs in code that assumes that a change in the stacking order is an
11000 * atomic operation.
11002 * another potential fix is to just remove this check here, and let
11003 * code doing stacking order changes inside the destruction sequence
11004 * of an actor continue doing the work.
11006 * the third fix is to silently bail out early from every
11007 * set_child_*_sibling() and set_child_at_index() method, and avoid
11010 * I have a preference for the second solution, since it involves the
11011 * least amount of work, and the least amount of code duplication.
11013 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11015 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11017 g_warning ("The actor '%s' is currently being destroyed, and "
11018 "cannot be added as a child of another actor.",
11019 _clutter_actor_get_debug_name (child));
11024 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11025 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11026 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11027 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11028 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11029 show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11031 old_first_child = self->priv->first_child;
11032 old_last_child = self->priv->last_child;
11034 g_object_freeze_notify (G_OBJECT (self));
11037 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11039 g_object_ref_sink (child);
11040 child->priv->parent = NULL;
11041 child->priv->next_sibling = NULL;
11042 child->priv->prev_sibling = NULL;
11044 /* delegate the actual insertion */
11045 add_func (self, child, data);
11047 g_assert (child->priv->parent == self);
11049 self->priv->n_children += 1;
11051 self->priv->age += 1;
11053 /* if push_internal() has been called then we automatically set
11054 * the flag on the actor
11056 if (self->priv->internal_child)
11057 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11059 /* clutter_actor_reparent() will emit ::parent-set for us */
11060 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11061 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11065 /* If parent is mapped or realized, we need to also be mapped or
11066 * realized once we're inside the parent.
11068 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11070 /* propagate the parent's text direction to the child */
11071 text_dir = clutter_actor_get_text_direction (self);
11072 clutter_actor_set_text_direction (child, text_dir);
11075 if (show_on_set_parent && child->priv->show_on_set_parent)
11076 clutter_actor_show (child);
11078 if (CLUTTER_ACTOR_IS_MAPPED (child))
11079 clutter_actor_queue_redraw (child);
11081 /* maintain the invariant that if an actor needs layout,
11082 * its parents do as well
11084 if (child->priv->needs_width_request ||
11085 child->priv->needs_height_request ||
11086 child->priv->needs_allocation)
11088 /* we work around the short-circuiting we do
11089 * in clutter_actor_queue_relayout() since we
11090 * want to force a relayout
11092 child->priv->needs_width_request = TRUE;
11093 child->priv->needs_height_request = TRUE;
11094 child->priv->needs_allocation = TRUE;
11096 clutter_actor_queue_relayout (child->priv->parent);
11099 if (emit_actor_added)
11100 g_signal_emit_by_name (self, "actor-added", child);
11102 if (notify_first_last)
11104 if (old_first_child != self->priv->first_child)
11105 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11107 if (old_last_child != self->priv->last_child)
11108 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11111 g_object_thaw_notify (G_OBJECT (self));
11115 * clutter_actor_add_child:
11116 * @self: a #ClutterActor
11117 * @child: a #ClutterActor
11119 * Adds @child to the children of @self.
11121 * This function will acquire a reference on @child that will only
11122 * be released when calling clutter_actor_remove_child().
11124 * This function will take into consideration the #ClutterActor:depth
11125 * of @child, and will keep the list of children sorted.
11127 * This function will emit the #ClutterContainer::actor-added signal
11133 clutter_actor_add_child (ClutterActor *self,
11134 ClutterActor *child)
11136 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11137 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11138 g_return_if_fail (self != child);
11139 g_return_if_fail (child->priv->parent == NULL);
11141 clutter_actor_add_child_internal (self, child,
11142 ADD_CHILD_DEFAULT_FLAGS,
11143 insert_child_at_depth,
11148 * clutter_actor_insert_child_at_index:
11149 * @self: a #ClutterActor
11150 * @child: a #ClutterActor
11151 * @index_: the index
11153 * Inserts @child into the list of children of @self, using the
11154 * given @index_. If @index_ is greater than the number of children
11155 * in @self, or is less than 0, then the new child is added at the end.
11157 * This function will acquire a reference on @child that will only
11158 * be released when calling clutter_actor_remove_child().
11160 * This function will not take into consideration the #ClutterActor:depth
11163 * This function will emit the #ClutterContainer::actor-added signal
11169 clutter_actor_insert_child_at_index (ClutterActor *self,
11170 ClutterActor *child,
11173 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11174 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11175 g_return_if_fail (self != child);
11176 g_return_if_fail (child->priv->parent == NULL);
11178 clutter_actor_add_child_internal (self, child,
11179 ADD_CHILD_DEFAULT_FLAGS,
11180 insert_child_at_index,
11181 GINT_TO_POINTER (index_));
11185 * clutter_actor_insert_child_above:
11186 * @self: a #ClutterActor
11187 * @child: a #ClutterActor
11188 * @sibling: (allow-none): a child of @self, or %NULL
11190 * Inserts @child into the list of children of @self, above another
11191 * child of @self or, if @sibling is %NULL, above all the children
11194 * This function will acquire a reference on @child that will only
11195 * be released when calling clutter_actor_remove_child().
11197 * This function will not take into consideration the #ClutterActor:depth
11200 * This function will emit the #ClutterContainer::actor-added signal
11206 clutter_actor_insert_child_above (ClutterActor *self,
11207 ClutterActor *child,
11208 ClutterActor *sibling)
11210 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11211 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11212 g_return_if_fail (self != child);
11213 g_return_if_fail (child != sibling);
11214 g_return_if_fail (child->priv->parent == NULL);
11215 g_return_if_fail (sibling == NULL ||
11216 (CLUTTER_IS_ACTOR (sibling) &&
11217 sibling->priv->parent == self));
11219 clutter_actor_add_child_internal (self, child,
11220 ADD_CHILD_DEFAULT_FLAGS,
11221 insert_child_above,
11226 * clutter_actor_insert_child_below:
11227 * @self: a #ClutterActor
11228 * @child: a #ClutterActor
11229 * @sibling: (allow-none): a child of @self, or %NULL
11231 * Inserts @child into the list of children of @self, below another
11232 * child of @self or, if @sibling is %NULL, below all the children
11235 * This function will acquire a reference on @child that will only
11236 * be released when calling clutter_actor_remove_child().
11238 * This function will not take into consideration the #ClutterActor:depth
11241 * This function will emit the #ClutterContainer::actor-added signal
11247 clutter_actor_insert_child_below (ClutterActor *self,
11248 ClutterActor *child,
11249 ClutterActor *sibling)
11251 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11252 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11253 g_return_if_fail (self != child);
11254 g_return_if_fail (child != sibling);
11255 g_return_if_fail (child->priv->parent == NULL);
11256 g_return_if_fail (sibling == NULL ||
11257 (CLUTTER_IS_ACTOR (sibling) &&
11258 sibling->priv->parent == self));
11260 clutter_actor_add_child_internal (self, child,
11261 ADD_CHILD_DEFAULT_FLAGS,
11262 insert_child_below,
11267 * clutter_actor_set_parent:
11268 * @self: A #ClutterActor
11269 * @parent: A new #ClutterActor parent
11271 * Sets the parent of @self to @parent.
11273 * This function will result in @parent acquiring a reference on @self,
11274 * eventually by sinking its floating reference first. The reference
11275 * will be released by clutter_actor_unparent().
11277 * This function should only be called by legacy #ClutterActor<!-- -->s
11278 * implementing the #ClutterContainer interface.
11280 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11283 clutter_actor_set_parent (ClutterActor *self,
11284 ClutterActor *parent)
11286 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11287 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11288 g_return_if_fail (self != parent);
11289 g_return_if_fail (self->priv->parent == NULL);
11291 /* as this function will be called inside ClutterContainer::add
11292 * implementations or when building up a composite actor, we have
11293 * to preserve the old behaviour, and not create child meta or
11294 * emit the ::actor-added signal, to avoid recursion or double
11297 clutter_actor_add_child_internal (parent, self,
11298 ADD_CHILD_LEGACY_FLAGS,
11299 insert_child_at_depth,
11304 * clutter_actor_get_parent:
11305 * @self: A #ClutterActor
11307 * Retrieves the parent of @self.
11309 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11310 * if no parent is set
11313 clutter_actor_get_parent (ClutterActor *self)
11315 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11317 return self->priv->parent;
11321 * clutter_actor_get_paint_visibility:
11322 * @self: A #ClutterActor
11324 * Retrieves the 'paint' visibility of an actor recursively checking for non
11327 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11329 * Return Value: %TRUE if the actor is visibile and will be painted.
11334 clutter_actor_get_paint_visibility (ClutterActor *actor)
11336 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11338 return CLUTTER_ACTOR_IS_MAPPED (actor);
11342 * clutter_actor_remove_child:
11343 * @self: a #ClutterActor
11344 * @child: a #ClutterActor
11346 * Removes @child from the children of @self.
11348 * This function will release the reference added by
11349 * clutter_actor_add_child(), so if you want to keep using @child
11350 * you will have to acquire a referenced on it before calling this
11353 * This function will emit the #ClutterContainer::actor-removed
11359 clutter_actor_remove_child (ClutterActor *self,
11360 ClutterActor *child)
11362 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11363 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11364 g_return_if_fail (self != child);
11365 g_return_if_fail (child->priv->parent != NULL);
11366 g_return_if_fail (child->priv->parent == self);
11368 clutter_actor_remove_child_internal (self, child,
11369 REMOVE_CHILD_DEFAULT_FLAGS);
11373 * clutter_actor_remove_all_children:
11374 * @self: a #ClutterActor
11376 * Removes all children of @self.
11378 * This function releases the reference added by inserting a child actor
11379 * in the list of children of @self.
11381 * If the reference count of a child drops to zero, the child will be
11382 * destroyed. If you want to ensure the destruction of all the children
11383 * of @self, use clutter_actor_destroy_all_children().
11388 clutter_actor_remove_all_children (ClutterActor *self)
11390 ClutterActorIter iter;
11392 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11394 if (self->priv->n_children == 0)
11397 g_object_freeze_notify (G_OBJECT (self));
11399 clutter_actor_iter_init (&iter, self);
11400 while (clutter_actor_iter_next (&iter, NULL))
11401 clutter_actor_iter_remove (&iter);
11403 g_object_thaw_notify (G_OBJECT (self));
11406 g_assert (self->priv->first_child == NULL);
11407 g_assert (self->priv->last_child == NULL);
11408 g_assert (self->priv->n_children == 0);
11412 * clutter_actor_destroy_all_children:
11413 * @self: a #ClutterActor
11415 * Destroys all children of @self.
11417 * This function releases the reference added by inserting a child
11418 * actor in the list of children of @self, and ensures that the
11419 * #ClutterActor::destroy signal is emitted on each child of the
11422 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11423 * when its reference count drops to 0; the default handler of the
11424 * #ClutterActor::destroy signal will destroy all the children of an
11425 * actor. This function ensures that all children are destroyed, instead
11426 * of just removed from @self, unlike clutter_actor_remove_all_children()
11427 * which will merely release the reference and remove each child.
11429 * Unless you acquired an additional reference on each child of @self
11430 * prior to calling clutter_actor_remove_all_children() and want to reuse
11431 * the actors, you should use clutter_actor_destroy_all_children() in
11432 * order to make sure that children are destroyed and signal handlers
11433 * are disconnected even in cases where circular references prevent this
11434 * from automatically happening through reference counting alone.
11439 clutter_actor_destroy_all_children (ClutterActor *self)
11441 ClutterActorIter iter;
11443 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11445 if (self->priv->n_children == 0)
11448 g_object_freeze_notify (G_OBJECT (self));
11450 clutter_actor_iter_init (&iter, self);
11451 while (clutter_actor_iter_next (&iter, NULL))
11452 clutter_actor_iter_destroy (&iter);
11454 g_object_thaw_notify (G_OBJECT (self));
11457 g_assert (self->priv->first_child == NULL);
11458 g_assert (self->priv->last_child == NULL);
11459 g_assert (self->priv->n_children == 0);
11462 typedef struct _InsertBetweenData {
11463 ClutterActor *prev_sibling;
11464 ClutterActor *next_sibling;
11465 } InsertBetweenData;
11468 insert_child_between (ClutterActor *self,
11469 ClutterActor *child,
11472 InsertBetweenData *data = data_;
11473 ClutterActor *prev_sibling = data->prev_sibling;
11474 ClutterActor *next_sibling = data->next_sibling;
11476 child->priv->parent = self;
11477 child->priv->prev_sibling = prev_sibling;
11478 child->priv->next_sibling = next_sibling;
11480 if (prev_sibling != NULL)
11481 prev_sibling->priv->next_sibling = child;
11483 if (next_sibling != NULL)
11484 next_sibling->priv->prev_sibling = child;
11486 if (child->priv->prev_sibling == NULL)
11487 self->priv->first_child = child;
11489 if (child->priv->next_sibling == NULL)
11490 self->priv->last_child = child;
11494 * clutter_actor_replace_child:
11495 * @self: a #ClutterActor
11496 * @old_child: the child of @self to replace
11497 * @new_child: the #ClutterActor to replace @old_child
11499 * Replaces @old_child with @new_child in the list of children of @self.
11504 clutter_actor_replace_child (ClutterActor *self,
11505 ClutterActor *old_child,
11506 ClutterActor *new_child)
11508 ClutterActor *prev_sibling, *next_sibling;
11509 InsertBetweenData clos;
11511 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11512 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11513 g_return_if_fail (old_child->priv->parent == self);
11514 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11515 g_return_if_fail (old_child != new_child);
11516 g_return_if_fail (new_child != self);
11517 g_return_if_fail (new_child->priv->parent == NULL);
11519 prev_sibling = old_child->priv->prev_sibling;
11520 next_sibling = old_child->priv->next_sibling;
11521 clutter_actor_remove_child_internal (self, old_child,
11522 REMOVE_CHILD_DEFAULT_FLAGS);
11524 clos.prev_sibling = prev_sibling;
11525 clos.next_sibling = next_sibling;
11526 clutter_actor_add_child_internal (self, new_child,
11527 ADD_CHILD_DEFAULT_FLAGS,
11528 insert_child_between,
11533 * clutter_actor_unparent:
11534 * @self: a #ClutterActor
11536 * Removes the parent of @self.
11538 * This will cause the parent of @self to release the reference
11539 * acquired when calling clutter_actor_set_parent(), so if you
11540 * want to keep @self you will have to acquire a reference of
11541 * your own, through g_object_ref().
11543 * This function should only be called by legacy #ClutterActor<!-- -->s
11544 * implementing the #ClutterContainer interface.
11548 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11551 clutter_actor_unparent (ClutterActor *self)
11553 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11555 if (self->priv->parent == NULL)
11558 clutter_actor_remove_child_internal (self->priv->parent, self,
11559 REMOVE_CHILD_LEGACY_FLAGS);
11563 * clutter_actor_reparent:
11564 * @self: a #ClutterActor
11565 * @new_parent: the new #ClutterActor parent
11567 * Resets the parent actor of @self.
11569 * This function is logically equivalent to calling clutter_actor_unparent()
11570 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11571 * ensures the child is not finalized when unparented, and emits the
11572 * #ClutterActor::parent-set signal only once.
11574 * In reality, calling this function is less useful than it sounds, as some
11575 * application code may rely on changes in the intermediate state between
11576 * removal and addition of the actor from its old parent to the @new_parent.
11577 * Thus, it is strongly encouraged to avoid using this function in application
11582 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11583 * clutter_actor_add_child() instead; remember to take a reference on
11584 * the actor being removed before calling clutter_actor_remove_child()
11585 * to avoid the reference count dropping to zero and the actor being
11589 clutter_actor_reparent (ClutterActor *self,
11590 ClutterActor *new_parent)
11592 ClutterActorPrivate *priv;
11594 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11595 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11596 g_return_if_fail (self != new_parent);
11598 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11600 g_warning ("Cannot set a parent on a toplevel actor");
11604 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11606 g_warning ("Cannot set a parent currently being destroyed");
11612 if (priv->parent != new_parent)
11614 ClutterActor *old_parent;
11616 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11618 old_parent = priv->parent;
11620 g_object_ref (self);
11622 if (old_parent != NULL)
11624 /* go through the Container implementation if this is a regular
11625 * child and not an internal one
11627 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11629 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11631 /* this will have to call unparent() */
11632 clutter_container_remove_actor (parent, self);
11635 clutter_actor_remove_child_internal (old_parent, self,
11636 REMOVE_CHILD_LEGACY_FLAGS);
11639 /* Note, will call set_parent() */
11640 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11641 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11643 clutter_actor_add_child_internal (new_parent, self,
11644 ADD_CHILD_LEGACY_FLAGS,
11645 insert_child_at_depth,
11648 /* we emit the ::parent-set signal once */
11649 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11651 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11653 /* the IN_REPARENT flag suspends state updates */
11654 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11656 g_object_unref (self);
11661 * clutter_actor_contains:
11662 * @self: A #ClutterActor
11663 * @descendant: A #ClutterActor, possibly contained in @self
11665 * Determines if @descendant is contained inside @self (either as an
11666 * immediate child, or as a deeper descendant). If @self and
11667 * @descendant point to the same actor then it will also return %TRUE.
11669 * Return value: whether @descendent is contained within @self
11674 clutter_actor_contains (ClutterActor *self,
11675 ClutterActor *descendant)
11677 ClutterActor *actor;
11679 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11680 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11682 for (actor = descendant; actor; actor = actor->priv->parent)
11690 * clutter_actor_set_child_above_sibling:
11691 * @self: a #ClutterActor
11692 * @child: a #ClutterActor child of @self
11693 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11695 * Sets @child to be above @sibling in the list of children of @self.
11697 * If @sibling is %NULL, @child will be the new last child of @self.
11699 * This function is logically equivalent to removing @child and using
11700 * clutter_actor_insert_child_above(), but it will not emit signals
11701 * or change state on @child.
11706 clutter_actor_set_child_above_sibling (ClutterActor *self,
11707 ClutterActor *child,
11708 ClutterActor *sibling)
11710 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11711 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11712 g_return_if_fail (child->priv->parent == self);
11713 g_return_if_fail (child != sibling);
11714 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11716 if (sibling != NULL)
11717 g_return_if_fail (sibling->priv->parent == self);
11719 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11720 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11721 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11724 /* we don't want to change the state of child, or emit signals, or
11725 * regenerate ChildMeta instances here, but we still want to follow
11726 * the correct sequence of steps encoded in remove_child() and
11727 * add_child(), so that correctness is ensured, and we only go
11728 * through one known code path.
11730 g_object_ref (child);
11731 clutter_actor_remove_child_internal (self, child, 0);
11732 clutter_actor_add_child_internal (self, child,
11733 ADD_CHILD_NOTIFY_FIRST_LAST,
11734 insert_child_above,
11737 clutter_actor_queue_relayout (self);
11741 * clutter_actor_set_child_below_sibling:
11742 * @self: a #ClutterActor
11743 * @child: a #ClutterActor child of @self
11744 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11746 * Sets @child to be below @sibling in the list of children of @self.
11748 * If @sibling is %NULL, @child will be the new first child of @self.
11750 * This function is logically equivalent to removing @self and using
11751 * clutter_actor_insert_child_below(), but it will not emit signals
11752 * or change state on @child.
11757 clutter_actor_set_child_below_sibling (ClutterActor *self,
11758 ClutterActor *child,
11759 ClutterActor *sibling)
11761 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11762 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11763 g_return_if_fail (child->priv->parent == self);
11764 g_return_if_fail (child != sibling);
11765 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11767 if (sibling != NULL)
11768 g_return_if_fail (sibling->priv->parent == self);
11770 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11771 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11772 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11775 /* see the comment in set_child_above_sibling() */
11776 g_object_ref (child);
11777 clutter_actor_remove_child_internal (self, child, 0);
11778 clutter_actor_add_child_internal (self, child,
11779 ADD_CHILD_NOTIFY_FIRST_LAST,
11780 insert_child_below,
11783 clutter_actor_queue_relayout (self);
11787 * clutter_actor_set_child_at_index:
11788 * @self: a #ClutterActor
11789 * @child: a #ClutterActor child of @self
11790 * @index_: the new index for @child
11792 * Changes the index of @child in the list of children of @self.
11794 * This function is logically equivalent to removing @child and
11795 * calling clutter_actor_insert_child_at_index(), but it will not
11796 * emit signals or change state on @child.
11801 clutter_actor_set_child_at_index (ClutterActor *self,
11802 ClutterActor *child,
11805 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11806 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11807 g_return_if_fail (child->priv->parent == self);
11808 g_return_if_fail (index_ <= self->priv->n_children);
11810 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11811 CLUTTER_ACTOR_IN_DESTRUCTION (child))
11814 g_object_ref (child);
11815 clutter_actor_remove_child_internal (self, child, 0);
11816 clutter_actor_add_child_internal (self, child,
11817 ADD_CHILD_NOTIFY_FIRST_LAST,
11818 insert_child_at_index,
11819 GINT_TO_POINTER (index_));
11821 clutter_actor_queue_relayout (self);
11825 * clutter_actor_raise:
11826 * @self: A #ClutterActor
11827 * @below: (allow-none): A #ClutterActor to raise above.
11829 * Puts @self above @below.
11831 * Both actors must have the same parent, and the parent must implement
11832 * the #ClutterContainer interface
11834 * This function calls clutter_container_raise_child() internally.
11836 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11839 clutter_actor_raise (ClutterActor *self,
11840 ClutterActor *below)
11842 ClutterActor *parent;
11844 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11846 parent = clutter_actor_get_parent (self);
11847 if (parent == NULL)
11849 g_warning ("%s: Actor '%s' is not inside a container",
11851 _clutter_actor_get_debug_name (self));
11857 if (parent != clutter_actor_get_parent (below))
11859 g_warning ("%s Actor '%s' is not in the same container as "
11862 _clutter_actor_get_debug_name (self),
11863 _clutter_actor_get_debug_name (below));
11868 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11872 * clutter_actor_lower:
11873 * @self: A #ClutterActor
11874 * @above: (allow-none): A #ClutterActor to lower below
11876 * Puts @self below @above.
11878 * Both actors must have the same parent, and the parent must implement
11879 * the #ClutterContainer interface.
11881 * This function calls clutter_container_lower_child() internally.
11883 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11886 clutter_actor_lower (ClutterActor *self,
11887 ClutterActor *above)
11889 ClutterActor *parent;
11891 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11893 parent = clutter_actor_get_parent (self);
11894 if (parent == NULL)
11896 g_warning ("%s: Actor of type %s is not inside a container",
11898 _clutter_actor_get_debug_name (self));
11904 if (parent != clutter_actor_get_parent (above))
11906 g_warning ("%s: Actor '%s' is not in the same container as "
11909 _clutter_actor_get_debug_name (self),
11910 _clutter_actor_get_debug_name (above));
11915 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11919 * clutter_actor_raise_top:
11920 * @self: A #ClutterActor
11922 * Raises @self to the top.
11924 * This function calls clutter_actor_raise() internally.
11926 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11927 * a %NULL sibling, instead.
11930 clutter_actor_raise_top (ClutterActor *self)
11932 clutter_actor_raise (self, NULL);
11936 * clutter_actor_lower_bottom:
11937 * @self: A #ClutterActor
11939 * Lowers @self to the bottom.
11941 * This function calls clutter_actor_lower() internally.
11943 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11944 * a %NULL sibling, instead.
11947 clutter_actor_lower_bottom (ClutterActor *self)
11949 clutter_actor_lower (self, NULL);
11957 * clutter_actor_event:
11958 * @actor: a #ClutterActor
11959 * @event: a #ClutterEvent
11960 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11962 * This function is used to emit an event on the main stage.
11963 * You should rarely need to use this function, except for
11964 * synthetising events.
11966 * Return value: the return value from the signal emission: %TRUE
11967 * if the actor handled the event, or %FALSE if the event was
11973 clutter_actor_event (ClutterActor *actor,
11974 ClutterEvent *event,
11977 gboolean retval = FALSE;
11978 gint signal_num = -1;
11980 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11981 g_return_val_if_fail (event != NULL, FALSE);
11983 g_object_ref (actor);
11987 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11993 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11997 switch (event->type)
11999 case CLUTTER_NOTHING:
12001 case CLUTTER_BUTTON_PRESS:
12002 signal_num = BUTTON_PRESS_EVENT;
12004 case CLUTTER_BUTTON_RELEASE:
12005 signal_num = BUTTON_RELEASE_EVENT;
12007 case CLUTTER_SCROLL:
12008 signal_num = SCROLL_EVENT;
12010 case CLUTTER_KEY_PRESS:
12011 signal_num = KEY_PRESS_EVENT;
12013 case CLUTTER_KEY_RELEASE:
12014 signal_num = KEY_RELEASE_EVENT;
12016 case CLUTTER_MOTION:
12017 signal_num = MOTION_EVENT;
12019 case CLUTTER_ENTER:
12020 signal_num = ENTER_EVENT;
12022 case CLUTTER_LEAVE:
12023 signal_num = LEAVE_EVENT;
12025 case CLUTTER_DELETE:
12026 case CLUTTER_DESTROY_NOTIFY:
12027 case CLUTTER_CLIENT_MESSAGE:
12033 if (signal_num != -1)
12034 g_signal_emit (actor, actor_signals[signal_num], 0,
12039 g_object_unref (actor);
12045 * clutter_actor_set_reactive:
12046 * @actor: a #ClutterActor
12047 * @reactive: whether the actor should be reactive to events
12049 * Sets @actor as reactive. Reactive actors will receive events.
12054 clutter_actor_set_reactive (ClutterActor *actor,
12057 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12059 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12063 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12065 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12067 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12071 * clutter_actor_get_reactive:
12072 * @actor: a #ClutterActor
12074 * Checks whether @actor is marked as reactive.
12076 * Return value: %TRUE if the actor is reactive
12081 clutter_actor_get_reactive (ClutterActor *actor)
12083 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12085 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12089 * clutter_actor_get_anchor_point:
12090 * @self: a #ClutterActor
12091 * @anchor_x: (out): return location for the X coordinate of the anchor point
12092 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12094 * Gets the current anchor point of the @actor in pixels.
12099 clutter_actor_get_anchor_point (ClutterActor *self,
12103 const ClutterTransformInfo *info;
12105 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12107 info = _clutter_actor_get_transform_info_or_defaults (self);
12108 clutter_anchor_coord_get_units (self, &info->anchor,
12115 * clutter_actor_set_anchor_point:
12116 * @self: a #ClutterActor
12117 * @anchor_x: X coordinate of the anchor point
12118 * @anchor_y: Y coordinate of the anchor point
12120 * Sets an anchor point for @self. The anchor point is a point in the
12121 * coordinate space of an actor to which the actor position within its
12122 * parent is relative; the default is (0, 0), i.e. the top-left corner
12128 clutter_actor_set_anchor_point (ClutterActor *self,
12132 ClutterTransformInfo *info;
12133 ClutterActorPrivate *priv;
12134 gboolean changed = FALSE;
12135 gfloat old_anchor_x, old_anchor_y;
12138 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12140 obj = G_OBJECT (self);
12142 info = _clutter_actor_get_transform_info (self);
12144 g_object_freeze_notify (obj);
12146 clutter_anchor_coord_get_units (self, &info->anchor,
12151 if (info->anchor.is_fractional)
12152 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12154 if (old_anchor_x != anchor_x)
12156 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12160 if (old_anchor_y != anchor_y)
12162 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12166 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12170 priv->transform_valid = FALSE;
12171 clutter_actor_queue_redraw (self);
12174 g_object_thaw_notify (obj);
12178 * clutter_actor_get_anchor_point_gravity:
12179 * @self: a #ClutterActor
12181 * Retrieves the anchor position expressed as a #ClutterGravity. If
12182 * the anchor point was specified using pixels or units this will
12183 * return %CLUTTER_GRAVITY_NONE.
12185 * Return value: the #ClutterGravity used by the anchor point
12190 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12192 const ClutterTransformInfo *info;
12194 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12196 info = _clutter_actor_get_transform_info_or_defaults (self);
12198 return clutter_anchor_coord_get_gravity (&info->anchor);
12202 * clutter_actor_move_anchor_point:
12203 * @self: a #ClutterActor
12204 * @anchor_x: X coordinate of the anchor point
12205 * @anchor_y: Y coordinate of the anchor point
12207 * Sets an anchor point for the actor, and adjusts the actor postion so that
12208 * the relative position of the actor toward its parent remains the same.
12213 clutter_actor_move_anchor_point (ClutterActor *self,
12217 gfloat old_anchor_x, old_anchor_y;
12218 const ClutterTransformInfo *info;
12220 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12222 info = _clutter_actor_get_transform_info (self);
12223 clutter_anchor_coord_get_units (self, &info->anchor,
12228 g_object_freeze_notify (G_OBJECT (self));
12230 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12232 if (self->priv->position_set)
12233 clutter_actor_move_by (self,
12234 anchor_x - old_anchor_x,
12235 anchor_y - old_anchor_y);
12237 g_object_thaw_notify (G_OBJECT (self));
12241 * clutter_actor_move_anchor_point_from_gravity:
12242 * @self: a #ClutterActor
12243 * @gravity: #ClutterGravity.
12245 * Sets an anchor point on the actor based on the given gravity, adjusting the
12246 * actor postion so that its relative position within its parent remains
12249 * Since version 1.0 the anchor point will be stored as a gravity so
12250 * that if the actor changes size then the anchor point will move. For
12251 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12252 * and later double the size of the actor, the anchor point will move
12253 * to the bottom right.
12258 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12259 ClutterGravity gravity)
12261 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12262 const ClutterTransformInfo *info;
12263 ClutterActorPrivate *priv;
12265 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12268 info = _clutter_actor_get_transform_info (self);
12270 g_object_freeze_notify (G_OBJECT (self));
12272 clutter_anchor_coord_get_units (self, &info->anchor,
12276 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12277 clutter_anchor_coord_get_units (self, &info->anchor,
12282 if (priv->position_set)
12283 clutter_actor_move_by (self,
12284 new_anchor_x - old_anchor_x,
12285 new_anchor_y - old_anchor_y);
12287 g_object_thaw_notify (G_OBJECT (self));
12291 * clutter_actor_set_anchor_point_from_gravity:
12292 * @self: a #ClutterActor
12293 * @gravity: #ClutterGravity.
12295 * Sets an anchor point on the actor, based on the given gravity (this is a
12296 * convenience function wrapping clutter_actor_set_anchor_point()).
12298 * Since version 1.0 the anchor point will be stored as a gravity so
12299 * that if the actor changes size then the anchor point will move. For
12300 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12301 * and later double the size of the actor, the anchor point will move
12302 * to the bottom right.
12307 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12308 ClutterGravity gravity)
12310 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12312 if (gravity == CLUTTER_GRAVITY_NONE)
12313 clutter_actor_set_anchor_point (self, 0, 0);
12316 GObject *obj = G_OBJECT (self);
12317 ClutterTransformInfo *info;
12319 g_object_freeze_notify (obj);
12321 info = _clutter_actor_get_transform_info (self);
12322 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12324 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12325 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12326 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12328 self->priv->transform_valid = FALSE;
12330 clutter_actor_queue_redraw (self);
12332 g_object_thaw_notify (obj);
12337 clutter_actor_store_content_box (ClutterActor *self,
12338 const ClutterActorBox *box)
12342 self->priv->content_box = *box;
12343 self->priv->content_box_valid = TRUE;
12346 self->priv->content_box_valid = FALSE;
12348 clutter_actor_queue_redraw (self);
12350 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12354 clutter_container_iface_init (ClutterContainerIface *iface)
12356 /* we don't override anything, as ClutterContainer already has a default
12357 * implementation that we can use, and which calls into our own API.
12372 parse_units (ClutterActor *self,
12373 ParseDimension dimension,
12376 GValue value = G_VALUE_INIT;
12379 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12382 json_node_get_value (node, &value);
12384 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12386 retval = (gfloat) g_value_get_int64 (&value);
12388 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12390 retval = g_value_get_double (&value);
12392 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12394 ClutterUnits units;
12397 res = clutter_units_from_string (&units, g_value_get_string (&value));
12399 retval = clutter_units_to_pixels (&units);
12402 g_warning ("Invalid value '%s': integers, strings or floating point "
12403 "values can be used for the x, y, width and height "
12404 "properties. Valid modifiers for strings are 'px', 'mm', "
12406 g_value_get_string (&value));
12412 g_warning ("Invalid value of type '%s': integers, strings of floating "
12413 "point values can be used for the x, y, width, height "
12414 "anchor-x and anchor-y properties.",
12415 g_type_name (G_VALUE_TYPE (&value)));
12418 g_value_unset (&value);
12424 ClutterRotateAxis axis;
12433 static inline gboolean
12434 parse_rotation_array (ClutterActor *actor,
12436 RotationInfo *info)
12440 if (json_array_get_length (array) != 2)
12444 element = json_array_get_element (array, 0);
12445 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12446 info->angle = json_node_get_double (element);
12451 element = json_array_get_element (array, 1);
12452 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12454 JsonArray *center = json_node_get_array (element);
12456 if (json_array_get_length (center) != 2)
12459 switch (info->axis)
12461 case CLUTTER_X_AXIS:
12462 info->center_y = parse_units (actor, PARSE_Y,
12463 json_array_get_element (center, 0));
12464 info->center_z = parse_units (actor, PARSE_Y,
12465 json_array_get_element (center, 1));
12468 case CLUTTER_Y_AXIS:
12469 info->center_x = parse_units (actor, PARSE_X,
12470 json_array_get_element (center, 0));
12471 info->center_z = parse_units (actor, PARSE_X,
12472 json_array_get_element (center, 1));
12475 case CLUTTER_Z_AXIS:
12476 info->center_x = parse_units (actor, PARSE_X,
12477 json_array_get_element (center, 0));
12478 info->center_y = parse_units (actor, PARSE_Y,
12479 json_array_get_element (center, 1));
12488 parse_rotation (ClutterActor *actor,
12490 RotationInfo *info)
12494 gboolean retval = FALSE;
12496 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12498 g_warning ("Invalid node of type '%s' found, expecting an array",
12499 json_node_type_name (node));
12503 array = json_node_get_array (node);
12504 len = json_array_get_length (array);
12506 for (i = 0; i < len; i++)
12508 JsonNode *element = json_array_get_element (array, i);
12509 JsonObject *object;
12512 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12514 g_warning ("Invalid node of type '%s' found, expecting an object",
12515 json_node_type_name (element));
12519 object = json_node_get_object (element);
12521 if (json_object_has_member (object, "x-axis"))
12523 member = json_object_get_member (object, "x-axis");
12525 info->axis = CLUTTER_X_AXIS;
12527 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12529 info->angle = json_node_get_double (member);
12532 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12533 retval = parse_rotation_array (actor,
12534 json_node_get_array (member),
12539 else if (json_object_has_member (object, "y-axis"))
12541 member = json_object_get_member (object, "y-axis");
12543 info->axis = CLUTTER_Y_AXIS;
12545 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12547 info->angle = json_node_get_double (member);
12550 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12551 retval = parse_rotation_array (actor,
12552 json_node_get_array (member),
12557 else if (json_object_has_member (object, "z-axis"))
12559 member = json_object_get_member (object, "z-axis");
12561 info->axis = CLUTTER_Z_AXIS;
12563 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12565 info->angle = json_node_get_double (member);
12568 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12569 retval = parse_rotation_array (actor,
12570 json_node_get_array (member),
12581 parse_actor_metas (ClutterScript *script,
12582 ClutterActor *actor,
12585 GList *elements, *l;
12586 GSList *retval = NULL;
12588 if (!JSON_NODE_HOLDS_ARRAY (node))
12591 elements = json_array_get_elements (json_node_get_array (node));
12593 for (l = elements; l != NULL; l = l->next)
12595 JsonNode *element = l->data;
12596 const gchar *id_ = _clutter_script_get_id_from_node (element);
12599 if (id_ == NULL || *id_ == '\0')
12602 meta = clutter_script_get_object (script, id_);
12606 retval = g_slist_prepend (retval, meta);
12609 g_list_free (elements);
12611 return g_slist_reverse (retval);
12615 parse_behaviours (ClutterScript *script,
12616 ClutterActor *actor,
12619 GList *elements, *l;
12620 GSList *retval = NULL;
12622 if (!JSON_NODE_HOLDS_ARRAY (node))
12625 elements = json_array_get_elements (json_node_get_array (node));
12627 for (l = elements; l != NULL; l = l->next)
12629 JsonNode *element = l->data;
12630 const gchar *id_ = _clutter_script_get_id_from_node (element);
12631 GObject *behaviour;
12633 if (id_ == NULL || *id_ == '\0')
12636 behaviour = clutter_script_get_object (script, id_);
12637 if (behaviour == NULL)
12640 retval = g_slist_prepend (retval, behaviour);
12643 g_list_free (elements);
12645 return g_slist_reverse (retval);
12649 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12650 ClutterScript *script,
12655 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12656 gboolean retval = FALSE;
12658 if ((name[0] == 'x' && name[1] == '\0') ||
12659 (name[0] == 'y' && name[1] == '\0') ||
12660 (strcmp (name, "width") == 0) ||
12661 (strcmp (name, "height") == 0) ||
12662 (strcmp (name, "anchor_x") == 0) ||
12663 (strcmp (name, "anchor_y") == 0))
12665 ParseDimension dimension;
12668 if (name[0] == 'x')
12669 dimension = PARSE_X;
12670 else if (name[0] == 'y')
12671 dimension = PARSE_Y;
12672 else if (name[0] == 'w')
12673 dimension = PARSE_WIDTH;
12674 else if (name[0] == 'h')
12675 dimension = PARSE_HEIGHT;
12676 else if (name[0] == 'a' && name[7] == 'x')
12677 dimension = PARSE_ANCHOR_X;
12678 else if (name[0] == 'a' && name[7] == 'y')
12679 dimension = PARSE_ANCHOR_Y;
12683 units = parse_units (actor, dimension, node);
12685 /* convert back to pixels: all properties are pixel-based */
12686 g_value_init (value, G_TYPE_FLOAT);
12687 g_value_set_float (value, units);
12691 else if (strcmp (name, "rotation") == 0)
12693 RotationInfo *info;
12695 info = g_slice_new0 (RotationInfo);
12696 retval = parse_rotation (actor, node, info);
12700 g_value_init (value, G_TYPE_POINTER);
12701 g_value_set_pointer (value, info);
12704 g_slice_free (RotationInfo, info);
12706 else if (strcmp (name, "behaviours") == 0)
12710 #ifdef CLUTTER_ENABLE_DEBUG
12711 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12712 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12713 "and it should not be used in newly "
12714 "written ClutterScript definitions.");
12717 l = parse_behaviours (script, actor, node);
12719 g_value_init (value, G_TYPE_POINTER);
12720 g_value_set_pointer (value, l);
12724 else if (strcmp (name, "actions") == 0 ||
12725 strcmp (name, "constraints") == 0 ||
12726 strcmp (name, "effects") == 0)
12730 l = parse_actor_metas (script, actor, node);
12732 g_value_init (value, G_TYPE_POINTER);
12733 g_value_set_pointer (value, l);
12742 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12743 ClutterScript *script,
12745 const GValue *value)
12747 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12749 #ifdef CLUTTER_ENABLE_DEBUG
12750 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12752 gchar *tmp = g_strdup_value_contents (value);
12754 CLUTTER_NOTE (SCRIPT,
12755 "in ClutterActor::set_custom_property('%s') = %s",
12761 #endif /* CLUTTER_ENABLE_DEBUG */
12763 if (strcmp (name, "rotation") == 0)
12765 RotationInfo *info;
12767 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12770 info = g_value_get_pointer (value);
12772 clutter_actor_set_rotation (actor,
12773 info->axis, info->angle,
12778 g_slice_free (RotationInfo, info);
12783 if (strcmp (name, "behaviours") == 0)
12785 GSList *behaviours, *l;
12787 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12790 behaviours = g_value_get_pointer (value);
12791 for (l = behaviours; l != NULL; l = l->next)
12793 ClutterBehaviour *behaviour = l->data;
12795 clutter_behaviour_apply (behaviour, actor);
12798 g_slist_free (behaviours);
12803 if (strcmp (name, "actions") == 0 ||
12804 strcmp (name, "constraints") == 0 ||
12805 strcmp (name, "effects") == 0)
12809 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12812 metas = g_value_get_pointer (value);
12813 for (l = metas; l != NULL; l = l->next)
12815 if (name[0] == 'a')
12816 clutter_actor_add_action (actor, l->data);
12818 if (name[0] == 'c')
12819 clutter_actor_add_constraint (actor, l->data);
12821 if (name[0] == 'e')
12822 clutter_actor_add_effect (actor, l->data);
12825 g_slist_free (metas);
12830 g_object_set_property (G_OBJECT (scriptable), name, value);
12834 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12836 iface->parse_custom_node = clutter_actor_parse_custom_node;
12837 iface->set_custom_property = clutter_actor_set_custom_property;
12840 static ClutterActorMeta *
12841 get_meta_from_animation_property (ClutterActor *actor,
12845 ClutterActorPrivate *priv = actor->priv;
12846 ClutterActorMeta *meta = NULL;
12849 /* if this is not a special property, fall through */
12850 if (name[0] != '@')
12853 /* detect the properties named using the following spec:
12855 * @<section>.<meta-name>.<property-name>
12857 * where <section> can be one of the following:
12863 * and <meta-name> is the name set on a specific ActorMeta
12866 tokens = g_strsplit (name + 1, ".", -1);
12867 if (tokens == NULL || g_strv_length (tokens) != 3)
12869 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12871 g_strfreev (tokens);
12875 if (strcmp (tokens[0], "actions") == 0)
12876 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12878 if (strcmp (tokens[0], "constraints") == 0)
12879 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12881 if (strcmp (tokens[0], "effects") == 0)
12882 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12884 if (name_p != NULL)
12885 *name_p = g_strdup (tokens[2]);
12887 CLUTTER_NOTE (ANIMATION,
12888 "Looking for property '%s' of object '%s' in section '%s'",
12893 g_strfreev (tokens);
12898 static GParamSpec *
12899 clutter_actor_find_property (ClutterAnimatable *animatable,
12900 const gchar *property_name)
12902 ClutterActorMeta *meta = NULL;
12903 GObjectClass *klass = NULL;
12904 GParamSpec *pspec = NULL;
12905 gchar *p_name = NULL;
12907 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12913 klass = G_OBJECT_GET_CLASS (meta);
12915 pspec = g_object_class_find_property (klass, p_name);
12919 klass = G_OBJECT_GET_CLASS (animatable);
12921 pspec = g_object_class_find_property (klass, property_name);
12930 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12931 const gchar *property_name,
12934 ClutterActorMeta *meta = NULL;
12935 gchar *p_name = NULL;
12937 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12942 g_object_get_property (G_OBJECT (meta), p_name, initial);
12944 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12950 * clutter_actor_set_animatable_property:
12951 * @actor: a #ClutterActor
12952 * @prop_id: the paramspec id
12953 * @value: the value to set
12954 * @pspec: the paramspec
12956 * Sets values of animatable properties.
12958 * This is a variant of clutter_actor_set_property() that gets called
12959 * by the #ClutterAnimatable implementation of #ClutterActor for the
12960 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12963 * Unlike the implementation of #GObjectClass.set_property(), this
12964 * function will not update the interval if a transition involving an
12965 * animatable property is in progress - this avoids cycles with the
12966 * transition API calling the public API.
12969 clutter_actor_set_animatable_property (ClutterActor *actor,
12971 const GValue *value,
12974 GObject *obj = G_OBJECT (actor);
12976 g_object_freeze_notify (obj);
12981 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12985 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12989 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12993 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12997 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13001 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13004 case PROP_BACKGROUND_COLOR:
13005 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13009 clutter_actor_set_scale_factor_internal (actor,
13010 g_value_get_double (value),
13015 clutter_actor_set_scale_factor_internal (actor,
13016 g_value_get_double (value),
13020 case PROP_ROTATION_ANGLE_X:
13021 clutter_actor_set_rotation_angle_internal (actor,
13023 g_value_get_double (value));
13026 case PROP_ROTATION_ANGLE_Y:
13027 clutter_actor_set_rotation_angle_internal (actor,
13029 g_value_get_double (value));
13032 case PROP_ROTATION_ANGLE_Z:
13033 clutter_actor_set_rotation_angle_internal (actor,
13035 g_value_get_double (value));
13038 case PROP_CONTENT_BOX:
13039 clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13043 g_object_set_property (obj, pspec->name, value);
13047 g_object_thaw_notify (obj);
13051 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13052 const gchar *property_name,
13053 const GValue *final)
13055 ClutterActor *actor = CLUTTER_ACTOR (animatable);
13056 ClutterActorMeta *meta = NULL;
13057 gchar *p_name = NULL;
13059 meta = get_meta_from_animation_property (actor,
13063 g_object_set_property (G_OBJECT (meta), p_name, final);
13066 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13069 pspec = g_object_class_find_property (obj_class, property_name);
13071 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13073 /* XXX - I'm going to the special hell for this */
13074 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13077 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13084 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13086 iface->find_property = clutter_actor_find_property;
13087 iface->get_initial_state = clutter_actor_get_initial_state;
13088 iface->set_final_state = clutter_actor_set_final_state;
13092 * clutter_actor_transform_stage_point:
13093 * @self: A #ClutterActor
13094 * @x: (in): x screen coordinate of the point to unproject
13095 * @y: (in): y screen coordinate of the point to unproject
13096 * @x_out: (out): return location for the unprojected x coordinance
13097 * @y_out: (out): return location for the unprojected y coordinance
13099 * This function translates screen coordinates (@x, @y) to
13100 * coordinates relative to the actor. For example, it can be used to translate
13101 * screen events from global screen coordinates into actor-local coordinates.
13103 * The conversion can fail, notably if the transform stack results in the
13104 * actor being projected on the screen as a mere line.
13106 * The conversion should not be expected to be pixel-perfect due to the
13107 * nature of the operation. In general the error grows when the skewing
13108 * of the actor rectangle on screen increases.
13110 * <note><para>This function can be computationally intensive.</para></note>
13112 * <note><para>This function only works when the allocation is up-to-date,
13113 * i.e. inside of paint().</para></note>
13115 * Return value: %TRUE if conversion was successful.
13120 clutter_actor_transform_stage_point (ClutterActor *self,
13126 ClutterVertex v[4];
13129 int du, dv, xi, yi;
13131 float xf, yf, wf, det;
13132 ClutterActorPrivate *priv;
13134 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13138 /* This implementation is based on the quad -> quad projection algorithm
13139 * described by Paul Heckbert in:
13141 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13143 * and the sample implementation at:
13145 * http://www.cs.cmu.edu/~ph/src/texfund/
13147 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13148 * quad to rectangle only, which significantly simplifies things; the
13149 * function calls have been unrolled, and most of the math is done in fixed
13153 clutter_actor_get_abs_allocation_vertices (self, v);
13155 /* Keeping these as ints simplifies the multiplication (no significant
13156 * loss of precision here).
13158 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13159 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13164 #define UX2FP(x) (x)
13165 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13167 /* First, find mapping from unit uv square to xy quadrilateral; this
13168 * equivalent to the pmap_square_quad() functions in the sample
13169 * implementation, which we can simplify, since our target is always
13172 px = v[0].x - v[1].x + v[3].x - v[2].x;
13173 py = v[0].y - v[1].y + v[3].y - v[2].y;
13177 /* affine transform */
13178 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13179 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13180 RQ[2][0] = UX2FP (v[0].x);
13181 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13182 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13183 RQ[2][1] = UX2FP (v[0].y);
13190 /* projective transform */
13191 double dx1, dx2, dy1, dy2, del;
13193 dx1 = UX2FP (v[1].x - v[3].x);
13194 dx2 = UX2FP (v[2].x - v[3].x);
13195 dy1 = UX2FP (v[1].y - v[3].y);
13196 dy2 = UX2FP (v[2].y - v[3].y);
13198 del = DET2FP (dx1, dx2, dy1, dy2);
13203 * The division here needs to be done in floating point for
13204 * precisions reasons.
13206 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13207 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13208 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13210 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13211 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13212 RQ[2][0] = UX2FP (v[0].x);
13213 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13214 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13215 RQ[2][1] = UX2FP (v[0].y);
13219 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13220 * square. Since our rectangle is based at 0,0 we only need to scale.
13230 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13233 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13234 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13235 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13236 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13237 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13238 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13239 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13240 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13241 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13244 * Check the resulting matrix is OK.
13246 det = (RQ[0][0] * ST[0][0])
13247 + (RQ[0][1] * ST[0][1])
13248 + (RQ[0][2] * ST[0][2]);
13253 * Now transform our point with the ST matrix; the notional w
13254 * coordinate is 1, hence the last part is simply added.
13259 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13260 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13261 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13279 static ClutterGeometry*
13280 clutter_geometry_copy (const ClutterGeometry *geometry)
13282 return g_slice_dup (ClutterGeometry, geometry);
13286 clutter_geometry_free (ClutterGeometry *geometry)
13288 if (G_LIKELY (geometry != NULL))
13289 g_slice_free (ClutterGeometry, geometry);
13293 * clutter_geometry_union:
13294 * @geometry_a: a #ClutterGeometry
13295 * @geometry_b: another #ClutterGeometry
13296 * @result: (out): location to store the result
13298 * Find the union of two rectangles represented as #ClutterGeometry.
13303 clutter_geometry_union (const ClutterGeometry *geometry_a,
13304 const ClutterGeometry *geometry_b,
13305 ClutterGeometry *result)
13307 /* We don't try to handle rectangles that can't be represented
13308 * as a signed integer box */
13309 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13310 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13311 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13312 geometry_b->x + (gint)geometry_b->width);
13313 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13314 geometry_b->y + (gint)geometry_b->height);
13317 result->width = x_2 - x_1;
13318 result->height = y_2 - y_1;
13322 * clutter_geometry_intersects:
13323 * @geometry0: The first geometry to test
13324 * @geometry1: The second geometry to test
13326 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13327 * they do else %FALSE.
13329 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13335 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13336 const ClutterGeometry *geometry1)
13338 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13339 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13340 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13341 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13348 clutter_geometry_progress (const GValue *a,
13353 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13354 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13355 ClutterGeometry res = { 0, };
13356 gint a_width = a_geom->width;
13357 gint b_width = b_geom->width;
13358 gint a_height = a_geom->height;
13359 gint b_height = b_geom->height;
13361 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13362 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13364 res.width = a_width + (b_width - a_width) * progress;
13365 res.height = a_height + (b_height - a_height) * progress;
13367 g_value_set_boxed (retval, &res);
13372 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13373 clutter_geometry_copy,
13374 clutter_geometry_free,
13375 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13382 * clutter_vertex_new:
13387 * Creates a new #ClutterVertex for the point in 3D space
13388 * identified by the 3 coordinates @x, @y, @z
13390 * Return value: the newly allocate #ClutterVertex. Use
13391 * clutter_vertex_free() to free the resources
13396 clutter_vertex_new (gfloat x,
13400 ClutterVertex *vertex;
13402 vertex = g_slice_new (ClutterVertex);
13403 clutter_vertex_init (vertex, x, y, z);
13409 * clutter_vertex_init:
13410 * @vertex: a #ClutterVertex
13415 * Initializes @vertex with the given coordinates.
13420 clutter_vertex_init (ClutterVertex *vertex,
13425 g_return_if_fail (vertex != NULL);
13433 * clutter_vertex_copy:
13434 * @vertex: a #ClutterVertex
13438 * Return value: a newly allocated copy of #ClutterVertex. Use
13439 * clutter_vertex_free() to free the allocated resources
13444 clutter_vertex_copy (const ClutterVertex *vertex)
13446 if (G_LIKELY (vertex != NULL))
13447 return g_slice_dup (ClutterVertex, vertex);
13453 * clutter_vertex_free:
13454 * @vertex: a #ClutterVertex
13456 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13461 clutter_vertex_free (ClutterVertex *vertex)
13463 if (G_UNLIKELY (vertex != NULL))
13464 g_slice_free (ClutterVertex, vertex);
13468 * clutter_vertex_equal:
13469 * @vertex_a: a #ClutterVertex
13470 * @vertex_b: a #ClutterVertex
13472 * Compares @vertex_a and @vertex_b for equality
13474 * Return value: %TRUE if the passed #ClutterVertex are equal
13479 clutter_vertex_equal (const ClutterVertex *vertex_a,
13480 const ClutterVertex *vertex_b)
13482 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13484 if (vertex_a == vertex_b)
13487 return vertex_a->x == vertex_b->x &&
13488 vertex_a->y == vertex_b->y &&
13489 vertex_a->z == vertex_b->z;
13493 clutter_vertex_progress (const GValue *a,
13498 const ClutterVertex *av = g_value_get_boxed (a);
13499 const ClutterVertex *bv = g_value_get_boxed (b);
13500 ClutterVertex res = { 0, };
13502 res.x = av->x + (bv->x - av->x) * progress;
13503 res.y = av->y + (bv->y - av->y) * progress;
13504 res.z = av->z + (bv->z - av->z) * progress;
13506 g_value_set_boxed (retval, &res);
13511 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13512 clutter_vertex_copy,
13513 clutter_vertex_free,
13514 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13517 * clutter_actor_is_rotated:
13518 * @self: a #ClutterActor
13520 * Checks whether any rotation is applied to the actor.
13522 * Return value: %TRUE if the actor is rotated.
13527 clutter_actor_is_rotated (ClutterActor *self)
13529 const ClutterTransformInfo *info;
13531 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13533 info = _clutter_actor_get_transform_info_or_defaults (self);
13535 if (info->rx_angle || info->ry_angle || info->rz_angle)
13542 * clutter_actor_is_scaled:
13543 * @self: a #ClutterActor
13545 * Checks whether the actor is scaled in either dimension.
13547 * Return value: %TRUE if the actor is scaled.
13552 clutter_actor_is_scaled (ClutterActor *self)
13554 const ClutterTransformInfo *info;
13556 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13558 info = _clutter_actor_get_transform_info_or_defaults (self);
13560 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13567 _clutter_actor_get_stage_internal (ClutterActor *actor)
13569 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13570 actor = actor->priv->parent;
13576 * clutter_actor_get_stage:
13577 * @actor: a #ClutterActor
13579 * Retrieves the #ClutterStage where @actor is contained.
13581 * Return value: (transfer none) (type Clutter.Stage): the stage
13582 * containing the actor, or %NULL
13587 clutter_actor_get_stage (ClutterActor *actor)
13589 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13591 return _clutter_actor_get_stage_internal (actor);
13595 * clutter_actor_allocate_available_size:
13596 * @self: a #ClutterActor
13597 * @x: the actor's X coordinate
13598 * @y: the actor's Y coordinate
13599 * @available_width: the maximum available width, or -1 to use the
13600 * actor's natural width
13601 * @available_height: the maximum available height, or -1 to use the
13602 * actor's natural height
13603 * @flags: flags controlling the allocation
13605 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13606 * preferred size, but limiting it to the maximum available width
13607 * and height provided.
13609 * This function will do the right thing when dealing with the
13610 * actor's request mode.
13612 * The implementation of this function is equivalent to:
13615 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13617 * clutter_actor_get_preferred_width (self, available_height,
13619 * &natural_width);
13620 * width = CLAMP (natural_width, min_width, available_width);
13622 * clutter_actor_get_preferred_height (self, width,
13624 * &natural_height);
13625 * height = CLAMP (natural_height, min_height, available_height);
13629 * clutter_actor_get_preferred_height (self, available_width,
13631 * &natural_height);
13632 * height = CLAMP (natural_height, min_height, available_height);
13634 * clutter_actor_get_preferred_width (self, height,
13636 * &natural_width);
13637 * width = CLAMP (natural_width, min_width, available_width);
13640 * box.x1 = x; box.y1 = y;
13641 * box.x2 = box.x1 + available_width;
13642 * box.y2 = box.y1 + available_height;
13643 * clutter_actor_allocate (self, &box, flags);
13646 * This function can be used by fluid layout managers to allocate
13647 * an actor's preferred size without making it bigger than the area
13648 * available for the container.
13653 clutter_actor_allocate_available_size (ClutterActor *self,
13656 gfloat available_width,
13657 gfloat available_height,
13658 ClutterAllocationFlags flags)
13660 ClutterActorPrivate *priv;
13661 gfloat width, height;
13662 gfloat min_width, min_height;
13663 gfloat natural_width, natural_height;
13664 ClutterActorBox box;
13666 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13670 width = height = 0.0;
13672 switch (priv->request_mode)
13674 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13675 clutter_actor_get_preferred_width (self, available_height,
13678 width = CLAMP (natural_width, min_width, available_width);
13680 clutter_actor_get_preferred_height (self, width,
13683 height = CLAMP (natural_height, min_height, available_height);
13686 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13687 clutter_actor_get_preferred_height (self, available_width,
13690 height = CLAMP (natural_height, min_height, available_height);
13692 clutter_actor_get_preferred_width (self, height,
13695 width = CLAMP (natural_width, min_width, available_width);
13702 box.x2 = box.x1 + width;
13703 box.y2 = box.y1 + height;
13704 clutter_actor_allocate (self, &box, flags);
13708 * clutter_actor_allocate_preferred_size:
13709 * @self: a #ClutterActor
13710 * @flags: flags controlling the allocation
13712 * Allocates the natural size of @self.
13714 * This function is a utility call for #ClutterActor implementations
13715 * that allocates the actor's preferred natural size. It can be used
13716 * by fixed layout managers (like #ClutterGroup or so called
13717 * 'composite actors') inside the ClutterActor::allocate
13718 * implementation to give each child exactly how much space it
13721 * This function is not meant to be used by applications. It is also
13722 * not meant to be used outside the implementation of the
13723 * ClutterActor::allocate virtual function.
13728 clutter_actor_allocate_preferred_size (ClutterActor *self,
13729 ClutterAllocationFlags flags)
13731 gfloat actor_x, actor_y;
13732 gfloat natural_width, natural_height;
13733 ClutterActorBox actor_box;
13735 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13737 actor_x = clutter_actor_get_x (self);
13738 actor_y = clutter_actor_get_y (self);
13740 clutter_actor_get_preferred_size (self,
13745 actor_box.x1 = actor_x;
13746 actor_box.y1 = actor_y;
13747 actor_box.x2 = actor_box.x1 + natural_width;
13748 actor_box.y2 = actor_box.y1 + natural_height;
13750 clutter_actor_allocate (self, &actor_box, flags);
13754 * clutter_actor_allocate_align_fill:
13755 * @self: a #ClutterActor
13756 * @box: a #ClutterActorBox, containing the available width and height
13757 * @x_align: the horizontal alignment, between 0 and 1
13758 * @y_align: the vertical alignment, between 0 and 1
13759 * @x_fill: whether the actor should fill horizontally
13760 * @y_fill: whether the actor should fill vertically
13761 * @flags: allocation flags to be passed to clutter_actor_allocate()
13763 * Allocates @self by taking into consideration the available allocation
13764 * area; an alignment factor on either axis; and whether the actor should
13765 * fill the allocation on either axis.
13767 * The @box should contain the available allocation width and height;
13768 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13769 * allocation will be offset by their value.
13771 * This function takes into consideration the geometry request specified by
13772 * the #ClutterActor:request-mode property, and the text direction.
13774 * This function is useful for fluid layout managers, like #ClutterBinLayout
13775 * or #ClutterTableLayout
13780 clutter_actor_allocate_align_fill (ClutterActor *self,
13781 const ClutterActorBox *box,
13786 ClutterAllocationFlags flags)
13788 ClutterActorPrivate *priv;
13789 ClutterActorBox allocation = { 0, };
13790 gfloat x_offset, y_offset;
13791 gfloat available_width, available_height;
13792 gfloat child_width, child_height;
13794 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13795 g_return_if_fail (box != NULL);
13796 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13797 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13801 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13802 clutter_actor_box_get_size (box, &available_width, &available_height);
13804 if (available_width < 0)
13805 available_width = 0;
13807 if (available_height < 0)
13808 available_height = 0;
13812 allocation.x1 = x_offset;
13813 allocation.x2 = allocation.x1 + available_width;
13818 allocation.y1 = y_offset;
13819 allocation.y2 = allocation.y1 + available_height;
13822 /* if we are filling horizontally and vertically then we're done */
13823 if (x_fill && y_fill)
13826 child_width = child_height = 0.0f;
13828 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13830 gfloat min_width, natural_width;
13831 gfloat min_height, natural_height;
13833 clutter_actor_get_preferred_width (self, available_height,
13837 child_width = CLAMP (natural_width, min_width, available_width);
13841 clutter_actor_get_preferred_height (self, child_width,
13845 child_height = CLAMP (natural_height, min_height, available_height);
13850 gfloat min_width, natural_width;
13851 gfloat min_height, natural_height;
13853 clutter_actor_get_preferred_height (self, available_width,
13857 child_height = CLAMP (natural_height, min_height, available_height);
13861 clutter_actor_get_preferred_width (self, child_height,
13865 child_width = CLAMP (natural_width, min_width, available_width);
13869 /* invert the horizontal alignment for RTL languages */
13870 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13871 x_align = 1.0 - x_align;
13875 allocation.x1 = x_offset
13876 + ((available_width - child_width) * x_align);
13877 allocation.x2 = allocation.x1 + child_width;
13882 allocation.y1 = y_offset
13883 + ((available_height - child_height) * y_align);
13884 allocation.y2 = allocation.y1 + child_height;
13888 clutter_actor_box_clamp_to_pixel (&allocation);
13889 clutter_actor_allocate (self, &allocation, flags);
13893 * clutter_actor_grab_key_focus:
13894 * @self: a #ClutterActor
13896 * Sets the key focus of the #ClutterStage including @self
13897 * to this #ClutterActor.
13902 clutter_actor_grab_key_focus (ClutterActor *self)
13904 ClutterActor *stage;
13906 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13908 stage = _clutter_actor_get_stage_internal (self);
13910 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13914 * clutter_actor_get_pango_context:
13915 * @self: a #ClutterActor
13917 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13918 * is already configured using the appropriate font map, resolution
13919 * and font options.
13921 * Unlike clutter_actor_create_pango_context(), this context is owend
13922 * by the #ClutterActor and it will be updated each time the options
13923 * stored by the #ClutterBackend change.
13925 * You can use the returned #PangoContext to create a #PangoLayout
13926 * and render text using cogl_pango_render_layout() to reuse the
13927 * glyphs cache also used by Clutter.
13929 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13930 * The returned #PangoContext is owned by the actor and should not be
13931 * unreferenced by the application code
13936 clutter_actor_get_pango_context (ClutterActor *self)
13938 ClutterActorPrivate *priv;
13940 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13944 if (priv->pango_context != NULL)
13945 return priv->pango_context;
13947 priv->pango_context = _clutter_context_get_pango_context ();
13948 g_object_ref (priv->pango_context);
13950 return priv->pango_context;
13954 * clutter_actor_create_pango_context:
13955 * @self: a #ClutterActor
13957 * Creates a #PangoContext for the given actor. The #PangoContext
13958 * is already configured using the appropriate font map, resolution
13959 * and font options.
13961 * See also clutter_actor_get_pango_context().
13963 * Return value: (transfer full): the newly created #PangoContext.
13964 * Use g_object_unref() on the returned value to deallocate its
13970 clutter_actor_create_pango_context (ClutterActor *self)
13972 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13974 return _clutter_context_create_pango_context ();
13978 * clutter_actor_create_pango_layout:
13979 * @self: a #ClutterActor
13980 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13982 * Creates a new #PangoLayout from the same #PangoContext used
13983 * by the #ClutterActor. The #PangoLayout is already configured
13984 * with the font map, resolution and font options, and the
13987 * If you want to keep around a #PangoLayout created by this
13988 * function you will have to connect to the #ClutterBackend::font-changed
13989 * and #ClutterBackend::resolution-changed signals, and call
13990 * pango_layout_context_changed() in response to them.
13992 * Return value: (transfer full): the newly created #PangoLayout.
13993 * Use g_object_unref() when done
13998 clutter_actor_create_pango_layout (ClutterActor *self,
14001 PangoContext *context;
14002 PangoLayout *layout;
14004 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14006 context = clutter_actor_get_pango_context (self);
14007 layout = pango_layout_new (context);
14010 pango_layout_set_text (layout, text, -1);
14015 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14016 * ClutterOffscreenEffect.
14019 _clutter_actor_set_opacity_override (ClutterActor *self,
14022 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14024 self->priv->opacity_override = opacity;
14028 _clutter_actor_get_opacity_override (ClutterActor *self)
14030 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14032 return self->priv->opacity_override;
14035 /* Allows you to disable applying the actors model view transform during
14036 * a paint. Used by ClutterClone. */
14038 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14041 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14043 self->priv->enable_model_view_transform = enable;
14047 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14050 ClutterActorPrivate *priv;
14052 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14056 priv->enable_paint_unmapped = enable;
14058 if (priv->enable_paint_unmapped)
14060 /* Make sure that the parents of the widget are realized first;
14061 * otherwise checks in clutter_actor_update_map_state() will
14064 clutter_actor_realize (self);
14066 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14070 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14075 clutter_anchor_coord_get_units (ClutterActor *self,
14076 const AnchorCoord *coord,
14081 if (coord->is_fractional)
14083 gfloat actor_width, actor_height;
14085 clutter_actor_get_size (self, &actor_width, &actor_height);
14088 *x = actor_width * coord->v.fraction.x;
14091 *y = actor_height * coord->v.fraction.y;
14099 *x = coord->v.units.x;
14102 *y = coord->v.units.y;
14105 *z = coord->v.units.z;
14110 clutter_anchor_coord_set_units (AnchorCoord *coord,
14115 coord->is_fractional = FALSE;
14116 coord->v.units.x = x;
14117 coord->v.units.y = y;
14118 coord->v.units.z = z;
14121 static ClutterGravity
14122 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14124 if (coord->is_fractional)
14126 if (coord->v.fraction.x == 0.0)
14128 if (coord->v.fraction.y == 0.0)
14129 return CLUTTER_GRAVITY_NORTH_WEST;
14130 else if (coord->v.fraction.y == 0.5)
14131 return CLUTTER_GRAVITY_WEST;
14132 else if (coord->v.fraction.y == 1.0)
14133 return CLUTTER_GRAVITY_SOUTH_WEST;
14135 return CLUTTER_GRAVITY_NONE;
14137 else if (coord->v.fraction.x == 0.5)
14139 if (coord->v.fraction.y == 0.0)
14140 return CLUTTER_GRAVITY_NORTH;
14141 else if (coord->v.fraction.y == 0.5)
14142 return CLUTTER_GRAVITY_CENTER;
14143 else if (coord->v.fraction.y == 1.0)
14144 return CLUTTER_GRAVITY_SOUTH;
14146 return CLUTTER_GRAVITY_NONE;
14148 else if (coord->v.fraction.x == 1.0)
14150 if (coord->v.fraction.y == 0.0)
14151 return CLUTTER_GRAVITY_NORTH_EAST;
14152 else if (coord->v.fraction.y == 0.5)
14153 return CLUTTER_GRAVITY_EAST;
14154 else if (coord->v.fraction.y == 1.0)
14155 return CLUTTER_GRAVITY_SOUTH_EAST;
14157 return CLUTTER_GRAVITY_NONE;
14160 return CLUTTER_GRAVITY_NONE;
14163 return CLUTTER_GRAVITY_NONE;
14167 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14168 ClutterGravity gravity)
14172 case CLUTTER_GRAVITY_NORTH:
14173 coord->v.fraction.x = 0.5;
14174 coord->v.fraction.y = 0.0;
14177 case CLUTTER_GRAVITY_NORTH_EAST:
14178 coord->v.fraction.x = 1.0;
14179 coord->v.fraction.y = 0.0;
14182 case CLUTTER_GRAVITY_EAST:
14183 coord->v.fraction.x = 1.0;
14184 coord->v.fraction.y = 0.5;
14187 case CLUTTER_GRAVITY_SOUTH_EAST:
14188 coord->v.fraction.x = 1.0;
14189 coord->v.fraction.y = 1.0;
14192 case CLUTTER_GRAVITY_SOUTH:
14193 coord->v.fraction.x = 0.5;
14194 coord->v.fraction.y = 1.0;
14197 case CLUTTER_GRAVITY_SOUTH_WEST:
14198 coord->v.fraction.x = 0.0;
14199 coord->v.fraction.y = 1.0;
14202 case CLUTTER_GRAVITY_WEST:
14203 coord->v.fraction.x = 0.0;
14204 coord->v.fraction.y = 0.5;
14207 case CLUTTER_GRAVITY_NORTH_WEST:
14208 coord->v.fraction.x = 0.0;
14209 coord->v.fraction.y = 0.0;
14212 case CLUTTER_GRAVITY_CENTER:
14213 coord->v.fraction.x = 0.5;
14214 coord->v.fraction.y = 0.5;
14218 coord->v.fraction.x = 0.0;
14219 coord->v.fraction.y = 0.0;
14223 coord->is_fractional = TRUE;
14227 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14229 if (coord->is_fractional)
14230 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14232 return (coord->v.units.x == 0.0
14233 && coord->v.units.y == 0.0
14234 && coord->v.units.z == 0.0);
14238 * clutter_actor_get_flags:
14239 * @self: a #ClutterActor
14241 * Retrieves the flags set on @self
14243 * Return value: a bitwise or of #ClutterActorFlags or 0
14248 clutter_actor_get_flags (ClutterActor *self)
14250 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14252 return self->flags;
14256 * clutter_actor_set_flags:
14257 * @self: a #ClutterActor
14258 * @flags: the flags to set
14260 * Sets @flags on @self
14262 * This function will emit notifications for the changed properties
14267 clutter_actor_set_flags (ClutterActor *self,
14268 ClutterActorFlags flags)
14270 ClutterActorFlags old_flags;
14272 gboolean was_reactive_set, reactive_set;
14273 gboolean was_realized_set, realized_set;
14274 gboolean was_mapped_set, mapped_set;
14275 gboolean was_visible_set, visible_set;
14277 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14279 if (self->flags == flags)
14282 obj = G_OBJECT (self);
14283 g_object_ref (obj);
14284 g_object_freeze_notify (obj);
14286 old_flags = self->flags;
14288 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14289 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14290 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14291 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14293 self->flags |= flags;
14295 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14296 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14297 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14298 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14300 if (reactive_set != was_reactive_set)
14301 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14303 if (realized_set != was_realized_set)
14304 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14306 if (mapped_set != was_mapped_set)
14307 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14309 if (visible_set != was_visible_set)
14310 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14312 g_object_thaw_notify (obj);
14313 g_object_unref (obj);
14317 * clutter_actor_unset_flags:
14318 * @self: a #ClutterActor
14319 * @flags: the flags to unset
14321 * Unsets @flags on @self
14323 * This function will emit notifications for the changed properties
14328 clutter_actor_unset_flags (ClutterActor *self,
14329 ClutterActorFlags flags)
14331 ClutterActorFlags old_flags;
14333 gboolean was_reactive_set, reactive_set;
14334 gboolean was_realized_set, realized_set;
14335 gboolean was_mapped_set, mapped_set;
14336 gboolean was_visible_set, visible_set;
14338 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14340 obj = G_OBJECT (self);
14341 g_object_freeze_notify (obj);
14343 old_flags = self->flags;
14345 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14346 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14347 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14348 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14350 self->flags &= ~flags;
14352 if (self->flags == old_flags)
14355 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14356 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14357 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14358 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14360 if (reactive_set != was_reactive_set)
14361 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14363 if (realized_set != was_realized_set)
14364 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14366 if (mapped_set != was_mapped_set)
14367 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14369 if (visible_set != was_visible_set)
14370 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14372 g_object_thaw_notify (obj);
14376 * clutter_actor_get_transformation_matrix:
14377 * @self: a #ClutterActor
14378 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14380 * Retrieves the transformations applied to @self relative to its
14386 clutter_actor_get_transformation_matrix (ClutterActor *self,
14387 CoglMatrix *matrix)
14389 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14391 cogl_matrix_init_identity (matrix);
14393 _clutter_actor_apply_modelview_transform (self, matrix);
14397 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14398 gboolean is_in_clone_paint)
14400 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14401 self->priv->in_clone_paint = is_in_clone_paint;
14405 * clutter_actor_is_in_clone_paint:
14406 * @self: a #ClutterActor
14408 * Checks whether @self is being currently painted by a #ClutterClone
14410 * This function is useful only inside the ::paint virtual function
14411 * implementations or within handlers for the #ClutterActor::paint
14414 * This function should not be used by applications
14416 * Return value: %TRUE if the #ClutterActor is currently being painted
14417 * by a #ClutterClone, and %FALSE otherwise
14422 clutter_actor_is_in_clone_paint (ClutterActor *self)
14424 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14426 return self->priv->in_clone_paint;
14430 set_direction_recursive (ClutterActor *actor,
14431 gpointer user_data)
14433 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14435 clutter_actor_set_text_direction (actor, text_dir);
14441 * clutter_actor_set_text_direction:
14442 * @self: a #ClutterActor
14443 * @text_dir: the text direction for @self
14445 * Sets the #ClutterTextDirection for an actor
14447 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14449 * If @self implements #ClutterContainer then this function will recurse
14450 * inside all the children of @self (including the internal ones).
14452 * Composite actors not implementing #ClutterContainer, or actors requiring
14453 * special handling when the text direction changes, should connect to
14454 * the #GObject::notify signal for the #ClutterActor:text-direction property
14459 clutter_actor_set_text_direction (ClutterActor *self,
14460 ClutterTextDirection text_dir)
14462 ClutterActorPrivate *priv;
14464 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14465 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14469 if (priv->text_direction != text_dir)
14471 priv->text_direction = text_dir;
14473 /* we need to emit the notify::text-direction first, so that
14474 * the sub-classes can catch that and do specific handling of
14475 * the text direction; see clutter_text_direction_changed_cb()
14476 * inside clutter-text.c
14478 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14480 _clutter_actor_foreach_child (self, set_direction_recursive,
14481 GINT_TO_POINTER (text_dir));
14483 clutter_actor_queue_relayout (self);
14488 _clutter_actor_set_has_pointer (ClutterActor *self,
14489 gboolean has_pointer)
14491 ClutterActorPrivate *priv = self->priv;
14493 if (priv->has_pointer != has_pointer)
14495 priv->has_pointer = has_pointer;
14497 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14502 * clutter_actor_get_text_direction:
14503 * @self: a #ClutterActor
14505 * Retrieves the value set using clutter_actor_set_text_direction()
14507 * If no text direction has been previously set, the default text
14508 * direction, as returned by clutter_get_default_text_direction(), will
14509 * be returned instead
14511 * Return value: the #ClutterTextDirection for the actor
14515 ClutterTextDirection
14516 clutter_actor_get_text_direction (ClutterActor *self)
14518 ClutterActorPrivate *priv;
14520 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14521 CLUTTER_TEXT_DIRECTION_LTR);
14525 /* if no direction has been set yet use the default */
14526 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14527 priv->text_direction = clutter_get_default_text_direction ();
14529 return priv->text_direction;
14533 * clutter_actor_push_internal:
14534 * @self: a #ClutterActor
14536 * Should be used by actors implementing the #ClutterContainer and with
14537 * internal children added through clutter_actor_set_parent(), for instance:
14541 * my_actor_init (MyActor *self)
14543 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14545 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14547 * /* calling clutter_actor_set_parent() now will result in
14548 * * the internal flag being set on a child of MyActor
14551 * /* internal child - a background texture */
14552 * self->priv->background_tex = clutter_texture_new ();
14553 * clutter_actor_set_parent (self->priv->background_tex,
14554 * CLUTTER_ACTOR (self));
14556 * /* internal child - a label */
14557 * self->priv->label = clutter_text_new ();
14558 * clutter_actor_set_parent (self->priv->label,
14559 * CLUTTER_ACTOR (self));
14561 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14563 * /* calling clutter_actor_set_parent() now will not result in
14564 * * the internal flag being set on a child of MyActor
14569 * This function will be used by Clutter to toggle an "internal child"
14570 * flag whenever clutter_actor_set_parent() is called; internal children
14571 * are handled differently by Clutter, specifically when destroying their
14574 * Call clutter_actor_pop_internal() when you finished adding internal
14577 * Nested calls to clutter_actor_push_internal() are allowed, but each
14578 * one must by followed by a clutter_actor_pop_internal() call.
14582 * Deprecated: 1.10: All children of an actor are accessible through
14583 * the #ClutterActor API, and #ClutterActor implements the
14584 * #ClutterContainer interface, so this function is only useful
14585 * for legacy containers overriding the default implementation.
14588 clutter_actor_push_internal (ClutterActor *self)
14590 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14592 self->priv->internal_child += 1;
14596 * clutter_actor_pop_internal:
14597 * @self: a #ClutterActor
14599 * Disables the effects of clutter_actor_push_internal().
14603 * Deprecated: 1.10: All children of an actor are accessible through
14604 * the #ClutterActor API. This function is only useful for legacy
14605 * containers overriding the default implementation of the
14606 * #ClutterContainer interface.
14609 clutter_actor_pop_internal (ClutterActor *self)
14611 ClutterActorPrivate *priv;
14613 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14617 if (priv->internal_child == 0)
14619 g_warning ("Mismatched %s: you need to call "
14620 "clutter_actor_push_composite() at least once before "
14621 "calling this function", G_STRFUNC);
14625 priv->internal_child -= 1;
14629 * clutter_actor_has_pointer:
14630 * @self: a #ClutterActor
14632 * Checks whether an actor contains the pointer of a
14633 * #ClutterInputDevice
14635 * Return value: %TRUE if the actor contains the pointer, and
14641 clutter_actor_has_pointer (ClutterActor *self)
14643 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14645 return self->priv->has_pointer;
14648 /* XXX: This is a workaround for not being able to break the ABI of
14649 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14650 * clutter_actor_queue_clipped_redraw() for details.
14652 ClutterPaintVolume *
14653 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14655 return g_object_get_data (G_OBJECT (self),
14656 "-clutter-actor-queue-redraw-clip");
14660 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14661 ClutterPaintVolume *clip)
14663 g_object_set_data (G_OBJECT (self),
14664 "-clutter-actor-queue-redraw-clip",
14669 * clutter_actor_has_allocation:
14670 * @self: a #ClutterActor
14672 * Checks if the actor has an up-to-date allocation assigned to
14673 * it. This means that the actor should have an allocation: it's
14674 * visible and has a parent. It also means that there is no
14675 * outstanding relayout request in progress for the actor or its
14676 * children (There might be other outstanding layout requests in
14677 * progress that will cause the actor to get a new allocation
14678 * when the stage is laid out, however).
14680 * If this function returns %FALSE, then the actor will normally
14681 * be allocated before it is next drawn on the screen.
14683 * Return value: %TRUE if the actor has an up-to-date allocation
14688 clutter_actor_has_allocation (ClutterActor *self)
14690 ClutterActorPrivate *priv;
14692 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14696 return priv->parent != NULL &&
14697 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14698 !priv->needs_allocation;
14702 * clutter_actor_add_action:
14703 * @self: a #ClutterActor
14704 * @action: a #ClutterAction
14706 * Adds @action to the list of actions applied to @self
14708 * A #ClutterAction can only belong to one actor at a time
14710 * The #ClutterActor will hold a reference on @action until either
14711 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14717 clutter_actor_add_action (ClutterActor *self,
14718 ClutterAction *action)
14720 ClutterActorPrivate *priv;
14722 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14723 g_return_if_fail (CLUTTER_IS_ACTION (action));
14727 if (priv->actions == NULL)
14729 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14730 priv->actions->actor = self;
14733 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14735 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14739 * clutter_actor_add_action_with_name:
14740 * @self: a #ClutterActor
14741 * @name: the name to set on the action
14742 * @action: a #ClutterAction
14744 * A convenience function for setting the name of a #ClutterAction
14745 * while adding it to the list of actions applied to @self
14747 * This function is the logical equivalent of:
14750 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14751 * clutter_actor_add_action (self, action);
14757 clutter_actor_add_action_with_name (ClutterActor *self,
14759 ClutterAction *action)
14761 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14762 g_return_if_fail (name != NULL);
14763 g_return_if_fail (CLUTTER_IS_ACTION (action));
14765 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14766 clutter_actor_add_action (self, action);
14770 * clutter_actor_remove_action:
14771 * @self: a #ClutterActor
14772 * @action: a #ClutterAction
14774 * Removes @action from the list of actions applied to @self
14776 * The reference held by @self on the #ClutterAction will be released
14781 clutter_actor_remove_action (ClutterActor *self,
14782 ClutterAction *action)
14784 ClutterActorPrivate *priv;
14786 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14787 g_return_if_fail (CLUTTER_IS_ACTION (action));
14791 if (priv->actions == NULL)
14794 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14796 if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14797 g_clear_object (&priv->actions);
14799 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14803 * clutter_actor_remove_action_by_name:
14804 * @self: a #ClutterActor
14805 * @name: the name of the action to remove
14807 * Removes the #ClutterAction with the given name from the list
14808 * of actions applied to @self
14813 clutter_actor_remove_action_by_name (ClutterActor *self,
14816 ClutterActorPrivate *priv;
14817 ClutterActorMeta *meta;
14819 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14820 g_return_if_fail (name != NULL);
14824 if (priv->actions == NULL)
14827 meta = _clutter_meta_group_get_meta (priv->actions, name);
14831 _clutter_meta_group_remove_meta (priv->actions, meta);
14833 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14837 * clutter_actor_get_actions:
14838 * @self: a #ClutterActor
14840 * Retrieves the list of actions applied to @self
14842 * Return value: (transfer container) (element-type Clutter.Action): a copy
14843 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14844 * owned by the #ClutterActor. Use g_list_free() to free the resources
14845 * allocated by the returned #GList
14850 clutter_actor_get_actions (ClutterActor *self)
14852 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14854 if (self->priv->actions == NULL)
14857 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14861 * clutter_actor_get_action:
14862 * @self: a #ClutterActor
14863 * @name: the name of the action to retrieve
14865 * Retrieves the #ClutterAction with the given name in the list
14866 * of actions applied to @self
14868 * Return value: (transfer none): a #ClutterAction for the given
14869 * name, or %NULL. The returned #ClutterAction is owned by the
14870 * actor and it should not be unreferenced directly
14875 clutter_actor_get_action (ClutterActor *self,
14878 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14879 g_return_val_if_fail (name != NULL, NULL);
14881 if (self->priv->actions == NULL)
14884 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14888 * clutter_actor_clear_actions:
14889 * @self: a #ClutterActor
14891 * Clears the list of actions applied to @self
14896 clutter_actor_clear_actions (ClutterActor *self)
14898 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14900 if (self->priv->actions == NULL)
14903 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14907 * clutter_actor_add_constraint:
14908 * @self: a #ClutterActor
14909 * @constraint: a #ClutterConstraint
14911 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14914 * The #ClutterActor will hold a reference on the @constraint until
14915 * either clutter_actor_remove_constraint() or
14916 * clutter_actor_clear_constraints() is called.
14921 clutter_actor_add_constraint (ClutterActor *self,
14922 ClutterConstraint *constraint)
14924 ClutterActorPrivate *priv;
14926 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14927 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14931 if (priv->constraints == NULL)
14933 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14934 priv->constraints->actor = self;
14937 _clutter_meta_group_add_meta (priv->constraints,
14938 CLUTTER_ACTOR_META (constraint));
14939 clutter_actor_queue_relayout (self);
14941 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14945 * clutter_actor_add_constraint_with_name:
14946 * @self: a #ClutterActor
14947 * @name: the name to set on the constraint
14948 * @constraint: a #ClutterConstraint
14950 * A convenience function for setting the name of a #ClutterConstraint
14951 * while adding it to the list of constraints applied to @self
14953 * This function is the logical equivalent of:
14956 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14957 * clutter_actor_add_constraint (self, constraint);
14963 clutter_actor_add_constraint_with_name (ClutterActor *self,
14965 ClutterConstraint *constraint)
14967 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14968 g_return_if_fail (name != NULL);
14969 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14971 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14972 clutter_actor_add_constraint (self, constraint);
14976 * clutter_actor_remove_constraint:
14977 * @self: a #ClutterActor
14978 * @constraint: a #ClutterConstraint
14980 * Removes @constraint from the list of constraints applied to @self
14982 * The reference held by @self on the #ClutterConstraint will be released
14987 clutter_actor_remove_constraint (ClutterActor *self,
14988 ClutterConstraint *constraint)
14990 ClutterActorPrivate *priv;
14992 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14993 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14997 if (priv->constraints == NULL)
15000 _clutter_meta_group_remove_meta (priv->constraints,
15001 CLUTTER_ACTOR_META (constraint));
15003 if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15004 g_clear_object (&priv->constraints);
15006 clutter_actor_queue_relayout (self);
15008 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15012 * clutter_actor_remove_constraint_by_name:
15013 * @self: a #ClutterActor
15014 * @name: the name of the constraint to remove
15016 * Removes the #ClutterConstraint with the given name from the list
15017 * of constraints applied to @self
15022 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15025 ClutterActorPrivate *priv;
15026 ClutterActorMeta *meta;
15028 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15029 g_return_if_fail (name != NULL);
15033 if (priv->constraints == NULL)
15036 meta = _clutter_meta_group_get_meta (priv->constraints, name);
15040 _clutter_meta_group_remove_meta (priv->constraints, meta);
15041 clutter_actor_queue_relayout (self);
15045 * clutter_actor_get_constraints:
15046 * @self: a #ClutterActor
15048 * Retrieves the list of constraints applied to @self
15050 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15051 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15052 * owned by the #ClutterActor. Use g_list_free() to free the resources
15053 * allocated by the returned #GList
15058 clutter_actor_get_constraints (ClutterActor *self)
15060 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15062 if (self->priv->constraints == NULL)
15065 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15069 * clutter_actor_get_constraint:
15070 * @self: a #ClutterActor
15071 * @name: the name of the constraint to retrieve
15073 * Retrieves the #ClutterConstraint with the given name in the list
15074 * of constraints applied to @self
15076 * Return value: (transfer none): a #ClutterConstraint for the given
15077 * name, or %NULL. The returned #ClutterConstraint is owned by the
15078 * actor and it should not be unreferenced directly
15082 ClutterConstraint *
15083 clutter_actor_get_constraint (ClutterActor *self,
15086 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15087 g_return_val_if_fail (name != NULL, NULL);
15089 if (self->priv->constraints == NULL)
15092 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15096 * clutter_actor_clear_constraints:
15097 * @self: a #ClutterActor
15099 * Clears the list of constraints applied to @self
15104 clutter_actor_clear_constraints (ClutterActor *self)
15106 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15108 if (self->priv->constraints == NULL)
15111 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15113 clutter_actor_queue_relayout (self);
15117 * clutter_actor_set_clip_to_allocation:
15118 * @self: a #ClutterActor
15119 * @clip_set: %TRUE to apply a clip tracking the allocation
15121 * Sets whether @self should be clipped to the same size as its
15127 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15130 ClutterActorPrivate *priv;
15132 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15134 clip_set = !!clip_set;
15138 if (priv->clip_to_allocation != clip_set)
15140 priv->clip_to_allocation = clip_set;
15142 clutter_actor_queue_redraw (self);
15144 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15149 * clutter_actor_get_clip_to_allocation:
15150 * @self: a #ClutterActor
15152 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15154 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15159 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15161 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15163 return self->priv->clip_to_allocation;
15167 * clutter_actor_add_effect:
15168 * @self: a #ClutterActor
15169 * @effect: a #ClutterEffect
15171 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15173 * The #ClutterActor will hold a reference on the @effect until either
15174 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15180 clutter_actor_add_effect (ClutterActor *self,
15181 ClutterEffect *effect)
15183 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15184 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15186 _clutter_actor_add_effect_internal (self, effect);
15188 clutter_actor_queue_redraw (self);
15190 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15194 * clutter_actor_add_effect_with_name:
15195 * @self: a #ClutterActor
15196 * @name: the name to set on the effect
15197 * @effect: a #ClutterEffect
15199 * A convenience function for setting the name of a #ClutterEffect
15200 * while adding it to the list of effectss applied to @self
15202 * This function is the logical equivalent of:
15205 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15206 * clutter_actor_add_effect (self, effect);
15212 clutter_actor_add_effect_with_name (ClutterActor *self,
15214 ClutterEffect *effect)
15216 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15217 g_return_if_fail (name != NULL);
15218 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15220 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15221 clutter_actor_add_effect (self, effect);
15225 * clutter_actor_remove_effect:
15226 * @self: a #ClutterActor
15227 * @effect: a #ClutterEffect
15229 * Removes @effect from the list of effects applied to @self
15231 * The reference held by @self on the #ClutterEffect will be released
15236 clutter_actor_remove_effect (ClutterActor *self,
15237 ClutterEffect *effect)
15239 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15240 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15242 _clutter_actor_remove_effect_internal (self, effect);
15244 clutter_actor_queue_redraw (self);
15246 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15250 * clutter_actor_remove_effect_by_name:
15251 * @self: a #ClutterActor
15252 * @name: the name of the effect to remove
15254 * Removes the #ClutterEffect with the given name from the list
15255 * of effects applied to @self
15260 clutter_actor_remove_effect_by_name (ClutterActor *self,
15263 ClutterActorPrivate *priv;
15264 ClutterActorMeta *meta;
15266 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15267 g_return_if_fail (name != NULL);
15271 if (priv->effects == NULL)
15274 meta = _clutter_meta_group_get_meta (priv->effects, name);
15278 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15282 * clutter_actor_get_effects:
15283 * @self: a #ClutterActor
15285 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15287 * Return value: (transfer container) (element-type Clutter.Effect): a list
15288 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15289 * list are owned by Clutter and they should not be freed. You should
15290 * free the returned list using g_list_free() when done
15295 clutter_actor_get_effects (ClutterActor *self)
15297 ClutterActorPrivate *priv;
15299 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15303 if (priv->effects == NULL)
15306 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15310 * clutter_actor_get_effect:
15311 * @self: a #ClutterActor
15312 * @name: the name of the effect to retrieve
15314 * Retrieves the #ClutterEffect with the given name in the list
15315 * of effects applied to @self
15317 * Return value: (transfer none): a #ClutterEffect for the given
15318 * name, or %NULL. The returned #ClutterEffect is owned by the
15319 * actor and it should not be unreferenced directly
15324 clutter_actor_get_effect (ClutterActor *self,
15327 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15328 g_return_val_if_fail (name != NULL, NULL);
15330 if (self->priv->effects == NULL)
15333 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15337 * clutter_actor_clear_effects:
15338 * @self: a #ClutterActor
15340 * Clears the list of effects applied to @self
15345 clutter_actor_clear_effects (ClutterActor *self)
15347 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15349 if (self->priv->effects == NULL)
15352 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15354 clutter_actor_queue_redraw (self);
15358 * clutter_actor_has_key_focus:
15359 * @self: a #ClutterActor
15361 * Checks whether @self is the #ClutterActor that has key focus
15363 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15368 clutter_actor_has_key_focus (ClutterActor *self)
15370 ClutterActor *stage;
15372 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15374 stage = _clutter_actor_get_stage_internal (self);
15378 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15382 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15383 ClutterPaintVolume *pv)
15385 ClutterActorPrivate *priv = self->priv;
15387 /* Actors are only expected to report a valid paint volume
15388 * while they have a valid allocation. */
15389 if (G_UNLIKELY (priv->needs_allocation))
15391 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15392 "Actor needs allocation",
15393 _clutter_actor_get_debug_name (self));
15397 /* Check if there are any handlers connected to the paint
15398 * signal. If there are then all bets are off for what the paint
15399 * volume for this actor might possibly be!
15401 * XXX: It's expected that this is going to end up being quite a
15402 * costly check to have to do here, but we haven't come up with
15403 * another solution that can reliably catch paint signal handlers at
15404 * the right time to either avoid artefacts due to invalid stage
15405 * clipping or due to incorrect culling.
15407 * Previously we checked in clutter_actor_paint(), but at that time
15408 * we may already be using a stage clip that could be derived from
15409 * an invalid paint-volume. We used to try and handle that by
15410 * queuing a follow up, unclipped, redraw but still the previous
15411 * checking wasn't enough to catch invalid volumes involved in
15412 * culling (considering that containers may derive their volume from
15413 * children that haven't yet been painted)
15415 * Longer term, improved solutions could be:
15416 * - Disallow painting in the paint signal, only allow using it
15417 * for tracking when paints happen. We can add another API that
15418 * allows monkey patching the paint of arbitrary actors but in a
15419 * more controlled way and that also supports modifying the
15421 * - If we could be notified somehow when signal handlers are
15422 * connected we wouldn't have to poll for handlers like this.
15424 if (g_signal_has_handler_pending (self,
15425 actor_signals[PAINT],
15429 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15430 "Actor has \"paint\" signal handlers",
15431 _clutter_actor_get_debug_name (self));
15435 _clutter_paint_volume_init_static (pv, self);
15437 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15439 clutter_paint_volume_free (pv);
15440 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15441 "Actor failed to report a volume",
15442 _clutter_actor_get_debug_name (self));
15446 /* since effects can modify the paint volume, we allow them to actually
15447 * do this by making get_paint_volume() "context sensitive"
15449 if (priv->effects != NULL)
15451 if (priv->current_effect != NULL)
15453 const GList *effects, *l;
15455 /* if we are being called from within the paint sequence of
15456 * an actor, get the paint volume up to the current effect
15458 effects = _clutter_meta_group_peek_metas (priv->effects);
15460 l != NULL || (l != NULL && l->data != priv->current_effect);
15463 if (!_clutter_effect_get_paint_volume (l->data, pv))
15465 clutter_paint_volume_free (pv);
15466 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15467 "Effect (%s) failed to report a volume",
15468 _clutter_actor_get_debug_name (self),
15469 _clutter_actor_meta_get_debug_name (l->data));
15476 const GList *effects, *l;
15478 /* otherwise, get the cumulative volume */
15479 effects = _clutter_meta_group_peek_metas (priv->effects);
15480 for (l = effects; l != NULL; l = l->next)
15481 if (!_clutter_effect_get_paint_volume (l->data, pv))
15483 clutter_paint_volume_free (pv);
15484 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15485 "Effect (%s) failed to report a volume",
15486 _clutter_actor_get_debug_name (self),
15487 _clutter_actor_meta_get_debug_name (l->data));
15496 /* The public clutter_actor_get_paint_volume API returns a const
15497 * pointer since we return a pointer directly to the cached
15498 * PaintVolume associated with the actor and don't want the user to
15499 * inadvertently modify it, but for internal uses we sometimes need
15500 * access to the same PaintVolume but need to apply some book-keeping
15501 * modifications to it so we don't want a const pointer.
15503 static ClutterPaintVolume *
15504 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15506 ClutterActorPrivate *priv;
15510 if (priv->paint_volume_valid)
15511 clutter_paint_volume_free (&priv->paint_volume);
15513 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15515 priv->paint_volume_valid = TRUE;
15516 return &priv->paint_volume;
15520 priv->paint_volume_valid = FALSE;
15526 * clutter_actor_get_paint_volume:
15527 * @self: a #ClutterActor
15529 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15530 * when a paint volume can't be determined.
15532 * The paint volume is defined as the 3D space occupied by an actor
15533 * when being painted.
15535 * This function will call the <function>get_paint_volume()</function>
15536 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15537 * should not usually care about overriding the default implementation,
15538 * unless they are, for instance: painting outside their allocation, or
15539 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15542 * <note>2D actors overriding <function>get_paint_volume()</function>
15543 * ensure their volume has a depth of 0. (This will be true so long as
15544 * you don't call clutter_paint_volume_set_depth().)</note>
15546 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15547 * or %NULL if no volume could be determined. The returned pointer
15548 * is not guaranteed to be valid across multiple frames; if you want
15549 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15553 const ClutterPaintVolume *
15554 clutter_actor_get_paint_volume (ClutterActor *self)
15556 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15558 return _clutter_actor_get_paint_volume_mutable (self);
15562 * clutter_actor_get_transformed_paint_volume:
15563 * @self: a #ClutterActor
15564 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15565 * (or %NULL for the stage)
15567 * Retrieves the 3D paint volume of an actor like
15568 * clutter_actor_get_paint_volume() does (Please refer to the
15569 * documentation of clutter_actor_get_paint_volume() for more
15570 * details.) and it additionally transforms the paint volume into the
15571 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15572 * is passed for @relative_to_ancestor)
15574 * This can be used by containers that base their paint volume on
15575 * the volume of their children. Such containers can query the
15576 * transformed paint volume of all of its children and union them
15577 * together using clutter_paint_volume_union().
15579 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15580 * or %NULL if no volume could be determined. The returned pointer is
15581 * not guaranteed to be valid across multiple frames; if you wish to
15582 * keep it, you will have to copy it using clutter_paint_volume_copy().
15586 const ClutterPaintVolume *
15587 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15588 ClutterActor *relative_to_ancestor)
15590 const ClutterPaintVolume *volume;
15591 ClutterActor *stage;
15592 ClutterPaintVolume *transformed_volume;
15594 stage = _clutter_actor_get_stage_internal (self);
15595 if (G_UNLIKELY (stage == NULL))
15598 if (relative_to_ancestor == NULL)
15599 relative_to_ancestor = stage;
15601 volume = clutter_actor_get_paint_volume (self);
15602 if (volume == NULL)
15605 transformed_volume =
15606 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15608 _clutter_paint_volume_copy_static (volume, transformed_volume);
15610 _clutter_paint_volume_transform_relative (transformed_volume,
15611 relative_to_ancestor);
15613 return transformed_volume;
15617 * clutter_actor_get_paint_box:
15618 * @self: a #ClutterActor
15619 * @box: (out): return location for a #ClutterActorBox
15621 * Retrieves the paint volume of the passed #ClutterActor, and
15622 * transforms it into a 2D bounding box in stage coordinates.
15624 * This function is useful to determine the on screen area occupied by
15625 * the actor. The box is only an approximation and may often be
15626 * considerably larger due to the optimizations used to calculate the
15627 * box. The box is never smaller though, so it can reliably be used
15630 * There are times when a 2D paint box can't be determined, e.g.
15631 * because the actor isn't yet parented under a stage or because
15632 * the actor is unable to determine a paint volume.
15634 * Return value: %TRUE if a 2D paint box could be determined, else
15640 clutter_actor_get_paint_box (ClutterActor *self,
15641 ClutterActorBox *box)
15643 ClutterActor *stage;
15644 ClutterPaintVolume *pv;
15646 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15647 g_return_val_if_fail (box != NULL, FALSE);
15649 stage = _clutter_actor_get_stage_internal (self);
15650 if (G_UNLIKELY (!stage))
15653 pv = _clutter_actor_get_paint_volume_mutable (self);
15654 if (G_UNLIKELY (!pv))
15657 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15663 * clutter_actor_has_overlaps:
15664 * @self: A #ClutterActor
15666 * Asks the actor's implementation whether it may contain overlapping
15669 * For example; Clutter may use this to determine whether the painting
15670 * should be redirected to an offscreen buffer to correctly implement
15671 * the opacity property.
15673 * Custom actors can override the default response by implementing the
15674 * #ClutterActor <function>has_overlaps</function> virtual function. See
15675 * clutter_actor_set_offscreen_redirect() for more information.
15677 * Return value: %TRUE if the actor may have overlapping primitives, and
15683 clutter_actor_has_overlaps (ClutterActor *self)
15685 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15687 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15691 * clutter_actor_has_effects:
15692 * @self: A #ClutterActor
15694 * Returns whether the actor has any effects applied.
15696 * Return value: %TRUE if the actor has any effects,
15702 clutter_actor_has_effects (ClutterActor *self)
15704 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15706 if (self->priv->effects == NULL)
15709 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15713 * clutter_actor_has_constraints:
15714 * @self: A #ClutterActor
15716 * Returns whether the actor has any constraints applied.
15718 * Return value: %TRUE if the actor has any constraints,
15724 clutter_actor_has_constraints (ClutterActor *self)
15726 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15728 return self->priv->constraints != NULL;
15732 * clutter_actor_has_actions:
15733 * @self: A #ClutterActor
15735 * Returns whether the actor has any actions applied.
15737 * Return value: %TRUE if the actor has any actions,
15743 clutter_actor_has_actions (ClutterActor *self)
15745 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15747 return self->priv->actions != NULL;
15751 * clutter_actor_get_n_children:
15752 * @self: a #ClutterActor
15754 * Retrieves the number of children of @self.
15756 * Return value: the number of children of an actor
15761 clutter_actor_get_n_children (ClutterActor *self)
15763 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15765 return self->priv->n_children;
15769 * clutter_actor_get_child_at_index:
15770 * @self: a #ClutterActor
15771 * @index_: the position in the list of children
15773 * Retrieves the actor at the given @index_ inside the list of
15774 * children of @self.
15776 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15781 clutter_actor_get_child_at_index (ClutterActor *self,
15784 ClutterActor *iter;
15787 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15788 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15790 for (iter = self->priv->first_child, i = 0;
15791 iter != NULL && i < index_;
15792 iter = iter->priv->next_sibling, i += 1)
15799 * _clutter_actor_foreach_child:
15800 * @actor: The actor whos children you want to iterate
15801 * @callback: The function to call for each child
15802 * @user_data: Private data to pass to @callback
15804 * Calls a given @callback once for each child of the specified @actor and
15805 * passing the @user_data pointer each time.
15807 * Return value: returns %TRUE if all children were iterated, else
15808 * %FALSE if a callback broke out of iteration early.
15811 _clutter_actor_foreach_child (ClutterActor *self,
15812 ClutterForeachCallback callback,
15813 gpointer user_data)
15815 ClutterActor *iter;
15818 if (self->priv->first_child == NULL)
15822 iter = self->priv->first_child;
15824 /* we use this form so that it's safe to change the children
15825 * list while iterating it
15827 while (cont && iter != NULL)
15829 ClutterActor *next = iter->priv->next_sibling;
15831 cont = callback (iter, user_data);
15840 /* For debugging purposes this gives us a simple way to print out
15841 * the scenegraph e.g in gdb using:
15843 * _clutter_actor_traverse (stage,
15845 * clutter_debug_print_actor_cb,
15850 static ClutterActorTraverseVisitFlags
15851 clutter_debug_print_actor_cb (ClutterActor *actor,
15855 g_print ("%*s%s:%p\n",
15857 _clutter_actor_get_debug_name (actor),
15860 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15865 _clutter_actor_traverse_breadth (ClutterActor *actor,
15866 ClutterTraverseCallback callback,
15867 gpointer user_data)
15869 GQueue *queue = g_queue_new ();
15870 ClutterActor dummy;
15871 int current_depth = 0;
15873 g_queue_push_tail (queue, actor);
15874 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15876 while ((actor = g_queue_pop_head (queue)))
15878 ClutterActorTraverseVisitFlags flags;
15880 if (actor == &dummy)
15883 g_queue_push_tail (queue, &dummy);
15887 flags = callback (actor, current_depth, user_data);
15888 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15890 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15892 ClutterActor *iter;
15894 for (iter = actor->priv->first_child;
15896 iter = iter->priv->next_sibling)
15898 g_queue_push_tail (queue, iter);
15903 g_queue_free (queue);
15906 static ClutterActorTraverseVisitFlags
15907 _clutter_actor_traverse_depth (ClutterActor *actor,
15908 ClutterTraverseCallback before_children_callback,
15909 ClutterTraverseCallback after_children_callback,
15911 gpointer user_data)
15913 ClutterActorTraverseVisitFlags flags;
15915 flags = before_children_callback (actor, current_depth, user_data);
15916 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15917 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15919 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15921 ClutterActor *iter;
15923 for (iter = actor->priv->first_child;
15925 iter = iter->priv->next_sibling)
15927 flags = _clutter_actor_traverse_depth (iter,
15928 before_children_callback,
15929 after_children_callback,
15933 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15934 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15938 if (after_children_callback)
15939 return after_children_callback (actor, current_depth, user_data);
15941 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15944 /* _clutter_actor_traverse:
15945 * @actor: The actor to start traversing the graph from
15946 * @flags: These flags may affect how the traversal is done
15947 * @before_children_callback: A function to call before visiting the
15948 * children of the current actor.
15949 * @after_children_callback: A function to call after visiting the
15950 * children of the current actor. (Ignored if
15951 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15952 * @user_data: The private data to pass to the callbacks
15954 * Traverses the scenegraph starting at the specified @actor and
15955 * descending through all its children and its children's children.
15956 * For each actor traversed @before_children_callback and
15957 * @after_children_callback are called with the specified
15958 * @user_data, before and after visiting that actor's children.
15960 * The callbacks can return flags that affect the ongoing traversal
15961 * such as by skipping over an actors children or bailing out of
15962 * any further traversing.
15965 _clutter_actor_traverse (ClutterActor *actor,
15966 ClutterActorTraverseFlags flags,
15967 ClutterTraverseCallback before_children_callback,
15968 ClutterTraverseCallback after_children_callback,
15969 gpointer user_data)
15971 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15972 _clutter_actor_traverse_breadth (actor,
15973 before_children_callback,
15975 else /* DEPTH_FIRST */
15976 _clutter_actor_traverse_depth (actor,
15977 before_children_callback,
15978 after_children_callback,
15979 0, /* start depth */
15984 on_layout_manager_changed (ClutterLayoutManager *manager,
15985 ClutterActor *self)
15987 clutter_actor_queue_relayout (self);
15991 * clutter_actor_set_layout_manager:
15992 * @self: a #ClutterActor
15993 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15995 * Sets the #ClutterLayoutManager delegate object that will be used to
15996 * lay out the children of @self.
15998 * The #ClutterActor will take a reference on the passed @manager which
15999 * will be released either when the layout manager is removed, or when
16000 * the actor is destroyed.
16005 clutter_actor_set_layout_manager (ClutterActor *self,
16006 ClutterLayoutManager *manager)
16008 ClutterActorPrivate *priv;
16010 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16011 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16015 if (priv->layout_manager != NULL)
16017 g_signal_handlers_disconnect_by_func (priv->layout_manager,
16018 G_CALLBACK (on_layout_manager_changed),
16020 clutter_layout_manager_set_container (priv->layout_manager, NULL);
16021 g_clear_object (&priv->layout_manager);
16024 priv->layout_manager = manager;
16026 if (priv->layout_manager != NULL)
16028 g_object_ref_sink (priv->layout_manager);
16029 clutter_layout_manager_set_container (priv->layout_manager,
16030 CLUTTER_CONTAINER (self));
16031 g_signal_connect (priv->layout_manager, "layout-changed",
16032 G_CALLBACK (on_layout_manager_changed),
16036 clutter_actor_queue_relayout (self);
16038 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16042 * clutter_actor_get_layout_manager:
16043 * @self: a #ClutterActor
16045 * Retrieves the #ClutterLayoutManager used by @self.
16047 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16052 ClutterLayoutManager *
16053 clutter_actor_get_layout_manager (ClutterActor *self)
16055 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16057 return self->priv->layout_manager;
16060 static const ClutterLayoutInfo default_layout_info = {
16063 { 0, 0, 0, 0 }, /* margin */
16064 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
16065 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
16066 0.f, 0.f, /* min_width, natural_width */
16067 0.f, 0.f, /* natual_width, natural_height */
16071 layout_info_free (gpointer data)
16073 if (G_LIKELY (data != NULL))
16074 g_slice_free (ClutterLayoutInfo, data);
16078 * _clutter_actor_get_layout_info:
16079 * @self: a #ClutterActor
16081 * Retrieves a pointer to the ClutterLayoutInfo structure.
16083 * If the actor does not have a ClutterLayoutInfo associated to it, one
16084 * will be created and initialized to the default values.
16086 * This function should be used for setters.
16088 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16091 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16093 ClutterLayoutInfo *
16094 _clutter_actor_get_layout_info (ClutterActor *self)
16096 ClutterLayoutInfo *retval;
16098 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16099 if (retval == NULL)
16101 retval = g_slice_new (ClutterLayoutInfo);
16103 *retval = default_layout_info;
16105 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16114 * _clutter_actor_get_layout_info_or_defaults:
16115 * @self: a #ClutterActor
16117 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16119 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16120 * then the default structure will be returned.
16122 * This function should only be used for getters.
16124 * Return value: a const pointer to the ClutterLayoutInfo structure
16126 const ClutterLayoutInfo *
16127 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16129 const ClutterLayoutInfo *info;
16131 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16133 return &default_layout_info;
16139 * clutter_actor_set_x_align:
16140 * @self: a #ClutterActor
16141 * @x_align: the horizontal alignment policy
16143 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16144 * actor received extra horizontal space.
16146 * See also the #ClutterActor:x-align property.
16151 clutter_actor_set_x_align (ClutterActor *self,
16152 ClutterActorAlign x_align)
16154 ClutterLayoutInfo *info;
16156 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16158 info = _clutter_actor_get_layout_info (self);
16160 if (info->x_align != x_align)
16162 info->x_align = x_align;
16164 clutter_actor_queue_relayout (self);
16166 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16171 * clutter_actor_get_x_align:
16172 * @self: a #ClutterActor
16174 * Retrieves the horizontal alignment policy set using
16175 * clutter_actor_set_x_align().
16177 * Return value: the horizontal alignment policy.
16182 clutter_actor_get_x_align (ClutterActor *self)
16184 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16186 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16190 * clutter_actor_set_y_align:
16191 * @self: a #ClutterActor
16192 * @y_align: the vertical alignment policy
16194 * Sets the vertical alignment policy of a #ClutterActor, in case the
16195 * actor received extra vertical space.
16197 * See also the #ClutterActor:y-align property.
16202 clutter_actor_set_y_align (ClutterActor *self,
16203 ClutterActorAlign y_align)
16205 ClutterLayoutInfo *info;
16207 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16209 info = _clutter_actor_get_layout_info (self);
16211 if (info->y_align != y_align)
16213 info->y_align = y_align;
16215 clutter_actor_queue_relayout (self);
16217 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16222 * clutter_actor_get_y_align:
16223 * @self: a #ClutterActor
16225 * Retrieves the vertical alignment policy set using
16226 * clutter_actor_set_y_align().
16228 * Return value: the vertical alignment policy.
16233 clutter_actor_get_y_align (ClutterActor *self)
16235 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16237 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16242 * clutter_margin_new:
16244 * Creates a new #ClutterMargin.
16246 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16247 * clutter_margin_free() to free the resources associated with it when
16253 clutter_margin_new (void)
16255 return g_slice_new0 (ClutterMargin);
16259 * clutter_margin_copy:
16260 * @margin_: a #ClutterMargin
16262 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16263 * the newly created structure.
16265 * Return value: (transfer full): a copy of the #ClutterMargin.
16270 clutter_margin_copy (const ClutterMargin *margin_)
16272 if (G_LIKELY (margin_ != NULL))
16273 return g_slice_dup (ClutterMargin, margin_);
16279 * clutter_margin_free:
16280 * @margin_: a #ClutterMargin
16282 * Frees the resources allocated by clutter_margin_new() and
16283 * clutter_margin_copy().
16288 clutter_margin_free (ClutterMargin *margin_)
16290 if (G_LIKELY (margin_ != NULL))
16291 g_slice_free (ClutterMargin, margin_);
16294 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16295 clutter_margin_copy,
16296 clutter_margin_free)
16299 * clutter_actor_set_margin:
16300 * @self: a #ClutterActor
16301 * @margin: a #ClutterMargin
16303 * Sets all the components of the margin of a #ClutterActor.
16308 clutter_actor_set_margin (ClutterActor *self,
16309 const ClutterMargin *margin)
16311 ClutterLayoutInfo *info;
16315 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16316 g_return_if_fail (margin != NULL);
16318 obj = G_OBJECT (self);
16321 g_object_freeze_notify (obj);
16323 info = _clutter_actor_get_layout_info (self);
16325 if (info->margin.top != margin->top)
16327 info->margin.top = margin->top;
16328 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16332 if (info->margin.right != margin->right)
16334 info->margin.right = margin->right;
16335 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16339 if (info->margin.bottom != margin->bottom)
16341 info->margin.bottom = margin->bottom;
16342 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16346 if (info->margin.left != margin->left)
16348 info->margin.left = margin->left;
16349 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16354 clutter_actor_queue_relayout (self);
16356 g_object_thaw_notify (obj);
16360 * clutter_actor_get_margin:
16361 * @self: a #ClutterActor
16362 * @margin: (out caller-allocates): return location for a #ClutterMargin
16364 * Retrieves all the components of the margin of a #ClutterActor.
16369 clutter_actor_get_margin (ClutterActor *self,
16370 ClutterMargin *margin)
16372 const ClutterLayoutInfo *info;
16374 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16375 g_return_if_fail (margin != NULL);
16377 info = _clutter_actor_get_layout_info_or_defaults (self);
16379 *margin = info->margin;
16383 * clutter_actor_set_margin_top:
16384 * @self: a #ClutterActor
16385 * @margin: the top margin
16387 * Sets the margin from the top of a #ClutterActor.
16392 clutter_actor_set_margin_top (ClutterActor *self,
16395 ClutterLayoutInfo *info;
16397 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16398 g_return_if_fail (margin >= 0.f);
16400 info = _clutter_actor_get_layout_info (self);
16402 if (info->margin.top == margin)
16405 info->margin.top = margin;
16407 clutter_actor_queue_relayout (self);
16409 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16413 * clutter_actor_get_margin_top:
16414 * @self: a #ClutterActor
16416 * Retrieves the top margin of a #ClutterActor.
16418 * Return value: the top margin
16423 clutter_actor_get_margin_top (ClutterActor *self)
16425 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16427 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16431 * clutter_actor_set_margin_bottom:
16432 * @self: a #ClutterActor
16433 * @margin: the bottom margin
16435 * Sets the margin from the bottom of a #ClutterActor.
16440 clutter_actor_set_margin_bottom (ClutterActor *self,
16443 ClutterLayoutInfo *info;
16445 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16446 g_return_if_fail (margin >= 0.f);
16448 info = _clutter_actor_get_layout_info (self);
16450 if (info->margin.bottom == margin)
16453 info->margin.bottom = margin;
16455 clutter_actor_queue_relayout (self);
16457 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16461 * clutter_actor_get_margin_bottom:
16462 * @self: a #ClutterActor
16464 * Retrieves the bottom margin of a #ClutterActor.
16466 * Return value: the bottom margin
16471 clutter_actor_get_margin_bottom (ClutterActor *self)
16473 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16475 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16479 * clutter_actor_set_margin_left:
16480 * @self: a #ClutterActor
16481 * @margin: the left margin
16483 * Sets the margin from the left of a #ClutterActor.
16488 clutter_actor_set_margin_left (ClutterActor *self,
16491 ClutterLayoutInfo *info;
16493 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16494 g_return_if_fail (margin >= 0.f);
16496 info = _clutter_actor_get_layout_info (self);
16498 if (info->margin.left == margin)
16501 info->margin.left = margin;
16503 clutter_actor_queue_relayout (self);
16505 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16509 * clutter_actor_get_margin_left:
16510 * @self: a #ClutterActor
16512 * Retrieves the left margin of a #ClutterActor.
16514 * Return value: the left margin
16519 clutter_actor_get_margin_left (ClutterActor *self)
16521 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16523 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16527 * clutter_actor_set_margin_right:
16528 * @self: a #ClutterActor
16529 * @margin: the right margin
16531 * Sets the margin from the right of a #ClutterActor.
16536 clutter_actor_set_margin_right (ClutterActor *self,
16539 ClutterLayoutInfo *info;
16541 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16542 g_return_if_fail (margin >= 0.f);
16544 info = _clutter_actor_get_layout_info (self);
16546 if (info->margin.right == margin)
16549 info->margin.right = margin;
16551 clutter_actor_queue_relayout (self);
16553 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16557 * clutter_actor_get_margin_right:
16558 * @self: a #ClutterActor
16560 * Retrieves the right margin of a #ClutterActor.
16562 * Return value: the right margin
16567 clutter_actor_get_margin_right (ClutterActor *self)
16569 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16571 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16575 clutter_actor_set_background_color_internal (ClutterActor *self,
16576 const ClutterColor *color)
16578 ClutterActorPrivate *priv = self->priv;
16581 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16584 obj = G_OBJECT (self);
16586 priv->bg_color = *color;
16587 priv->bg_color_set = TRUE;
16589 clutter_actor_queue_redraw (self);
16591 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16592 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16596 * clutter_actor_set_background_color:
16597 * @self: a #ClutterActor
16598 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16601 * Sets the background color of a #ClutterActor.
16603 * The background color will be used to cover the whole allocation of the
16604 * actor. The default background color of an actor is transparent.
16606 * To check whether an actor has a background color, you can use the
16607 * #ClutterActor:background-color-set actor property.
16609 * The #ClutterActor:background-color property is animatable.
16614 clutter_actor_set_background_color (ClutterActor *self,
16615 const ClutterColor *color)
16617 ClutterActorPrivate *priv;
16619 GParamSpec *bg_color_pspec;
16621 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16623 obj = G_OBJECT (self);
16629 priv->bg_color_set = FALSE;
16630 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16631 clutter_actor_queue_redraw (self);
16635 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16636 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16638 _clutter_actor_create_transition (self, bg_color_pspec,
16643 _clutter_actor_update_transition (self, bg_color_pspec, color);
16645 clutter_actor_queue_redraw (self);
16649 * clutter_actor_get_background_color:
16650 * @self: a #ClutterActor
16651 * @color: (out caller-allocates): return location for a #ClutterColor
16653 * Retrieves the color set using clutter_actor_set_background_color().
16658 clutter_actor_get_background_color (ClutterActor *self,
16659 ClutterColor *color)
16661 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16662 g_return_if_fail (color != NULL);
16664 *color = self->priv->bg_color;
16668 * clutter_actor_get_previous_sibling:
16669 * @self: a #ClutterActor
16671 * Retrieves the sibling of @self that comes before it in the list
16672 * of children of @self's parent.
16674 * The returned pointer is only valid until the scene graph changes; it
16675 * is not safe to modify the list of children of @self while iterating
16678 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16683 clutter_actor_get_previous_sibling (ClutterActor *self)
16685 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16687 return self->priv->prev_sibling;
16691 * clutter_actor_get_next_sibling:
16692 * @self: a #ClutterActor
16694 * Retrieves the sibling of @self that comes after it in the list
16695 * of children of @self's parent.
16697 * The returned pointer is only valid until the scene graph changes; it
16698 * is not safe to modify the list of children of @self while iterating
16701 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16706 clutter_actor_get_next_sibling (ClutterActor *self)
16708 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16710 return self->priv->next_sibling;
16714 * clutter_actor_get_first_child:
16715 * @self: a #ClutterActor
16717 * Retrieves the first child of @self.
16719 * The returned pointer is only valid until the scene graph changes; it
16720 * is not safe to modify the list of children of @self while iterating
16723 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16728 clutter_actor_get_first_child (ClutterActor *self)
16730 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16732 return self->priv->first_child;
16736 * clutter_actor_get_last_child:
16737 * @self: a #ClutterActor
16739 * Retrieves the last child of @self.
16741 * The returned pointer is only valid until the scene graph changes; it
16742 * is not safe to modify the list of children of @self while iterating
16745 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16750 clutter_actor_get_last_child (ClutterActor *self)
16752 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16754 return self->priv->last_child;
16757 /* easy way to have properly named fields instead of the dummy ones
16758 * we use in the public structure
16760 typedef struct _RealActorIter
16762 ClutterActor *root; /* dummy1 */
16763 ClutterActor *current; /* dummy2 */
16764 gpointer padding_1; /* dummy3 */
16765 gint age; /* dummy4 */
16766 gpointer padding_2; /* dummy5 */
16770 * clutter_actor_iter_init:
16771 * @iter: a #ClutterActorIter
16772 * @root: a #ClutterActor
16774 * Initializes a #ClutterActorIter, which can then be used to iterate
16775 * efficiently over a section of the scene graph, and associates it
16778 * Modifying the scene graph section that contains @root will invalidate
16782 * ClutterActorIter iter;
16783 * ClutterActor *child;
16785 * clutter_actor_iter_init (&iter, container);
16786 * while (clutter_actor_iter_next (&iter, &child))
16788 * /* do something with child */
16795 clutter_actor_iter_init (ClutterActorIter *iter,
16796 ClutterActor *root)
16798 RealActorIter *ri = (RealActorIter *) iter;
16800 g_return_if_fail (iter != NULL);
16801 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16804 ri->current = NULL;
16805 ri->age = root->priv->age;
16809 * clutter_actor_iter_next:
16810 * @iter: a #ClutterActorIter
16811 * @child: (out): return location for a #ClutterActor
16813 * Advances the @iter and retrieves the next child of the root #ClutterActor
16814 * that was used to initialize the #ClutterActorIterator.
16816 * If the iterator can advance, this function returns %TRUE and sets the
16819 * If the iterator cannot advance, this function returns %FALSE, and
16820 * the contents of @child are undefined.
16822 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16827 clutter_actor_iter_next (ClutterActorIter *iter,
16828 ClutterActor **child)
16830 RealActorIter *ri = (RealActorIter *) iter;
16832 g_return_val_if_fail (iter != NULL, FALSE);
16833 g_return_val_if_fail (ri->root != NULL, FALSE);
16834 #ifndef G_DISABLE_ASSERT
16835 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16838 if (ri->current == NULL)
16839 ri->current = ri->root->priv->first_child;
16841 ri->current = ri->current->priv->next_sibling;
16844 *child = ri->current;
16846 return ri->current != NULL;
16850 * clutter_actor_iter_prev:
16851 * @iter: a #ClutterActorIter
16852 * @child: (out): return location for a #ClutterActor
16854 * Advances the @iter and retrieves the previous child of the root
16855 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16857 * If the iterator can advance, this function returns %TRUE and sets the
16860 * If the iterator cannot advance, this function returns %FALSE, and
16861 * the contents of @child are undefined.
16863 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16868 clutter_actor_iter_prev (ClutterActorIter *iter,
16869 ClutterActor **child)
16871 RealActorIter *ri = (RealActorIter *) iter;
16873 g_return_val_if_fail (iter != NULL, FALSE);
16874 g_return_val_if_fail (ri->root != NULL, FALSE);
16875 #ifndef G_DISABLE_ASSERT
16876 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16879 if (ri->current == NULL)
16880 ri->current = ri->root->priv->last_child;
16882 ri->current = ri->current->priv->prev_sibling;
16885 *child = ri->current;
16887 return ri->current != NULL;
16891 * clutter_actor_iter_remove:
16892 * @iter: a #ClutterActorIter
16894 * Safely removes the #ClutterActor currently pointer to by the iterator
16897 * This function can only be called after clutter_actor_iter_next() or
16898 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16899 * than once for the same actor.
16901 * This function will call clutter_actor_remove_child() internally.
16906 clutter_actor_iter_remove (ClutterActorIter *iter)
16908 RealActorIter *ri = (RealActorIter *) iter;
16911 g_return_if_fail (iter != NULL);
16912 g_return_if_fail (ri->root != NULL);
16913 #ifndef G_DISABLE_ASSERT
16914 g_return_if_fail (ri->age == ri->root->priv->age);
16916 g_return_if_fail (ri->current != NULL);
16922 ri->current = cur->priv->prev_sibling;
16924 clutter_actor_remove_child_internal (ri->root, cur,
16925 REMOVE_CHILD_DEFAULT_FLAGS);
16932 * clutter_actor_iter_destroy:
16933 * @iter: a #ClutterActorIter
16935 * Safely destroys the #ClutterActor currently pointer to by the iterator
16938 * This function can only be called after clutter_actor_iter_next() or
16939 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16940 * than once for the same actor.
16942 * This function will call clutter_actor_destroy() internally.
16947 clutter_actor_iter_destroy (ClutterActorIter *iter)
16949 RealActorIter *ri = (RealActorIter *) iter;
16952 g_return_if_fail (iter != NULL);
16953 g_return_if_fail (ri->root != NULL);
16954 #ifndef G_DISABLE_ASSERT
16955 g_return_if_fail (ri->age == ri->root->priv->age);
16957 g_return_if_fail (ri->current != NULL);
16963 ri->current = cur->priv->prev_sibling;
16965 clutter_actor_destroy (cur);
16971 static const ClutterAnimationInfo default_animation_info = {
16972 NULL, /* transitions */
16974 NULL, /* cur_state */
16978 clutter_animation_info_free (gpointer data)
16982 ClutterAnimationInfo *info = data;
16984 if (info->transitions != NULL)
16985 g_hash_table_unref (info->transitions);
16987 if (info->states != NULL)
16988 g_array_unref (info->states);
16990 g_slice_free (ClutterAnimationInfo, info);
16994 const ClutterAnimationInfo *
16995 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16997 const ClutterAnimationInfo *res;
16998 GObject *obj = G_OBJECT (self);
17000 res = g_object_get_qdata (obj, quark_actor_animation_info);
17004 return &default_animation_info;
17007 ClutterAnimationInfo *
17008 _clutter_actor_get_animation_info (ClutterActor *self)
17010 GObject *obj = G_OBJECT (self);
17011 ClutterAnimationInfo *res;
17013 res = g_object_get_qdata (obj, quark_actor_animation_info);
17016 res = g_slice_new (ClutterAnimationInfo);
17018 *res = default_animation_info;
17020 g_object_set_qdata_full (obj, quark_actor_animation_info,
17022 clutter_animation_info_free);
17028 ClutterTransition *
17029 _clutter_actor_get_transition (ClutterActor *actor,
17032 const ClutterAnimationInfo *info;
17034 info = _clutter_actor_get_animation_info_or_defaults (actor);
17036 if (info->transitions == NULL)
17039 return g_hash_table_lookup (info->transitions, pspec->name);
17042 typedef struct _TransitionClosure
17044 ClutterActor *actor;
17045 ClutterTransition *transition;
17047 gulong completed_id;
17048 } TransitionClosure;
17051 transition_closure_free (gpointer data)
17053 if (G_LIKELY (data != NULL))
17055 TransitionClosure *clos = data;
17056 ClutterTimeline *timeline;
17058 timeline = CLUTTER_TIMELINE (clos->transition);
17060 if (clutter_timeline_is_playing (timeline))
17061 clutter_timeline_stop (timeline);
17063 g_signal_handler_disconnect (clos->transition, clos->completed_id);
17065 g_object_unref (clos->transition);
17066 g_free (clos->name);
17068 g_slice_free (TransitionClosure, clos);
17073 on_transition_completed (ClutterTransition *transition,
17074 TransitionClosure *clos)
17076 ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17077 ClutterActor *actor = clos->actor;
17078 ClutterAnimationInfo *info;
17079 gint n_repeats, cur_repeat;
17081 info = _clutter_actor_get_animation_info (actor);
17083 /* reset the caches used by animations */
17084 clutter_actor_store_content_box (actor, NULL);
17086 /* ensure that we remove the transition only at the end
17087 * of its run; we emit ::completed for every repeat
17089 n_repeats = clutter_timeline_get_repeat_count (timeline);
17090 cur_repeat = clutter_timeline_get_current_repeat (timeline);
17092 if (cur_repeat == n_repeats)
17094 if (clutter_transition_get_remove_on_complete (transition))
17096 /* we take a reference here because removing the closure
17097 * will release the reference on the transition, and we
17098 * want the transition to survive the signal emission;
17099 * the master clock will release the last reference at
17100 * the end of the frame processing.
17102 g_object_ref (transition);
17103 g_hash_table_remove (info->transitions, clos->name);
17107 /* if it's the last transition then we clean up */
17108 if (g_hash_table_size (info->transitions) == 0)
17110 g_hash_table_unref (info->transitions);
17111 info->transitions = NULL;
17113 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17114 _clutter_actor_get_debug_name (actor));
17116 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17121 _clutter_actor_update_transition (ClutterActor *actor,
17125 TransitionClosure *clos;
17126 ClutterTimeline *timeline;
17127 ClutterInterval *interval;
17128 const ClutterAnimationInfo *info;
17131 GValue initial = G_VALUE_INIT;
17132 GValue final = G_VALUE_INIT;
17133 char *error = NULL;
17135 info = _clutter_actor_get_animation_info_or_defaults (actor);
17137 if (info->transitions == NULL)
17140 clos = g_hash_table_lookup (info->transitions, pspec->name);
17144 timeline = CLUTTER_TIMELINE (clos->transition);
17146 va_start (var_args, pspec);
17148 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17150 g_value_init (&initial, ptype);
17151 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17155 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17158 g_critical ("%s: %s", G_STRLOC, error);
17163 interval = clutter_transition_get_interval (clos->transition);
17164 clutter_interval_set_initial_value (interval, &initial);
17165 clutter_interval_set_final_value (interval, &final);
17167 /* if we're updating with an easing duration of zero milliseconds,
17168 * we just jump the timeline to the end and let it run its course
17170 if (info->cur_state != NULL &&
17171 info->cur_state->easing_duration != 0)
17173 guint cur_duration = clutter_timeline_get_duration (timeline);
17174 ClutterAnimationMode cur_mode =
17175 clutter_timeline_get_progress_mode (timeline);
17177 if (cur_duration != info->cur_state->easing_duration)
17178 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17180 if (cur_mode != info->cur_state->easing_mode)
17181 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17183 clutter_timeline_rewind (timeline);
17187 guint duration = clutter_timeline_get_duration (timeline);
17189 clutter_timeline_advance (timeline, duration);
17193 g_value_unset (&initial);
17194 g_value_unset (&final);
17200 * _clutter_actor_create_transition:
17201 * @actor: a #ClutterActor
17202 * @pspec: the property used for the transition
17203 * @...: initial and final state
17205 * Creates a #ClutterTransition for the property represented by @pspec.
17207 * Return value: a #ClutterTransition
17209 ClutterTransition *
17210 _clutter_actor_create_transition (ClutterActor *actor,
17214 ClutterAnimationInfo *info;
17215 ClutterTransition *res = NULL;
17216 gboolean call_restore = FALSE;
17217 TransitionClosure *clos;
17220 info = _clutter_actor_get_animation_info (actor);
17222 /* XXX - this will go away in 2.0
17224 * if no state has been pushed, we assume that the easing state is
17225 * in "compatibility mode": all transitions have a duration of 0
17226 * msecs, which means that they happen immediately. in Clutter 2.0
17227 * this will turn into a g_assert(info->states != NULL), as every
17228 * actor will start with a predefined easing state
17230 if (info->states == NULL)
17232 clutter_actor_save_easing_state (actor);
17233 clutter_actor_set_easing_duration (actor, 0);
17234 call_restore = TRUE;
17237 if (info->transitions == NULL)
17238 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17240 transition_closure_free);
17242 va_start (var_args, pspec);
17244 clos = g_hash_table_lookup (info->transitions, pspec->name);
17247 ClutterInterval *interval;
17248 GValue initial = G_VALUE_INIT;
17249 GValue final = G_VALUE_INIT;
17253 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17255 G_VALUE_COLLECT_INIT (&initial, ptype,
17260 g_critical ("%s: %s", G_STRLOC, error);
17265 G_VALUE_COLLECT_INIT (&final, ptype,
17271 g_critical ("%s: %s", G_STRLOC, error);
17272 g_value_unset (&initial);
17277 /* if the current easing state has a duration of 0, then we don't
17278 * bother to create the transition, and we just set the final value
17279 * directly on the actor; we don't go through the Animatable
17280 * interface because we know we got here through an animatable
17283 if (info->cur_state->easing_duration == 0)
17285 clutter_actor_set_animatable_property (actor,
17289 g_value_unset (&initial);
17290 g_value_unset (&final);
17295 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17297 g_value_unset (&initial);
17298 g_value_unset (&final);
17300 res = clutter_property_transition_new (pspec->name);
17302 clutter_transition_set_interval (res, interval);
17303 clutter_transition_set_remove_on_complete (res, TRUE);
17305 /* this will start the transition as well */
17306 clutter_actor_add_transition (actor, pspec->name, res);
17308 /* the actor now owns the transition */
17309 g_object_unref (res);
17312 res = clos->transition;
17316 clutter_actor_restore_easing_state (actor);
17324 * clutter_actor_add_transition:
17325 * @self: a #ClutterActor
17326 * @name: the name of the transition to add
17327 * @transition: the #ClutterTransition to add
17329 * Adds a @transition to the #ClutterActor's list of animations.
17331 * The @name string is a per-actor unique identifier of the @transition: only
17332 * one #ClutterTransition can be associated to the specified @name.
17334 * The @transition will be given the easing duration, mode, and delay
17335 * associated to the actor's current easing state; it is possible to modify
17336 * these values after calling clutter_actor_add_transition().
17338 * The @transition will be started once added.
17340 * This function will take a reference on the @transition.
17342 * This function is usually called implicitly when modifying an animatable
17348 clutter_actor_add_transition (ClutterActor *self,
17350 ClutterTransition *transition)
17352 ClutterTimeline *timeline;
17353 TransitionClosure *clos;
17354 ClutterAnimationInfo *info;
17356 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17357 g_return_if_fail (name != NULL);
17358 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17360 info = _clutter_actor_get_animation_info (self);
17362 if (info->cur_state == NULL)
17364 g_warning ("No easing state is defined for the actor '%s'; you "
17365 "must call clutter_actor_save_easing_state() before "
17366 "calling clutter_actor_add_transition().",
17367 _clutter_actor_get_debug_name (self));
17371 if (info->transitions == NULL)
17372 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17374 transition_closure_free);
17376 if (g_hash_table_lookup (info->transitions, name) != NULL)
17378 g_warning ("A transition with name '%s' already exists for "
17381 _clutter_actor_get_debug_name (self));
17385 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17387 timeline = CLUTTER_TIMELINE (transition);
17389 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17390 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17391 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17393 clos = g_slice_new (TransitionClosure);
17394 clos->actor = self;
17395 clos->transition = g_object_ref (transition);
17396 clos->name = g_strdup (name);
17397 clos->completed_id = g_signal_connect (timeline, "completed",
17398 G_CALLBACK (on_transition_completed),
17401 CLUTTER_NOTE (ANIMATION,
17402 "Adding transition '%s' [%p] to actor '%s'",
17405 _clutter_actor_get_debug_name (self));
17407 g_hash_table_insert (info->transitions, clos->name, clos);
17408 clutter_timeline_start (timeline);
17412 * clutter_actor_remove_transition:
17413 * @self: a #ClutterActor
17414 * @name: the name of the transition to remove
17416 * Removes the transition stored inside a #ClutterActor using @name
17419 * If the transition is currently in progress, it will be stopped.
17421 * This function releases the reference acquired when the transition
17422 * was added to the #ClutterActor.
17427 clutter_actor_remove_transition (ClutterActor *self,
17430 const ClutterAnimationInfo *info;
17432 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17433 g_return_if_fail (name != NULL);
17435 info = _clutter_actor_get_animation_info_or_defaults (self);
17437 if (info->transitions == NULL)
17440 g_hash_table_remove (info->transitions, name);
17444 * clutter_actor_remove_all_transitions:
17445 * @self: a #ClutterActor
17447 * Removes all transitions associated to @self.
17452 clutter_actor_remove_all_transitions (ClutterActor *self)
17454 const ClutterAnimationInfo *info;
17456 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17458 info = _clutter_actor_get_animation_info_or_defaults (self);
17459 if (info->transitions == NULL)
17462 g_hash_table_remove_all (info->transitions);
17466 * clutter_actor_set_easing_duration:
17467 * @self: a #ClutterActor
17468 * @msecs: the duration of the easing, or %NULL
17470 * Sets the duration of the tweening for animatable properties
17471 * of @self for the current easing state.
17476 clutter_actor_set_easing_duration (ClutterActor *self,
17479 ClutterAnimationInfo *info;
17481 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17483 info = _clutter_actor_get_animation_info (self);
17485 if (info->cur_state == NULL)
17487 g_warning ("You must call clutter_actor_save_easing_state() prior "
17488 "to calling clutter_actor_set_easing_duration().");
17492 if (info->cur_state->easing_duration != msecs)
17493 info->cur_state->easing_duration = msecs;
17497 * clutter_actor_get_easing_duration:
17498 * @self: a #ClutterActor
17500 * Retrieves the duration of the tweening for animatable
17501 * properties of @self for the current easing state.
17503 * Return value: the duration of the tweening, in milliseconds
17508 clutter_actor_get_easing_duration (ClutterActor *self)
17510 const ClutterAnimationInfo *info;
17512 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17514 info = _clutter_actor_get_animation_info_or_defaults (self);
17516 if (info->cur_state != NULL)
17517 return info->cur_state->easing_duration;
17523 * clutter_actor_set_easing_mode:
17524 * @self: a #ClutterActor
17525 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17527 * Sets the easing mode for the tweening of animatable properties
17533 clutter_actor_set_easing_mode (ClutterActor *self,
17534 ClutterAnimationMode mode)
17536 ClutterAnimationInfo *info;
17538 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17539 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17540 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17542 info = _clutter_actor_get_animation_info (self);
17544 if (info->cur_state == NULL)
17546 g_warning ("You must call clutter_actor_save_easing_state() prior "
17547 "to calling clutter_actor_set_easing_mode().");
17551 if (info->cur_state->easing_mode != mode)
17552 info->cur_state->easing_mode = mode;
17556 * clutter_actor_get_easing_mode:
17557 * @self: a #ClutterActor
17559 * Retrieves the easing mode for the tweening of animatable properties
17560 * of @self for the current easing state.
17562 * Return value: an easing mode
17566 ClutterAnimationMode
17567 clutter_actor_get_easing_mode (ClutterActor *self)
17569 const ClutterAnimationInfo *info;
17571 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17573 info = _clutter_actor_get_animation_info_or_defaults (self);
17575 if (info->cur_state != NULL)
17576 return info->cur_state->easing_mode;
17578 return CLUTTER_EASE_OUT_CUBIC;
17582 * clutter_actor_set_easing_delay:
17583 * @self: a #ClutterActor
17584 * @msecs: the delay before the start of the tweening, in milliseconds
17586 * Sets the delay that should be applied before tweening animatable
17592 clutter_actor_set_easing_delay (ClutterActor *self,
17595 ClutterAnimationInfo *info;
17597 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17599 info = _clutter_actor_get_animation_info (self);
17601 if (info->cur_state == NULL)
17603 g_warning ("You must call clutter_actor_save_easing_state() prior "
17604 "to calling clutter_actor_set_easing_delay().");
17608 if (info->cur_state->easing_delay != msecs)
17609 info->cur_state->easing_delay = msecs;
17613 * clutter_actor_get_easing_delay:
17614 * @self: a #ClutterActor
17616 * Retrieves the delay that should be applied when tweening animatable
17619 * Return value: a delay, in milliseconds
17624 clutter_actor_get_easing_delay (ClutterActor *self)
17626 const ClutterAnimationInfo *info;
17628 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17630 info = _clutter_actor_get_animation_info_or_defaults (self);
17632 if (info->cur_state != NULL)
17633 return info->cur_state->easing_delay;
17639 * clutter_actor_get_transition:
17640 * @self: a #ClutterActor
17641 * @name: the name of the transition
17643 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17644 * transition @name.
17646 * Transitions created for animatable properties use the name of the
17647 * property itself, for instance the code below:
17650 * clutter_actor_set_easing_duration (actor, 1000);
17651 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17653 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17654 * g_signal_connect (transition, "completed",
17655 * G_CALLBACK (on_transition_complete),
17659 * will call the <function>on_transition_complete</function> callback when
17660 * the transition is complete.
17662 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17663 * was found to match the passed name; the returned instance is owned
17664 * by Clutter and it should not be freed
17668 ClutterTransition *
17669 clutter_actor_get_transition (ClutterActor *self,
17672 TransitionClosure *clos;
17673 const ClutterAnimationInfo *info;
17675 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17676 g_return_val_if_fail (name != NULL, NULL);
17678 info = _clutter_actor_get_animation_info_or_defaults (self);
17679 if (info->transitions == NULL)
17682 clos = g_hash_table_lookup (info->transitions, name);
17686 return clos->transition;
17690 * clutter_actor_save_easing_state:
17691 * @self: a #ClutterActor
17693 * Saves the current easing state for animatable properties, and creates
17694 * a new state with the default values for easing mode and duration.
17699 clutter_actor_save_easing_state (ClutterActor *self)
17701 ClutterAnimationInfo *info;
17704 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17706 info = _clutter_actor_get_animation_info (self);
17708 if (info->states == NULL)
17709 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17711 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17712 new_state.easing_duration = 250;
17713 new_state.easing_delay = 0;
17715 g_array_append_val (info->states, new_state);
17717 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17721 * clutter_actor_restore_easing_state:
17722 * @self: a #ClutterActor
17724 * Restores the easing state as it was prior to a call to
17725 * clutter_actor_save_easing_state().
17730 clutter_actor_restore_easing_state (ClutterActor *self)
17732 ClutterAnimationInfo *info;
17734 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17736 info = _clutter_actor_get_animation_info (self);
17738 if (info->states == NULL)
17740 g_critical ("The function clutter_actor_restore_easing_state() has "
17741 "called without a previous call to "
17742 "clutter_actor_save_easing_state().");
17746 g_array_remove_index (info->states, info->states->len - 1);
17748 if (info->states->len > 0)
17749 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17752 g_array_unref (info->states);
17753 info->states = NULL;
17754 info->cur_state = NULL;
17759 * clutter_actor_set_content:
17760 * @self: a #ClutterActor
17761 * @content: (allow-none): a #ClutterContent, or %NULL
17763 * Sets the contents of a #ClutterActor.
17768 clutter_actor_set_content (ClutterActor *self,
17769 ClutterContent *content)
17771 ClutterActorPrivate *priv;
17773 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17774 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17778 if (priv->content != NULL)
17780 _clutter_content_detached (priv->content, self);
17781 g_clear_object (&priv->content);
17784 priv->content = content;
17786 if (priv->content != NULL)
17788 g_object_ref (priv->content);
17789 _clutter_content_attached (priv->content, self);
17792 /* given that the content is always painted within the allocation,
17793 * we only need to queue a redraw here
17795 clutter_actor_queue_redraw (self);
17797 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17799 /* if the content gravity is not resize-fill, and the new content has a
17800 * different preferred size than the previous one, then the content box
17801 * may have been changed. since we compute that lazily, we just notify
17802 * here, and let whomever watches :content-box do whatever they need to
17805 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17806 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17810 * clutter_actor_get_content:
17811 * @self: a #ClutterActor
17813 * Retrieves the contents of @self.
17815 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17816 * or %NULL if none was set
17821 clutter_actor_get_content (ClutterActor *self)
17823 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17825 return self->priv->content;
17829 * clutter_actor_set_content_gravity:
17830 * @self: a #ClutterActor
17831 * @gravity: the #ClutterContentGravity
17833 * Sets the gravity of the #ClutterContent used by @self.
17835 * See the description of the #ClutterActor:content-gravity property for
17836 * more information.
17838 * The #ClutterActor:content-gravity property is animatable.
17843 clutter_actor_set_content_gravity (ClutterActor *self,
17844 ClutterContentGravity gravity)
17846 ClutterActorPrivate *priv;
17848 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17852 if (priv->content_gravity == gravity)
17855 priv->content_box_valid = FALSE;
17857 if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17859 ClutterActorBox from_box, to_box;
17861 clutter_actor_get_content_box (self, &from_box);
17863 priv->content_gravity = gravity;
17865 clutter_actor_get_content_box (self, &to_box);
17867 _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17873 ClutterActorBox to_box;
17875 priv->content_gravity = gravity;
17877 clutter_actor_get_content_box (self, &to_box);
17879 _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17883 clutter_actor_queue_redraw (self);
17885 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17889 * clutter_actor_get_content_gravity:
17890 * @self: a #ClutterActor
17892 * Retrieves the content gravity as set using
17893 * clutter_actor_get_content_gravity().
17895 * Return value: the content gravity
17899 ClutterContentGravity
17900 clutter_actor_get_content_gravity (ClutterActor *self)
17902 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17903 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17905 return self->priv->content_gravity;
17909 * clutter_actor_get_content_box:
17910 * @self: a #ClutterActor
17911 * @box: (out caller-allocates): the return location for the bounding
17912 * box for the #ClutterContent
17914 * Retrieves the bounding box for the #ClutterContent of @self.
17916 * The bounding box is relative to the actor's allocation.
17918 * If no #ClutterContent is set for @self, or if @self has not been
17919 * allocated yet, then the result is undefined.
17921 * The content box is guaranteed to be, at most, as big as the allocation
17922 * of the #ClutterActor.
17924 * If the #ClutterContent used by the actor has a preferred size, then
17925 * it is possible to modify the content box by using the
17926 * #ClutterActor:content-gravity property.
17931 clutter_actor_get_content_box (ClutterActor *self,
17932 ClutterActorBox *box)
17934 ClutterActorPrivate *priv;
17935 gfloat content_w, content_h;
17936 gfloat alloc_w, alloc_h;
17938 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17939 g_return_if_fail (box != NULL);
17945 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17946 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17948 if (priv->content_box_valid)
17950 *box = priv->content_box;
17954 /* no need to do any more work */
17955 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17958 if (priv->content == NULL)
17961 /* if the content does not have a preferred size then there is
17962 * no point in computing the content box
17964 if (!clutter_content_get_preferred_size (priv->content,
17972 switch (priv->content_gravity)
17974 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17975 box->x2 = box->x1 + MIN (content_w, alloc_w);
17976 box->y2 = box->y1 + MIN (content_h, alloc_h);
17979 case CLUTTER_CONTENT_GRAVITY_TOP:
17980 if (alloc_w > content_w)
17982 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17983 box->x2 = box->x1 + content_w;
17985 box->y2 = box->y1 + MIN (content_h, alloc_h);
17988 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17989 if (alloc_w > content_w)
17991 box->x1 += (alloc_w - content_w);
17992 box->x2 = box->x1 + content_w;
17994 box->y2 = box->y1 + MIN (content_h, alloc_h);
17997 case CLUTTER_CONTENT_GRAVITY_LEFT:
17998 box->x2 = box->x1 + MIN (content_w, alloc_w);
17999 if (alloc_h > content_h)
18001 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18002 box->y2 = box->y1 + content_h;
18006 case CLUTTER_CONTENT_GRAVITY_CENTER:
18007 if (alloc_w > content_w)
18009 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18010 box->x2 = box->x1 + content_w;
18012 if (alloc_h > content_h)
18014 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18015 box->y2 = box->y1 + content_h;
18019 case CLUTTER_CONTENT_GRAVITY_RIGHT:
18020 if (alloc_w > content_w)
18022 box->x1 += (alloc_w - content_w);
18023 box->x2 = box->x1 + content_w;
18025 if (alloc_h > content_h)
18027 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18028 box->y2 = box->y1 + content_h;
18032 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18033 box->x2 = box->x1 + MIN (content_w, alloc_w);
18034 if (alloc_h > content_h)
18036 box->y1 += (alloc_h - content_h);
18037 box->y2 = box->y1 + content_h;
18041 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18042 if (alloc_w > content_w)
18044 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18045 box->x2 = box->x1 + content_w;
18047 if (alloc_h > content_h)
18049 box->y1 += (alloc_h - content_h);
18050 box->y2 = box->y1 + content_h;
18054 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18055 if (alloc_w > content_w)
18057 box->x1 += (alloc_w - content_w);
18058 box->x2 = box->x1 + content_w;
18060 if (alloc_h > content_h)
18062 box->y1 += (alloc_h - content_h);
18063 box->y2 = box->y1 + content_h;
18067 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18068 g_assert_not_reached ();
18071 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18073 double r_c = content_w / content_h;
18074 double r_a = alloc_w / alloc_h;
18083 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18084 box->y2 = box->y1 + (alloc_w * r_c);
18091 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18092 box->x2 = box->x1 + (alloc_h * r_c);
18102 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18103 box->x2 = box->x1 + (alloc_h * r_c);
18110 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18111 box->y2 = box->y1 + (alloc_w * r_c);
18120 * clutter_actor_set_content_scaling_filters:
18121 * @self: a #ClutterActor
18122 * @min_filter: the minification filter for the content
18123 * @mag_filter: the magnification filter for the content
18125 * Sets the minification and magnification filter to be applied when
18126 * scaling the #ClutterActor:content of a #ClutterActor.
18128 * The #ClutterActor:minification-filter will be used when reducing
18129 * the size of the content; the #ClutterActor:magnification-filter
18130 * will be used when increasing the size of the content.
18135 clutter_actor_set_content_scaling_filters (ClutterActor *self,
18136 ClutterScalingFilter min_filter,
18137 ClutterScalingFilter mag_filter)
18139 ClutterActorPrivate *priv;
18143 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18146 obj = G_OBJECT (self);
18148 g_object_freeze_notify (obj);
18152 if (priv->min_filter != min_filter)
18154 priv->min_filter = min_filter;
18157 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18160 if (priv->mag_filter != mag_filter)
18162 priv->mag_filter = mag_filter;
18165 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18169 clutter_actor_queue_redraw (self);
18171 g_object_thaw_notify (obj);
18175 * clutter_actor_get_content_scaling_filters:
18176 * @self: a #ClutterActor
18177 * @min_filter: (out) (allow-none): return location for the minification
18179 * @mag_filter: (out) (allow-none): return location for the magnification
18182 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18187 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18188 ClutterScalingFilter *min_filter,
18189 ClutterScalingFilter *mag_filter)
18191 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18193 if (min_filter != NULL)
18194 *min_filter = self->priv->min_filter;
18196 if (mag_filter != NULL)
18197 *mag_filter = self->priv->mag_filter;