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>
263 * <title>Explicit animations</title>
264 * <para>The explicit animation model supported by Clutter requires that
265 * you create a #ClutterTransition object, and set the initial and
266 * final values. The transition will not start unless you add it to the
267 * #ClutterActor.</para>
268 * <informalexample><programlisting>
269 * ClutterTransition *transition;
271 * transition = clutter_property_transition_new ("opacity");
272 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
273 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
274 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
275 * clutter_transition_set_interval (transition, clutter_interval_new (G_TYPE_UINT, 255, 0));
277 * clutter_actor_add_transition (actor, "animate-opacity", transition);
278 * </programlisting></informalexample>
279 * <para>The example above will animate the #ClutterActor:opacity property
280 * of an actor between fully opaque and fully transparent, and back, over
281 * a span of 3 seconds. The animation does not begin until it is added to
283 * <para>The explicit animation API should also be used when using custom
284 * animatable properties for #ClutterAction, #ClutterConstraint, and
285 * #ClutterEffect instances associated to an actor; see the section on
286 * <ulink linkend="ClutterActor-custom-animatable-properties">custom
287 * animatable properties below</ulink> for an example.</para>
288 * <para>Finally, explicit animations are useful for creating animations
289 * that run continuously, for instance:</para>
290 * <informalexample><programlisting>
291 * /* this animation will pulse the actor's opacity continuously */
292 * ClutterTransition *transition;
293 * ClutterInterval *interval;
295 * transition = clutter_property_transition_new ("opacity");
297 * /* we want to animate the opacity between 0 and 255 */
298 * internal = clutter_interval_new (G_TYPE_UINT, 0, 255);
299 * clutter_transition_set_interval (transition, interval);
301 * /* over a one second duration, running an infinite amount of times */
302 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
303 * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
305 * /* we want to fade in and out, so we need to auto-reverse the transition */
306 * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
308 * /* and we want to use an easing function that eases both in and out */
309 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
310 * CLUTTER_EASE_IN_OUT_CUBIC);
312 * /* add the transition to the desired actor; this will
313 * * start the animation.
315 * clutter_actor_add_transition (actor, "opacityAnimation", transition);
316 * </programlisting></informalexample>
320 * <refsect2 id="ClutterActor-subclassing">
321 * <title>Implementing an actor</title>
322 * <para>Careful consideration should be given when deciding to implement
323 * a #ClutterActor sub-class. It is generally recommended to implement a
324 * sub-class of #ClutterActor only for actors that should be used as leaf
325 * nodes of a scene graph.</para>
326 * <para>If your actor should be painted in a custom way, you should
327 * override the #ClutterActor::paint signal class handler. You can either
328 * opt to chain up to the parent class implementation or decide to fully
329 * override the default paint implementation; Clutter will set up the
330 * transformations and clip regions prior to emitting the #ClutterActor::paint
332 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
333 * #ClutterActorClass.get_preferred_height() virtual functions it is
334 * possible to change or provide the preferred size of an actor; similarly,
335 * by overriding the #ClutterActorClass.allocate() virtual function it is
336 * possible to control the layout of the children of an actor. Make sure to
337 * always chain up to the parent implementation of the
338 * #ClutterActorClass.allocate() virtual function.</para>
339 * <para>In general, it is strongly encouraged to use delegation and
340 * composition instead of direct subclassing.</para>
343 * <refsect2 id="ClutterActor-script">
344 * <title>ClutterActor custom properties for #ClutterScript</title>
345 * <para>#ClutterActor defines a custom "rotation" property which
346 * allows a short-hand description of the rotations to be applied
347 * to an actor.</para>
348 * <para>The syntax of the "rotation" property is the following:</para>
352 * { "<axis>" : [ <angle>, [ <center> ] ] }
356 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
357 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
358 * floating point value representing the rotation angle on the given axis,
360 * <para>The <emphasis>center</emphasis> array is optional, and if present
361 * it must contain the center of rotation as described by two coordinates:
362 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
364 * <para>#ClutterActor will also parse every positional and dimensional
365 * property defined as a string through clutter_units_from_string(); you
366 * should read the documentation for the #ClutterUnits parser format for
367 * the valid units and syntax.</para>
370 * <refsect2 id="ClutterActor-custom-animatable-properties">
371 * <title>Custom animatable properties</title>
372 * <para>#ClutterActor allows accessing properties of #ClutterAction,
373 * #ClutterEffect, and #ClutterConstraint instances associated to an actor
374 * instance for animation purposes.</para>
375 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
376 * property it is necessary to set the #ClutterActorMeta:name property on the
377 * given action or constraint.</para>
378 * <para>The property can be accessed using the following syntax:</para>
381 * @<section>.<meta-name>.<property-name>
384 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
385 * <para>The <emphasis>section</emphasis> fragment can be one between
386 * "actions", "constraints" and "effects".</para>
387 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
388 * action or constraint, as specified by the #ClutterActorMeta:name
390 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
391 * action or constraint property to be animated.</para>
392 * <para>The example below animates a #ClutterBindConstraint applied to an
393 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
394 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
395 * its initial state is overlapping the actor to which is bound to.</para>
396 * <informalexample><programlisting>
397 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
398 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
399 * clutter_actor_add_constraint (rect, constraint);
401 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
402 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
403 * clutter_actor_add_constraint (rect, constraint);
405 * clutter_actor_set_reactive (origin, TRUE);
407 * g_signal_connect (origin, "button-press-event",
408 * G_CALLBACK (on_button_press),
410 * </programlisting></informalexample>
411 * <para>On button press, the rectangle "slides" from behind the actor to
412 * which is bound to, using the #ClutterBindConstraint:offset property to
413 * achieve the effect:</para>
414 * <informalexample><programlisting>
416 * on_button_press (ClutterActor *origin,
417 * ClutterEvent *event,
418 * ClutterActor *rect)
420 * ClutterTransition *transition;
421 * ClutterInterval *interval;
423 * /* the offset that we want to apply; this will make the actor
424 * * slide in from behind the origin and rest at the right of
425 * * the origin, plus a padding value.
427 * float new_offset = clutter_actor_get_width (origin) + h_padding;
429 * /* the property we wish to animate; the "@constraints" section
430 * * tells Clutter to check inside the constraints associated
431 * * with the actor; the "bind-x" section is the name of the
432 * * constraint; and the "offset" is the name of the property
433 * * on the constraint.
435 * const char *prop = "@constraints.bind-x.offset";
437 * /* create a new transition for the given property */
438 * transition = clutter_property_transition_new (prop);
440 * /* set the easing mode and duration */
441 * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
442 * CLUTTER_EASE_OUT_CUBIC);
443 * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
445 * /* create the interval with the initial and final values */
446 * interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
447 * clutter_transition_set_interval (transition, interval);
449 * /* add the transition to the actor; this causes the animation
450 * * to start. the name "offsetAnimation" can be used to retrieve
451 * * the transition later.
453 * clutter_actor_add_transition (rect, "offsetAnimation", transition);
455 * /* we handled the event */
456 * return CLUTTER_EVENT_STOP;
458 * </programlisting></informalexample>
463 * CLUTTER_ACTOR_IS_MAPPED:
464 * @a: a #ClutterActor
466 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
468 * The mapped state is set when the actor is visible and all its parents up
469 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
471 * This check can be used to see if an actor is going to be painted, as only
472 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
474 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
475 * not be checked directly; instead, the recommended usage is to connect a
476 * handler on the #GObject::notify signal for the #ClutterActor:mapped
477 * property of #ClutterActor, and check the presence of
478 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
480 * It is also important to note that Clutter may delay the changes of
481 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
482 * limitations, or during the reparenting of an actor, to optimize
483 * unnecessary (and potentially expensive) state changes.
489 * CLUTTER_ACTOR_IS_REALIZED:
490 * @a: a #ClutterActor
492 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
494 * The realized state has an actor-dependant interpretation. If an
495 * actor wants to delay allocating resources until it is attached to a
496 * stage, it may use the realize state to do so. However it is
497 * perfectly acceptable for an actor to allocate Cogl resources before
498 * being realized because there is only one drawing context used by Clutter
499 * so any resources will work on any stage. If an actor is mapped it
500 * must also be realized, but an actor can be realized and unmapped
501 * (this is so hiding an actor temporarily doesn't do an expensive
502 * unrealize/realize).
504 * To be realized an actor must be inside a stage, and all its parents
511 * CLUTTER_ACTOR_IS_VISIBLE:
512 * @a: a #ClutterActor
514 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
515 * Equivalent to the ClutterActor::visible object property.
517 * Note that an actor is only painted onscreen if it's mapped, which
518 * means it's visible, and all its parents are visible, and one of the
519 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
525 * CLUTTER_ACTOR_IS_REACTIVE:
526 * @a: a #ClutterActor
528 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
530 * Only reactive actors will receive event-related signals.
541 #include <gobject/gvaluecollector.h>
543 #include <cogl/cogl.h>
545 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
546 #define CLUTTER_ENABLE_EXPERIMENTAL_API
548 #include "clutter-actor-private.h"
550 #include "clutter-action.h"
551 #include "clutter-actor-meta-private.h"
552 #include "clutter-animatable.h"
553 #include "clutter-color-static.h"
554 #include "clutter-color.h"
555 #include "clutter-constraint.h"
556 #include "clutter-container.h"
557 #include "clutter-content-private.h"
558 #include "clutter-debug.h"
559 #include "clutter-effect-private.h"
560 #include "clutter-enum-types.h"
561 #include "clutter-fixed-layout.h"
562 #include "clutter-flatten-effect.h"
563 #include "clutter-interval.h"
564 #include "clutter-main.h"
565 #include "clutter-marshal.h"
566 #include "clutter-paint-nodes.h"
567 #include "clutter-paint-node-private.h"
568 #include "clutter-paint-volume-private.h"
569 #include "clutter-private.h"
570 #include "clutter-profile.h"
571 #include "clutter-property-transition.h"
572 #include "clutter-scriptable.h"
573 #include "clutter-script-private.h"
574 #include "clutter-stage-private.h"
575 #include "clutter-timeline.h"
576 #include "clutter-transition.h"
577 #include "clutter-units.h"
579 #include "deprecated/clutter-actor.h"
580 #include "deprecated/clutter-behaviour.h"
581 #include "deprecated/clutter-container.h"
583 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
584 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
586 /* Internal enum used to control mapped state update. This is a hint
587 * which indicates when to do something other than just enforce
591 MAP_STATE_CHECK, /* just enforce invariants. */
592 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
593 * used when about to unparent.
595 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
596 * used to set mapped on toplevels.
598 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
599 * used just before unmapping parent.
603 /* 3 entries should be a good compromise, few layout managers
604 * will ask for 3 different preferred size in each allocation cycle */
605 #define N_CACHED_SIZE_REQUESTS 3
607 struct _ClutterActorPrivate
610 ClutterRequestMode request_mode;
612 /* our cached size requests for different width / height */
613 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
614 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
616 /* An age of 0 means the entry is not set */
617 guint cached_height_age;
618 guint cached_width_age;
620 /* the bounding box of the actor, relative to the parent's
623 ClutterActorBox allocation;
624 ClutterAllocationFlags allocation_flags;
626 /* clip, in actor coordinates */
627 cairo_rectangle_t clip;
629 /* the cached transformation matrix; see apply_transform() */
630 CoglMatrix transform;
633 gint opacity_override;
635 ClutterOffscreenRedirect offscreen_redirect;
637 /* This is an internal effect used to implement the
638 offscreen-redirect property */
639 ClutterEffect *flatten_effect;
642 ClutterActor *parent;
643 ClutterActor *prev_sibling;
644 ClutterActor *next_sibling;
645 ClutterActor *first_child;
646 ClutterActor *last_child;
650 /* tracks whenever the children of an actor are changed; the
651 * age is incremented by 1 whenever an actor is added or
652 * removed. the age is not incremented when the first or the
653 * last child pointers are changed, or when grandchildren of
654 * an actor are changed.
658 gchar *name; /* a non-unique name, used for debugging */
659 guint32 id; /* unique id, used for backward compatibility */
661 gint32 pick_id; /* per-stage unique id, used for picking */
663 /* a back-pointer to the Pango context that we can use
664 * to create pre-configured PangoLayout
666 PangoContext *pango_context;
668 /* the text direction configured for this child - either by
669 * application code, or by the actor's parent
671 ClutterTextDirection text_direction;
673 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
677 ClutterMetaGroup *actions;
678 ClutterMetaGroup *constraints;
679 ClutterMetaGroup *effects;
681 /* delegate object used to allocate the children of this actor */
682 ClutterLayoutManager *layout_manager;
684 /* delegate object used to paint the contents of this actor */
685 ClutterContent *content;
687 ClutterContentGravity content_gravity;
688 ClutterScalingFilter min_filter;
689 ClutterScalingFilter mag_filter;
691 /* used when painting, to update the paint volume */
692 ClutterEffect *current_effect;
694 /* This is used to store an effect which needs to be redrawn. A
695 redraw can be queued to start from a particular effect. This is
696 used by parametrised effects that can cache an image of the
697 actor. If a parameter of the effect changes then it only needs to
698 redraw the cached image, not the actual actor. The pointer is
699 only valid if is_dirty == TRUE. If the pointer is NULL then the
700 whole actor is dirty. */
701 ClutterEffect *effect_to_redraw;
703 /* This is used when painting effects to implement the
704 clutter_actor_continue_paint() function. It points to the node in
705 the list of effects that is next in the chain */
706 const GList *next_effect_to_paint;
708 ClutterPaintVolume paint_volume;
710 /* NB: This volume isn't relative to this actor, it is in eye
711 * coordinates so that it can remain valid after the actor changes.
713 ClutterPaintVolume last_paint_volume;
715 ClutterStageQueueRedrawEntry *queue_redraw_entry;
717 ClutterColor bg_color;
721 /* fixed position and sizes */
722 guint position_set : 1;
723 guint min_width_set : 1;
724 guint min_height_set : 1;
725 guint natural_width_set : 1;
726 guint natural_height_set : 1;
727 /* cached request is invalid (implies allocation is too) */
728 guint needs_width_request : 1;
729 /* cached request is invalid (implies allocation is too) */
730 guint needs_height_request : 1;
731 /* cached allocation is invalid (request has changed, probably) */
732 guint needs_allocation : 1;
733 guint show_on_set_parent : 1;
735 guint clip_to_allocation : 1;
736 guint enable_model_view_transform : 1;
737 guint enable_paint_unmapped : 1;
738 guint has_pointer : 1;
739 guint propagated_one_redraw : 1;
740 guint paint_volume_valid : 1;
741 guint last_paint_volume_valid : 1;
742 guint in_clone_paint : 1;
743 guint transform_valid : 1;
744 /* This is TRUE if anything has queued a redraw since we were last
745 painted. In this case effect_to_redraw will point to an effect
746 the redraw was queued from or it will be NULL if the redraw was
747 queued without an effect. */
749 guint bg_color_set : 1;
758 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
759 * when set they force a size request, when gotten they
760 * get the allocation if the allocation is valid, and the
768 /* Then the rest of these size-related properties are the "actual"
769 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
774 PROP_FIXED_POSITION_SET,
783 PROP_NATURAL_WIDTH_SET,
786 PROP_NATURAL_HEIGHT_SET,
790 /* Allocation properties are read-only */
797 PROP_CLIP_TO_ALLOCATION,
801 PROP_OFFSCREEN_REDIRECT,
814 PROP_ROTATION_ANGLE_X,
815 PROP_ROTATION_ANGLE_Y,
816 PROP_ROTATION_ANGLE_Z,
817 PROP_ROTATION_CENTER_X,
818 PROP_ROTATION_CENTER_Y,
819 PROP_ROTATION_CENTER_Z,
820 /* This property only makes sense for the z rotation because the
821 others would depend on the actor having a size along the
823 PROP_ROTATION_CENTER_Z_GRAVITY,
829 PROP_SHOW_ON_SET_PARENT,
847 PROP_BACKGROUND_COLOR,
848 PROP_BACKGROUND_COLOR_SET,
854 PROP_CONTENT_GRAVITY,
856 PROP_MINIFICATION_FILTER,
857 PROP_MAGNIFICATION_FILTER,
862 static GParamSpec *obj_props[PROP_LAST];
881 BUTTON_RELEASE_EVENT,
889 TRANSITIONS_COMPLETED,
894 static guint actor_signals[LAST_SIGNAL] = { 0, };
896 static void clutter_container_iface_init (ClutterContainerIface *iface);
897 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
898 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
899 static void atk_implementor_iface_init (AtkImplementorIface *iface);
901 /* These setters are all static for now, maybe they should be in the
902 * public API, but they are perhaps obscure enough to leave only as
905 static void clutter_actor_set_min_width (ClutterActor *self,
907 static void clutter_actor_set_min_height (ClutterActor *self,
909 static void clutter_actor_set_natural_width (ClutterActor *self,
910 gfloat natural_width);
911 static void clutter_actor_set_natural_height (ClutterActor *self,
912 gfloat natural_height);
913 static void clutter_actor_set_min_width_set (ClutterActor *self,
914 gboolean use_min_width);
915 static void clutter_actor_set_min_height_set (ClutterActor *self,
916 gboolean use_min_height);
917 static void clutter_actor_set_natural_width_set (ClutterActor *self,
918 gboolean use_natural_width);
919 static void clutter_actor_set_natural_height_set (ClutterActor *self,
920 gboolean use_natural_height);
921 static void clutter_actor_update_map_state (ClutterActor *self,
922 MapStateChange change);
923 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
925 /* Helper routines for managing anchor coords */
926 static void clutter_anchor_coord_get_units (ClutterActor *self,
927 const AnchorCoord *coord,
931 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
936 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
937 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
938 ClutterGravity gravity);
940 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
942 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
944 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
945 ClutterActor *ancestor,
948 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
950 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
952 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
953 const ClutterColor *color);
955 static void on_layout_manager_changed (ClutterLayoutManager *manager,
958 /* Helper macro which translates by the anchor coord, applies the
959 given transformation and then translates back */
960 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
961 gfloat _tx, _ty, _tz; \
962 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
963 cogl_matrix_translate ((m), _tx, _ty, _tz); \
965 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
967 static GQuark quark_shader_data = 0;
968 static GQuark quark_actor_layout_info = 0;
969 static GQuark quark_actor_transform_info = 0;
970 static GQuark quark_actor_animation_info = 0;
972 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
974 G_TYPE_INITIALLY_UNOWNED,
975 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
976 clutter_container_iface_init)
977 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
978 clutter_scriptable_iface_init)
979 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
980 clutter_animatable_iface_init)
981 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
982 atk_implementor_iface_init));
985 * clutter_actor_get_debug_name:
986 * @actor: a #ClutterActor
988 * Retrieves a printable name of @actor for debugging messages
990 * Return value: a string with a printable name
993 _clutter_actor_get_debug_name (ClutterActor *actor)
995 return actor->priv->name != NULL ? actor->priv->name
996 : G_OBJECT_TYPE_NAME (actor);
999 #ifdef CLUTTER_ENABLE_DEBUG
1000 /* XXX - this is for debugging only, remove once working (or leave
1001 * in only in some debug mode). Should leave it for a little while
1002 * until we're confident in the new map/realize/visible handling.
1005 clutter_actor_verify_map_state (ClutterActor *self)
1007 ClutterActorPrivate *priv = self->priv;
1009 if (CLUTTER_ACTOR_IS_REALIZED (self))
1011 /* all bets are off during reparent when we're potentially realized,
1012 * but should not be according to invariants
1014 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1016 if (priv->parent == NULL)
1018 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1022 g_warning ("Realized non-toplevel actor '%s' should "
1024 _clutter_actor_get_debug_name (self));
1026 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1028 g_warning ("Realized actor %s has an unrealized parent %s",
1029 _clutter_actor_get_debug_name (self),
1030 _clutter_actor_get_debug_name (priv->parent));
1035 if (CLUTTER_ACTOR_IS_MAPPED (self))
1037 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1038 g_warning ("Actor '%s' is mapped but not realized",
1039 _clutter_actor_get_debug_name (self));
1041 /* remaining bets are off during reparent when we're potentially
1042 * mapped, but should not be according to invariants
1044 if (!CLUTTER_ACTOR_IN_REPARENT (self))
1046 if (priv->parent == NULL)
1048 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1050 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1051 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1053 g_warning ("Toplevel actor '%s' is mapped "
1055 _clutter_actor_get_debug_name (self));
1060 g_warning ("Mapped actor '%s' should have a parent",
1061 _clutter_actor_get_debug_name (self));
1066 ClutterActor *iter = self;
1068 /* check for the enable_paint_unmapped flag on the actor
1069 * and parents; if the flag is enabled at any point of this
1070 * branch of the scene graph then all the later checks
1073 while (iter != NULL)
1075 if (iter->priv->enable_paint_unmapped)
1078 iter = iter->priv->parent;
1081 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1083 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1085 _clutter_actor_get_debug_name (self),
1086 _clutter_actor_get_debug_name (priv->parent));
1089 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1091 g_warning ("Actor '%s' should not be mapped if parent '%s'"
1093 _clutter_actor_get_debug_name (self),
1094 _clutter_actor_get_debug_name (priv->parent));
1097 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1099 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1100 g_warning ("Actor '%s' is mapped but its non-toplevel "
1101 "parent '%s' is not mapped",
1102 _clutter_actor_get_debug_name (self),
1103 _clutter_actor_get_debug_name (priv->parent));
1110 #endif /* CLUTTER_ENABLE_DEBUG */
1113 clutter_actor_set_mapped (ClutterActor *self,
1116 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1121 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1122 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1126 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1127 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1131 /* this function updates the mapped and realized states according to
1132 * invariants, in the appropriate order.
1135 clutter_actor_update_map_state (ClutterActor *self,
1136 MapStateChange change)
1138 gboolean was_mapped;
1140 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1142 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1144 /* the mapped flag on top-level actors must be set by the
1145 * per-backend implementation because it might be asynchronous.
1147 * That is, the MAPPED flag on toplevels currently tracks the X
1148 * server mapped-ness of the window, while the expected behavior
1149 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1150 * This creates some weird complexity by breaking the invariant
1151 * that if we're visible and all ancestors shown then we are
1152 * also mapped - instead, we are mapped if all ancestors
1153 * _possibly excepting_ the stage are mapped. The stage
1154 * will map/unmap for example when it is minimized or
1155 * moved to another workspace.
1157 * So, the only invariant on the stage is that if visible it
1158 * should be realized, and that it has to be visible to be
1161 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1162 clutter_actor_realize (self);
1166 case MAP_STATE_CHECK:
1169 case MAP_STATE_MAKE_MAPPED:
1170 g_assert (!was_mapped);
1171 clutter_actor_set_mapped (self, TRUE);
1174 case MAP_STATE_MAKE_UNMAPPED:
1175 g_assert (was_mapped);
1176 clutter_actor_set_mapped (self, FALSE);
1179 case MAP_STATE_MAKE_UNREALIZED:
1180 /* we only use MAKE_UNREALIZED in unparent,
1181 * and unparenting a stage isn't possible.
1182 * If someone wants to just unrealize a stage
1183 * then clutter_actor_unrealize() doesn't
1184 * go through this codepath.
1186 g_warning ("Trying to force unrealize stage is not allowed");
1190 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1191 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1192 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1194 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1195 "it is somehow still mapped",
1196 _clutter_actor_get_debug_name (self));
1201 ClutterActorPrivate *priv = self->priv;
1202 ClutterActor *parent = priv->parent;
1203 gboolean should_be_mapped;
1204 gboolean may_be_realized;
1205 gboolean must_be_realized;
1207 should_be_mapped = FALSE;
1208 may_be_realized = TRUE;
1209 must_be_realized = FALSE;
1211 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1213 may_be_realized = FALSE;
1217 /* Maintain invariant that if parent is mapped, and we are
1218 * visible, then we are mapped ... unless parent is a
1219 * stage, in which case we map regardless of parent's map
1220 * state but do require stage to be visible and realized.
1222 * If parent is realized, that does not force us to be
1223 * realized; but if parent is unrealized, that does force
1224 * us to be unrealized.
1226 * The reason we don't force children to realize with
1227 * parents is _clutter_actor_rerealize(); if we require that
1228 * a realized parent means children are realized, then to
1229 * unrealize an actor we would have to unrealize its
1230 * parents, which would end up meaning unrealizing and
1231 * hiding the entire stage. So we allow unrealizing a
1232 * child (as long as that child is not mapped) while that
1233 * child still has a realized parent.
1235 * Also, if we unrealize from leaf nodes to root, and
1236 * realize from root to leaf, the invariants are never
1237 * violated if we allow children to be unrealized
1238 * while parents are realized.
1240 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1241 * to force us to unmap, even though parent is still
1242 * mapped. This is because we're unmapping from leaf nodes
1245 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1246 change != MAP_STATE_MAKE_UNMAPPED)
1248 gboolean parent_is_visible_realized_toplevel;
1250 parent_is_visible_realized_toplevel =
1251 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1252 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1253 CLUTTER_ACTOR_IS_REALIZED (parent));
1255 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1256 parent_is_visible_realized_toplevel)
1258 must_be_realized = TRUE;
1259 should_be_mapped = TRUE;
1263 /* if the actor has been set to be painted even if unmapped
1264 * then we should map it and check for realization as well;
1265 * this is an override for the branch of the scene graph
1266 * which begins with this node
1268 if (priv->enable_paint_unmapped)
1270 if (priv->parent == NULL)
1271 g_warning ("Attempting to map an unparented actor '%s'",
1272 _clutter_actor_get_debug_name (self));
1274 should_be_mapped = TRUE;
1275 must_be_realized = TRUE;
1278 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1279 may_be_realized = FALSE;
1282 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1285 g_warning ("Attempting to map a child that does not "
1286 "meet the necessary invariants: the actor '%s' "
1288 _clutter_actor_get_debug_name (self));
1290 g_warning ("Attempting to map a child that does not "
1291 "meet the necessary invariants: the actor '%s' "
1292 "is parented to an unmapped actor '%s'",
1293 _clutter_actor_get_debug_name (self),
1294 _clutter_actor_get_debug_name (priv->parent));
1297 /* If in reparent, we temporarily suspend unmap and unrealize.
1299 * We want to go in the order "realize, map" and "unmap, unrealize"
1303 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1304 clutter_actor_set_mapped (self, FALSE);
1307 if (must_be_realized)
1308 clutter_actor_realize (self);
1310 /* if we must be realized then we may be, presumably */
1311 g_assert (!(must_be_realized && !may_be_realized));
1314 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1315 clutter_actor_unrealize_not_hiding (self);
1318 if (should_be_mapped)
1320 if (!must_be_realized)
1321 g_warning ("Somehow we think actor '%s' should be mapped but "
1322 "not realized, which isn't allowed",
1323 _clutter_actor_get_debug_name (self));
1325 /* realization is allowed to fail (though I don't know what
1326 * an app is supposed to do about that - shouldn't it just
1327 * be a g_error? anyway, we have to avoid mapping if this
1330 if (CLUTTER_ACTOR_IS_REALIZED (self))
1331 clutter_actor_set_mapped (self, TRUE);
1335 #ifdef CLUTTER_ENABLE_DEBUG
1336 /* check all invariants were kept */
1337 clutter_actor_verify_map_state (self);
1342 clutter_actor_real_map (ClutterActor *self)
1344 ClutterActorPrivate *priv = self->priv;
1345 ClutterActor *stage, *iter;
1347 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1349 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1350 _clutter_actor_get_debug_name (self));
1352 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1354 stage = _clutter_actor_get_stage_internal (self);
1355 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1357 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1359 _clutter_actor_get_debug_name (self));
1361 /* notify on parent mapped before potentially mapping
1362 * children, so apps see a top-down notification.
1364 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1366 for (iter = self->priv->first_child;
1368 iter = iter->priv->next_sibling)
1370 clutter_actor_map (iter);
1375 * clutter_actor_map:
1376 * @self: A #ClutterActor
1378 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1379 * and realizes its children if they are visible. Does nothing if the
1380 * actor is not visible.
1382 * Calling this function is strongly disencouraged: the default
1383 * implementation of #ClutterActorClass.map() will map all the children
1384 * of an actor when mapping its parent.
1386 * When overriding map, it is mandatory to chain up to the parent
1392 clutter_actor_map (ClutterActor *self)
1394 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1396 if (CLUTTER_ACTOR_IS_MAPPED (self))
1399 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1402 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1406 clutter_actor_real_unmap (ClutterActor *self)
1408 ClutterActorPrivate *priv = self->priv;
1411 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1413 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1414 _clutter_actor_get_debug_name (self));
1416 for (iter = self->priv->first_child;
1418 iter = iter->priv->next_sibling)
1420 clutter_actor_unmap (iter);
1423 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1425 /* clear the contents of the last paint volume, so that hiding + moving +
1426 * showing will not result in the wrong area being repainted
1428 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1429 priv->last_paint_volume_valid = TRUE;
1431 /* notify on parent mapped after potentially unmapping
1432 * children, so apps see a bottom-up notification.
1434 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1436 /* relinquish keyboard focus if we were unmapped while owning it */
1437 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1439 ClutterStage *stage;
1441 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1444 _clutter_stage_release_pick_id (stage, priv->pick_id);
1448 if (stage != NULL &&
1449 clutter_stage_get_key_focus (stage) == self)
1451 clutter_stage_set_key_focus (stage, NULL);
1457 * clutter_actor_unmap:
1458 * @self: A #ClutterActor
1460 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1461 * unmaps its children if they were mapped.
1463 * Calling this function is not encouraged: the default #ClutterActor
1464 * implementation of #ClutterActorClass.unmap() will also unmap any
1465 * eventual children by default when their parent is unmapped.
1467 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1468 * chain up to the parent implementation.
1470 * <note>It is important to note that the implementation of the
1471 * #ClutterActorClass.unmap() virtual function may be called after
1472 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1473 * implementation, but it is guaranteed to be called before the
1474 * #GObjectClass.finalize() implementation.</note>
1479 clutter_actor_unmap (ClutterActor *self)
1481 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1483 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1486 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1490 clutter_actor_real_show (ClutterActor *self)
1492 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1494 ClutterActorPrivate *priv = self->priv;
1496 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1498 /* we notify on the "visible" flag in the clutter_actor_show()
1499 * wrapper so the entire show signal emission completes first
1502 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1504 /* we queue a relayout unless the actor is inside a
1505 * container that explicitly told us not to
1507 if (priv->parent != NULL &&
1508 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1510 /* While an actor is hidden the parent may not have
1511 * allocated/requested so we need to start from scratch
1512 * and avoid the short-circuiting in
1513 * clutter_actor_queue_relayout().
1515 priv->needs_width_request = FALSE;
1516 priv->needs_height_request = FALSE;
1517 priv->needs_allocation = FALSE;
1518 clutter_actor_queue_relayout (self);
1524 set_show_on_set_parent (ClutterActor *self,
1527 ClutterActorPrivate *priv = self->priv;
1529 set_show = !!set_show;
1531 if (priv->show_on_set_parent == set_show)
1534 if (priv->parent == NULL)
1536 priv->show_on_set_parent = set_show;
1537 g_object_notify_by_pspec (G_OBJECT (self),
1538 obj_props[PROP_SHOW_ON_SET_PARENT]);
1543 * clutter_actor_show:
1544 * @self: A #ClutterActor
1546 * Flags an actor to be displayed. An actor that isn't shown will not
1547 * be rendered on the stage.
1549 * Actors are visible by default.
1551 * If this function is called on an actor without a parent, the
1552 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1556 clutter_actor_show (ClutterActor *self)
1558 ClutterActorPrivate *priv;
1560 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1562 /* simple optimization */
1563 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1565 /* we still need to set the :show-on-set-parent property, in
1566 * case show() is called on an unparented actor
1568 set_show_on_set_parent (self, TRUE);
1572 #ifdef CLUTTER_ENABLE_DEBUG
1573 clutter_actor_verify_map_state (self);
1578 g_object_freeze_notify (G_OBJECT (self));
1580 set_show_on_set_parent (self, TRUE);
1582 g_signal_emit (self, actor_signals[SHOW], 0);
1583 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1585 if (priv->parent != NULL)
1586 clutter_actor_queue_redraw (priv->parent);
1588 g_object_thaw_notify (G_OBJECT (self));
1592 * clutter_actor_show_all:
1593 * @self: a #ClutterActor
1595 * Calls clutter_actor_show() on all children of an actor (if any).
1599 * Deprecated: 1.10: Actors are visible by default
1602 clutter_actor_show_all (ClutterActor *self)
1604 ClutterActorClass *klass;
1606 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1608 klass = CLUTTER_ACTOR_GET_CLASS (self);
1609 if (klass->show_all)
1610 klass->show_all (self);
1614 clutter_actor_real_hide (ClutterActor *self)
1616 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1618 ClutterActorPrivate *priv = self->priv;
1620 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1622 /* we notify on the "visible" flag in the clutter_actor_hide()
1623 * wrapper so the entire hide signal emission completes first
1626 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1628 /* we queue a relayout unless the actor is inside a
1629 * container that explicitly told us not to
1631 if (priv->parent != NULL &&
1632 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1633 clutter_actor_queue_relayout (priv->parent);
1638 * clutter_actor_hide:
1639 * @self: A #ClutterActor
1641 * Flags an actor to be hidden. A hidden actor will not be
1642 * rendered on the stage.
1644 * Actors are visible by default.
1646 * If this function is called on an actor without a parent, the
1647 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1651 clutter_actor_hide (ClutterActor *self)
1653 ClutterActorPrivate *priv;
1655 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1657 /* simple optimization */
1658 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1660 /* we still need to set the :show-on-set-parent property, in
1661 * case hide() is called on an unparented actor
1663 set_show_on_set_parent (self, FALSE);
1667 #ifdef CLUTTER_ENABLE_DEBUG
1668 clutter_actor_verify_map_state (self);
1673 g_object_freeze_notify (G_OBJECT (self));
1675 set_show_on_set_parent (self, FALSE);
1677 g_signal_emit (self, actor_signals[HIDE], 0);
1678 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1680 if (priv->parent != NULL)
1681 clutter_actor_queue_redraw (priv->parent);
1683 g_object_thaw_notify (G_OBJECT (self));
1687 * clutter_actor_hide_all:
1688 * @self: a #ClutterActor
1690 * Calls clutter_actor_hide() on all child actors (if any).
1694 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1695 * prevent its children from being painted as well.
1698 clutter_actor_hide_all (ClutterActor *self)
1700 ClutterActorClass *klass;
1702 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1704 klass = CLUTTER_ACTOR_GET_CLASS (self);
1705 if (klass->hide_all)
1706 klass->hide_all (self);
1710 * clutter_actor_realize:
1711 * @self: A #ClutterActor
1713 * Realization informs the actor that it is attached to a stage. It
1714 * can use this to allocate resources if it wanted to delay allocation
1715 * until it would be rendered. However it is perfectly acceptable for
1716 * an actor to create resources before being realized because Clutter
1717 * only ever has a single rendering context so that actor is free to
1718 * be moved from one stage to another.
1720 * This function does nothing if the actor is already realized.
1722 * Because a realized actor must have realized parent actors, calling
1723 * clutter_actor_realize() will also realize all parents of the actor.
1725 * This function does not realize child actors, except in the special
1726 * case that realizing the stage, when the stage is visible, will
1727 * suddenly map (and thus realize) the children of the stage.
1730 clutter_actor_realize (ClutterActor *self)
1732 ClutterActorPrivate *priv;
1734 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1738 #ifdef CLUTTER_ENABLE_DEBUG
1739 clutter_actor_verify_map_state (self);
1742 if (CLUTTER_ACTOR_IS_REALIZED (self))
1745 /* To be realized, our parent actors must be realized first.
1746 * This will only succeed if we're inside a toplevel.
1748 if (priv->parent != NULL)
1749 clutter_actor_realize (priv->parent);
1751 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1753 /* toplevels can be realized at any time */
1757 /* "Fail" the realization if parent is missing or unrealized;
1758 * this should really be a g_warning() not some kind of runtime
1759 * failure; how can an app possibly recover? Instead it's a bug
1760 * in the app and the app should get an explanatory warning so
1761 * someone can fix it. But for now it's too hard to fix this
1762 * because e.g. ClutterTexture needs reworking.
1764 if (priv->parent == NULL ||
1765 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1769 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1771 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1772 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1774 g_signal_emit (self, actor_signals[REALIZE], 0);
1776 /* Stage actor is allowed to unset the realized flag again in its
1777 * default signal handler, though that is a pathological situation.
1780 /* If realization "failed" we'll have to update child state. */
1781 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1785 clutter_actor_real_unrealize (ClutterActor *self)
1787 /* we must be unmapped (implying our children are also unmapped) */
1788 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1792 * clutter_actor_unrealize:
1793 * @self: A #ClutterActor
1795 * Unrealization informs the actor that it may be being destroyed or
1796 * moved to another stage. The actor may want to destroy any
1797 * underlying graphics resources at this point. However it is
1798 * perfectly acceptable for it to retain the resources until the actor
1799 * is destroyed because Clutter only ever uses a single rendering
1800 * context and all of the graphics resources are valid on any stage.
1802 * Because mapped actors must be realized, actors may not be
1803 * unrealized if they are mapped. This function hides the actor to be
1804 * sure it isn't mapped, an application-visible side effect that you
1805 * may not be expecting.
1807 * This function should not be called by application code.
1810 clutter_actor_unrealize (ClutterActor *self)
1812 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1813 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1815 /* This function should not really be in the public API, because
1816 * there isn't a good reason to call it. ClutterActor will already
1817 * unrealize things for you when it's important to do so.
1819 * If you were using clutter_actor_unrealize() in a dispose
1820 * implementation, then don't, just chain up to ClutterActor's
1823 * If you were using clutter_actor_unrealize() to implement
1824 * unrealizing children of your container, then don't, ClutterActor
1825 * will already take care of that.
1827 * If you were using clutter_actor_unrealize() to re-realize to
1828 * create your resources in a different way, then use
1829 * _clutter_actor_rerealize() (inside Clutter) or just call your
1830 * code that recreates your resources directly (outside Clutter).
1833 #ifdef CLUTTER_ENABLE_DEBUG
1834 clutter_actor_verify_map_state (self);
1837 clutter_actor_hide (self);
1839 clutter_actor_unrealize_not_hiding (self);
1842 static ClutterActorTraverseVisitFlags
1843 unrealize_actor_before_children_cb (ClutterActor *self,
1847 /* If an actor is already unrealized we know its children have also
1848 * already been unrealized... */
1849 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1850 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1852 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1854 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1857 static ClutterActorTraverseVisitFlags
1858 unrealize_actor_after_children_cb (ClutterActor *self,
1862 /* We want to unset the realized flag only _after_
1863 * child actors are unrealized, to maintain invariants.
1865 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1866 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1867 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1871 * clutter_actor_unrealize_not_hiding:
1872 * @self: A #ClutterActor
1874 * Unrealization informs the actor that it may be being destroyed or
1875 * moved to another stage. The actor may want to destroy any
1876 * underlying graphics resources at this point. However it is
1877 * perfectly acceptable for it to retain the resources until the actor
1878 * is destroyed because Clutter only ever uses a single rendering
1879 * context and all of the graphics resources are valid on any stage.
1881 * Because mapped actors must be realized, actors may not be
1882 * unrealized if they are mapped. You must hide the actor or one of
1883 * its parents before attempting to unrealize.
1885 * This function is separate from clutter_actor_unrealize() because it
1886 * does not automatically hide the actor.
1887 * Actors need not be hidden to be unrealized, they just need to
1888 * be unmapped. In fact we don't want to mess up the application's
1889 * setting of the "visible" flag, so hiding is very undesirable.
1891 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1892 * backward compatibility.
1895 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1897 _clutter_actor_traverse (self,
1898 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1899 unrealize_actor_before_children_cb,
1900 unrealize_actor_after_children_cb,
1905 * _clutter_actor_rerealize:
1906 * @self: A #ClutterActor
1907 * @callback: Function to call while unrealized
1908 * @data: data for callback
1910 * If an actor is already unrealized, this just calls the callback.
1912 * If it is realized, it unrealizes temporarily, calls the callback,
1913 * and then re-realizes the actor.
1915 * As a side effect, leaves all children of the actor unrealized if
1916 * the actor was realized but not showing. This is because when we
1917 * unrealize the actor temporarily we must unrealize its children
1918 * (e.g. children of a stage can't be realized if stage window is
1919 * gone). And we aren't clever enough to save the realization state of
1920 * all children. In most cases this should not matter, because
1921 * the children will automatically realize when they next become mapped.
1924 _clutter_actor_rerealize (ClutterActor *self,
1925 ClutterCallback callback,
1928 gboolean was_mapped;
1929 gboolean was_showing;
1930 gboolean was_realized;
1932 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1934 #ifdef CLUTTER_ENABLE_DEBUG
1935 clutter_actor_verify_map_state (self);
1938 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1939 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1940 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1942 /* Must be unmapped to unrealize. Note we only have to hide this
1943 * actor if it was mapped (if all parents were showing). If actor
1944 * is merely visible (but not mapped), then that's fine, we can
1948 clutter_actor_hide (self);
1950 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1952 /* unrealize self and all children */
1953 clutter_actor_unrealize_not_hiding (self);
1955 if (callback != NULL)
1957 (* callback) (self, data);
1961 clutter_actor_show (self); /* will realize only if mapping implies it */
1962 else if (was_realized)
1963 clutter_actor_realize (self); /* realize self and all parents */
1967 clutter_actor_real_pick (ClutterActor *self,
1968 const ClutterColor *color)
1970 /* the default implementation is just to paint a rectangle
1971 * with the same size of the actor using the passed color
1973 if (clutter_actor_should_pick_paint (self))
1975 ClutterActorBox box = { 0, };
1976 float width, height;
1978 clutter_actor_get_allocation_box (self, &box);
1980 width = box.x2 - box.x1;
1981 height = box.y2 - box.y1;
1983 cogl_set_source_color4ub (color->red,
1988 cogl_rectangle (0, 0, width, height);
1991 /* XXX - this thoroughly sucks, but we need to maintain compatibility
1992 * with existing container classes that override the pick() virtual
1993 * and chain up to the default implementation - otherwise we'll end up
1994 * painting our children twice.
1996 * this has to go away for 2.0; hopefully along the pick() itself.
1998 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2002 for (iter = self->priv->first_child;
2004 iter = iter->priv->next_sibling)
2005 clutter_actor_paint (iter);
2010 * clutter_actor_should_pick_paint:
2011 * @self: A #ClutterActor
2013 * Should be called inside the implementation of the
2014 * #ClutterActor::pick virtual function in order to check whether
2015 * the actor should paint itself in pick mode or not.
2017 * This function should never be called directly by applications.
2019 * Return value: %TRUE if the actor should paint its silhouette,
2023 clutter_actor_should_pick_paint (ClutterActor *self)
2025 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2027 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2028 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2029 CLUTTER_ACTOR_IS_REACTIVE (self)))
2036 clutter_actor_real_get_preferred_width (ClutterActor *self,
2038 gfloat *min_width_p,
2039 gfloat *natural_width_p)
2041 ClutterActorPrivate *priv = self->priv;
2043 if (priv->n_children != 0 &&
2044 priv->layout_manager != NULL)
2046 ClutterContainer *container = CLUTTER_CONTAINER (self);
2048 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2049 "for the preferred width",
2050 G_OBJECT_TYPE_NAME (priv->layout_manager),
2051 priv->layout_manager);
2053 clutter_layout_manager_get_preferred_width (priv->layout_manager,
2062 /* Default implementation is always 0x0, usually an actor
2063 * using this default is relying on someone to set the
2066 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2071 if (natural_width_p)
2072 *natural_width_p = 0;
2076 clutter_actor_real_get_preferred_height (ClutterActor *self,
2078 gfloat *min_height_p,
2079 gfloat *natural_height_p)
2081 ClutterActorPrivate *priv = self->priv;
2083 if (priv->n_children != 0 &&
2084 priv->layout_manager != NULL)
2086 ClutterContainer *container = CLUTTER_CONTAINER (self);
2088 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2089 "for the preferred height",
2090 G_OBJECT_TYPE_NAME (priv->layout_manager),
2091 priv->layout_manager);
2093 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2101 /* Default implementation is always 0x0, usually an actor
2102 * using this default is relying on someone to set the
2105 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2110 if (natural_height_p)
2111 *natural_height_p = 0;
2115 clutter_actor_store_old_geometry (ClutterActor *self,
2116 ClutterActorBox *box)
2118 *box = self->priv->allocation;
2122 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2123 const ClutterActorBox *old)
2125 ClutterActorPrivate *priv = self->priv;
2126 GObject *obj = G_OBJECT (self);
2128 g_object_freeze_notify (obj);
2130 /* to avoid excessive requisition or allocation cycles we
2131 * use the cached values.
2133 * - if we don't have an allocation we assume that we need
2135 * - if we don't have a width or a height request we notify
2137 * - if we have a valid allocation then we check the old
2138 * bounding box with the current allocation and we notify
2141 if (priv->needs_allocation)
2143 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2144 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2145 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2146 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2148 else if (priv->needs_width_request || priv->needs_height_request)
2150 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2151 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2156 gfloat width, height;
2158 x = priv->allocation.x1;
2159 y = priv->allocation.y1;
2160 width = priv->allocation.x2 - priv->allocation.x1;
2161 height = priv->allocation.y2 - priv->allocation.y1;
2164 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2167 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2169 if (width != (old->x2 - old->x1))
2170 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2172 if (height != (old->y2 - old->y1))
2173 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2176 g_object_thaw_notify (obj);
2180 * clutter_actor_set_allocation_internal:
2181 * @self: a #ClutterActor
2182 * @box: a #ClutterActorBox
2183 * @flags: allocation flags
2185 * Stores the allocation of @self.
2187 * This function only performs basic storage and property notification.
2189 * This function should be called by clutter_actor_set_allocation()
2190 * and by the default implementation of #ClutterActorClass.allocate().
2192 * Return value: %TRUE if the allocation of the #ClutterActor has been
2193 * changed, and %FALSE otherwise
2195 static inline gboolean
2196 clutter_actor_set_allocation_internal (ClutterActor *self,
2197 const ClutterActorBox *box,
2198 ClutterAllocationFlags flags)
2200 ClutterActorPrivate *priv = self->priv;
2202 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2203 gboolean flags_changed;
2205 ClutterActorBox old_alloc = { 0, };
2207 obj = G_OBJECT (self);
2209 g_object_freeze_notify (obj);
2211 clutter_actor_store_old_geometry (self, &old_alloc);
2213 x1_changed = priv->allocation.x1 != box->x1;
2214 y1_changed = priv->allocation.y1 != box->y1;
2215 x2_changed = priv->allocation.x2 != box->x2;
2216 y2_changed = priv->allocation.y2 != box->y2;
2218 flags_changed = priv->allocation_flags != flags;
2220 priv->allocation = *box;
2221 priv->allocation_flags = flags;
2223 /* allocation is authoritative */
2224 priv->needs_width_request = FALSE;
2225 priv->needs_height_request = FALSE;
2226 priv->needs_allocation = FALSE;
2228 if (x1_changed || y1_changed ||
2229 x2_changed || y2_changed ||
2232 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2233 _clutter_actor_get_debug_name (self));
2235 priv->transform_valid = FALSE;
2237 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2239 /* if the allocation changes, so does the content box */
2240 if (priv->content != NULL)
2241 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2248 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2250 g_object_thaw_notify (obj);
2255 static void clutter_actor_real_allocate (ClutterActor *self,
2256 const ClutterActorBox *box,
2257 ClutterAllocationFlags flags);
2260 clutter_actor_maybe_layout_children (ClutterActor *self,
2261 const ClutterActorBox *allocation,
2262 ClutterAllocationFlags flags)
2264 ClutterActorPrivate *priv = self->priv;
2266 /* this is going to be a bit hard to follow, so let's put an explanation
2269 * we want ClutterActor to have a default layout manager if the actor was
2270 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2272 * we also want any subclass of ClutterActor that does not override the
2273 * ::allocate() virtual function to delegate to a layout manager.
2275 * finally, we want to allow people subclassing ClutterActor and overriding
2276 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2278 * on the other hand, we want existing actor subclasses overriding the
2279 * ::allocate() virtual function and chaining up to the parent's
2280 * implementation to continue working without allocating their children
2281 * twice, or without entering an allocation loop.
2283 * for the first two points, we check if the class of the actor is
2284 * overridding the ::allocate() virtual function; if it isn't, then we
2285 * follow through with checking whether we have children and a layout
2286 * manager, and eventually calling clutter_layout_manager_allocate().
2288 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2289 * allocation flags that we got passed, and if it is present, we continue
2290 * with the check above.
2292 * if neither of these two checks yields a positive result, we just
2293 * assume that the ::allocate() virtual function that resulted in this
2294 * function being called will also allocate the children of the actor.
2297 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2300 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2306 if (priv->n_children != 0 &&
2307 priv->layout_manager != NULL)
2309 ClutterContainer *container = CLUTTER_CONTAINER (self);
2310 ClutterAllocationFlags children_flags;
2311 ClutterActorBox children_box;
2313 /* normalize the box passed to the layout manager */
2314 children_box.x1 = children_box.y1 = 0.f;
2315 children_box.x2 = (allocation->x2 - allocation->x1);
2316 children_box.y2 = (allocation->y2 - allocation->y1);
2318 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2319 * the actor's children, since it refers only to the current
2320 * actor's allocation.
2322 children_flags = flags;
2323 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2325 CLUTTER_NOTE (LAYOUT,
2326 "Allocating %d children of %s "
2327 "at { %.2f, %.2f - %.2f x %.2f } "
2330 _clutter_actor_get_debug_name (self),
2333 (allocation->x2 - allocation->x1),
2334 (allocation->y2 - allocation->y1),
2335 G_OBJECT_TYPE_NAME (priv->layout_manager));
2337 clutter_layout_manager_allocate (priv->layout_manager,
2345 clutter_actor_real_allocate (ClutterActor *self,
2346 const ClutterActorBox *box,
2347 ClutterAllocationFlags flags)
2349 ClutterActorPrivate *priv = self->priv;
2352 g_object_freeze_notify (G_OBJECT (self));
2354 changed = clutter_actor_set_allocation_internal (self, box, flags);
2356 /* we allocate our children before we notify changes in our geometry,
2357 * so that people connecting to properties will be able to get valid
2358 * data out of the sub-tree of the scene graph that has this actor at
2361 clutter_actor_maybe_layout_children (self, box, flags);
2365 ClutterActorBox signal_box = priv->allocation;
2366 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2368 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2373 g_object_thaw_notify (G_OBJECT (self));
2377 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2378 ClutterActor *origin)
2380 /* no point in queuing a redraw on a destroyed actor */
2381 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2384 /* NB: We can't bail out early here if the actor is hidden in case
2385 * the actor bas been cloned. In this case the clone will need to
2386 * receive the signal so it can queue its own redraw.
2389 /* calls klass->queue_redraw in default handler */
2390 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2394 clutter_actor_real_queue_redraw (ClutterActor *self,
2395 ClutterActor *origin)
2397 ClutterActor *parent;
2399 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2400 _clutter_actor_get_debug_name (self),
2401 origin != NULL ? _clutter_actor_get_debug_name (origin)
2404 /* no point in queuing a redraw on a destroyed actor */
2405 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2408 /* If the queue redraw is coming from a child then the actor has
2409 become dirty and any queued effect is no longer valid */
2412 self->priv->is_dirty = TRUE;
2413 self->priv->effect_to_redraw = NULL;
2416 /* If the actor isn't visible, we still had to emit the signal
2417 * to allow for a ClutterClone, but the appearance of the parent
2418 * won't change so we don't have to propagate up the hierarchy.
2420 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2423 /* Although we could determine here that a full stage redraw
2424 * has already been queued and immediately bail out, we actually
2425 * guarantee that we will propagate a queue-redraw signal to our
2426 * parent at least once so that it's possible to implement a
2427 * container that tracks which of its children have queued a
2430 if (self->priv->propagated_one_redraw)
2432 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2433 if (stage != NULL &&
2434 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2438 self->priv->propagated_one_redraw = TRUE;
2440 /* notify parents, if they are all visible eventually we'll
2441 * queue redraw on the stage, which queues the redraw idle.
2443 parent = clutter_actor_get_parent (self);
2446 /* this will go up recursively */
2447 _clutter_actor_signal_queue_redraw (parent, origin);
2452 clutter_actor_real_queue_relayout (ClutterActor *self)
2454 ClutterActorPrivate *priv = self->priv;
2456 /* no point in queueing a redraw on a destroyed actor */
2457 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2460 priv->needs_width_request = TRUE;
2461 priv->needs_height_request = TRUE;
2462 priv->needs_allocation = TRUE;
2464 /* reset the cached size requests */
2465 memset (priv->width_requests, 0,
2466 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2467 memset (priv->height_requests, 0,
2468 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2470 /* We need to go all the way up the hierarchy */
2471 if (priv->parent != NULL)
2472 _clutter_actor_queue_only_relayout (priv->parent);
2476 * clutter_actor_apply_relative_transform_to_point:
2477 * @self: A #ClutterActor
2478 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2479 * default #ClutterStage
2480 * @point: A point as #ClutterVertex
2481 * @vertex: (out caller-allocates): The translated #ClutterVertex
2483 * Transforms @point in coordinates relative to the actor into
2484 * ancestor-relative coordinates using the relevant transform
2485 * stack (i.e. scale, rotation, etc).
2487 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2488 * this case, the coordinates returned will be the coordinates on
2489 * the stage before the projection is applied. This is different from
2490 * the behaviour of clutter_actor_apply_transform_to_point().
2495 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2496 ClutterActor *ancestor,
2497 const ClutterVertex *point,
2498 ClutterVertex *vertex)
2503 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2504 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2505 g_return_if_fail (point != NULL);
2506 g_return_if_fail (vertex != NULL);
2511 if (ancestor == NULL)
2512 ancestor = _clutter_actor_get_stage_internal (self);
2514 if (ancestor == NULL)
2520 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2521 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2525 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2526 const ClutterVertex *vertices_in,
2527 ClutterVertex *vertices_out,
2530 ClutterActor *stage;
2531 CoglMatrix modelview;
2532 CoglMatrix projection;
2535 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2537 stage = _clutter_actor_get_stage_internal (self);
2539 /* We really can't do anything meaningful in this case so don't try
2540 * to do any transform */
2544 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2545 * that gets us to stage coordinates, we want to go all the way to eye
2547 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2549 /* Fetch the projection and viewport */
2550 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2551 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2557 _clutter_util_fully_transform_vertices (&modelview,
2568 * clutter_actor_apply_transform_to_point:
2569 * @self: A #ClutterActor
2570 * @point: A point as #ClutterVertex
2571 * @vertex: (out caller-allocates): The translated #ClutterVertex
2573 * Transforms @point in coordinates relative to the actor
2574 * into screen-relative coordinates with the current actor
2575 * transformation (i.e. scale, rotation, etc)
2580 clutter_actor_apply_transform_to_point (ClutterActor *self,
2581 const ClutterVertex *point,
2582 ClutterVertex *vertex)
2584 g_return_if_fail (point != NULL);
2585 g_return_if_fail (vertex != NULL);
2586 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2590 * _clutter_actor_get_relative_transformation_matrix:
2591 * @self: The actor whose coordinate space you want to transform from.
2592 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2593 * or %NULL if you want to transform all the way to eye coordinates.
2594 * @matrix: A #CoglMatrix to store the transformation
2596 * This gets a transformation @matrix that will transform coordinates from the
2597 * coordinate space of @self into the coordinate space of @ancestor.
2599 * For example if you need a matrix that can transform the local actor
2600 * coordinates of @self into stage coordinates you would pass the actor's stage
2601 * pointer as the @ancestor.
2603 * If you pass %NULL then the transformation will take you all the way through
2604 * to eye coordinates. This can be useful if you want to extract the entire
2605 * modelview transform that Clutter applies before applying the projection
2606 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2607 * using cogl_set_modelview_matrix() for example then you would want a matrix
2608 * that transforms into eye coordinates.
2610 * <note><para>This function explicitly initializes the given @matrix. If you just
2611 * want clutter to multiply a relative transformation with an existing matrix
2612 * you can use clutter_actor_apply_relative_transformation_matrix()
2613 * instead.</para></note>
2616 /* XXX: We should consider caching the stage relative modelview along with
2617 * the actor itself */
2619 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2620 ClutterActor *ancestor,
2623 cogl_matrix_init_identity (matrix);
2625 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2628 /* Project the given @box into stage window coordinates, writing the
2629 * transformed vertices to @verts[]. */
2631 _clutter_actor_transform_and_project_box (ClutterActor *self,
2632 const ClutterActorBox *box,
2633 ClutterVertex verts[])
2635 ClutterVertex box_vertices[4];
2637 box_vertices[0].x = box->x1;
2638 box_vertices[0].y = box->y1;
2639 box_vertices[0].z = 0;
2640 box_vertices[1].x = box->x2;
2641 box_vertices[1].y = box->y1;
2642 box_vertices[1].z = 0;
2643 box_vertices[2].x = box->x1;
2644 box_vertices[2].y = box->y2;
2645 box_vertices[2].z = 0;
2646 box_vertices[3].x = box->x2;
2647 box_vertices[3].y = box->y2;
2648 box_vertices[3].z = 0;
2651 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2655 * clutter_actor_get_allocation_vertices:
2656 * @self: A #ClutterActor
2657 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2658 * against, or %NULL to use the #ClutterStage
2659 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2660 * location for an array of 4 #ClutterVertex in which to store the result
2662 * Calculates the transformed coordinates of the four corners of the
2663 * actor in the plane of @ancestor. The returned vertices relate to
2664 * the #ClutterActorBox coordinates as follows:
2666 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2667 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2668 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2669 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2672 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2673 * this case, the coordinates returned will be the coordinates on
2674 * the stage before the projection is applied. This is different from
2675 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2680 clutter_actor_get_allocation_vertices (ClutterActor *self,
2681 ClutterActor *ancestor,
2682 ClutterVertex verts[])
2684 ClutterActorPrivate *priv;
2685 ClutterActorBox box;
2686 ClutterVertex vertices[4];
2687 CoglMatrix modelview;
2689 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2690 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2692 if (ancestor == NULL)
2693 ancestor = _clutter_actor_get_stage_internal (self);
2695 /* Fallback to a NOP transform if the actor isn't parented under a
2697 if (ancestor == NULL)
2702 /* if the actor needs to be allocated we force a relayout, so that
2703 * we will have valid values to use in the transformations */
2704 if (priv->needs_allocation)
2706 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2708 _clutter_stage_maybe_relayout (stage);
2711 box.x1 = box.y1 = 0;
2712 /* The result isn't really meaningful in this case but at
2713 * least try to do something *vaguely* reasonable... */
2714 clutter_actor_get_size (self, &box.x2, &box.y2);
2718 clutter_actor_get_allocation_box (self, &box);
2720 vertices[0].x = box.x1;
2721 vertices[0].y = box.y1;
2723 vertices[1].x = box.x2;
2724 vertices[1].y = box.y1;
2726 vertices[2].x = box.x1;
2727 vertices[2].y = box.y2;
2729 vertices[3].x = box.x2;
2730 vertices[3].y = box.y2;
2733 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2736 cogl_matrix_transform_points (&modelview,
2738 sizeof (ClutterVertex),
2740 sizeof (ClutterVertex),
2746 * clutter_actor_get_abs_allocation_vertices:
2747 * @self: A #ClutterActor
2748 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2749 * of 4 #ClutterVertex where to store the result.
2751 * Calculates the transformed screen coordinates of the four corners of
2752 * the actor; the returned vertices relate to the #ClutterActorBox
2753 * coordinates as follows:
2755 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2756 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2757 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2758 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2764 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2765 ClutterVertex verts[])
2767 ClutterActorPrivate *priv;
2768 ClutterActorBox actor_space_allocation;
2770 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2774 /* if the actor needs to be allocated we force a relayout, so that
2775 * the actor allocation box will be valid for
2776 * _clutter_actor_transform_and_project_box()
2778 if (priv->needs_allocation)
2780 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2781 /* There's nothing meaningful we can do now */
2785 _clutter_stage_maybe_relayout (stage);
2788 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2789 * own coordinate space... */
2790 actor_space_allocation.x1 = 0;
2791 actor_space_allocation.y1 = 0;
2792 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2793 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2794 _clutter_actor_transform_and_project_box (self,
2795 &actor_space_allocation,
2800 clutter_actor_real_apply_transform (ClutterActor *self,
2803 ClutterActorPrivate *priv = self->priv;
2805 if (!priv->transform_valid)
2807 CoglMatrix *transform = &priv->transform;
2808 const ClutterTransformInfo *info;
2810 info = _clutter_actor_get_transform_info_or_defaults (self);
2812 cogl_matrix_init_identity (transform);
2814 cogl_matrix_translate (transform,
2815 priv->allocation.x1,
2816 priv->allocation.y1,
2820 cogl_matrix_translate (transform, 0, 0, info->depth);
2823 * because the rotation involves translations, we must scale
2824 * before applying the rotations (if we apply the scale after
2825 * the rotations, the translations included in the rotation are
2826 * not scaled and so the entire object will move on the screen
2827 * as a result of rotating it).
2829 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2831 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2832 &info->scale_center,
2833 cogl_matrix_scale (transform,
2840 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2842 cogl_matrix_rotate (transform,
2847 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2849 cogl_matrix_rotate (transform,
2854 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2856 cogl_matrix_rotate (transform,
2860 if (!clutter_anchor_coord_is_zero (&info->anchor))
2864 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2865 cogl_matrix_translate (transform, -x, -y, -z);
2868 priv->transform_valid = TRUE;
2871 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2874 /* Applies the transforms associated with this actor to the given
2877 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2880 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2884 * clutter_actor_apply_relative_transformation_matrix:
2885 * @self: The actor whose coordinate space you want to transform from.
2886 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2887 * or %NULL if you want to transform all the way to eye coordinates.
2888 * @matrix: A #CoglMatrix to apply the transformation too.
2890 * This multiplies a transform with @matrix that will transform coordinates
2891 * from the coordinate space of @self into the coordinate space of @ancestor.
2893 * For example if you need a matrix that can transform the local actor
2894 * coordinates of @self into stage coordinates you would pass the actor's stage
2895 * pointer as the @ancestor.
2897 * If you pass %NULL then the transformation will take you all the way through
2898 * to eye coordinates. This can be useful if you want to extract the entire
2899 * modelview transform that Clutter applies before applying the projection
2900 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2901 * using cogl_set_modelview_matrix() for example then you would want a matrix
2902 * that transforms into eye coordinates.
2904 * <note>This function doesn't initialize the given @matrix, it simply
2905 * multiplies the requested transformation matrix with the existing contents of
2906 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2907 * before calling this function, or you can use
2908 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2911 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2912 ClutterActor *ancestor,
2915 ClutterActor *parent;
2917 /* Note we terminate before ever calling stage->apply_transform()
2918 * since that would conceptually be relative to the underlying
2919 * window OpenGL coordinates so we'd need a special @ancestor
2920 * value to represent the fake parent of the stage. */
2921 if (self == ancestor)
2924 parent = clutter_actor_get_parent (self);
2927 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2930 _clutter_actor_apply_modelview_transform (self, matrix);
2934 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2935 ClutterPaintVolume *pv,
2937 const CoglColor *color)
2939 static CoglPipeline *outline = NULL;
2940 CoglPrimitive *prim;
2941 ClutterVertex line_ends[12 * 2];
2944 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2945 /* XXX: at some point we'll query this from the stage but we can't
2946 * do that until the osx backend uses Cogl natively. */
2947 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2949 if (outline == NULL)
2950 outline = cogl_pipeline_new (ctx);
2952 _clutter_paint_volume_complete (pv);
2954 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2957 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2958 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2959 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2960 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2965 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2966 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2967 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2968 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2970 /* Lines connecting front face to back face */
2971 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2972 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2973 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2974 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2977 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2979 (CoglVertexP3 *)line_ends);
2981 cogl_pipeline_set_color (outline, color);
2982 cogl_framebuffer_draw_primitive (fb, outline, prim);
2983 cogl_object_unref (prim);
2987 PangoLayout *layout;
2988 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2989 pango_layout_set_text (layout, label, -1);
2990 cogl_pango_render_layout (layout,
2995 g_object_unref (layout);
3000 _clutter_actor_draw_paint_volume (ClutterActor *self)
3002 ClutterPaintVolume *pv;
3005 pv = _clutter_actor_get_paint_volume_mutable (self);
3008 gfloat width, height;
3009 ClutterPaintVolume fake_pv;
3011 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3012 _clutter_paint_volume_init_static (&fake_pv, stage);
3014 clutter_actor_get_size (self, &width, &height);
3015 clutter_paint_volume_set_width (&fake_pv, width);
3016 clutter_paint_volume_set_height (&fake_pv, height);
3018 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3019 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3020 _clutter_actor_get_debug_name (self),
3023 clutter_paint_volume_free (&fake_pv);
3027 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3028 _clutter_actor_draw_paint_volume_full (self, pv,
3029 _clutter_actor_get_debug_name (self),
3035 _clutter_actor_paint_cull_result (ClutterActor *self,
3037 ClutterCullResult result)
3039 ClutterPaintVolume *pv;
3044 if (result == CLUTTER_CULL_RESULT_IN)
3045 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3046 else if (result == CLUTTER_CULL_RESULT_OUT)
3047 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3049 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3052 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3054 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3055 _clutter_actor_draw_paint_volume_full (self, pv,
3056 _clutter_actor_get_debug_name (self),
3060 PangoLayout *layout;
3062 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3063 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3064 cogl_set_source_color (&color);
3066 layout = pango_layout_new (clutter_actor_get_pango_context (self));
3067 pango_layout_set_text (layout, label, -1);
3068 cogl_pango_render_layout (layout,
3074 g_object_unref (layout);
3078 static int clone_paint_level = 0;
3081 _clutter_actor_push_clone_paint (void)
3083 clone_paint_level++;
3087 _clutter_actor_pop_clone_paint (void)
3089 clone_paint_level--;
3093 in_clone_paint (void)
3095 return clone_paint_level > 0;
3098 /* Returns TRUE if the actor can be ignored */
3099 /* FIXME: we should return a ClutterCullResult, and
3100 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3101 * means there's no point in trying to cull descendants of the current
3104 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3106 ClutterActorPrivate *priv = self->priv;
3107 ClutterActor *stage;
3108 const ClutterPlane *stage_clip;
3110 if (!priv->last_paint_volume_valid)
3112 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3113 "->last_paint_volume_valid == FALSE",
3114 _clutter_actor_get_debug_name (self));
3118 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3121 stage = _clutter_actor_get_stage_internal (self);
3122 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3123 if (G_UNLIKELY (!stage_clip))
3125 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3126 "No stage clip set",
3127 _clutter_actor_get_debug_name (self));
3131 if (cogl_get_draw_framebuffer () !=
3132 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3134 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3135 "Current framebuffer doesn't correspond to stage",
3136 _clutter_actor_get_debug_name (self));
3141 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3146 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3148 ClutterActorPrivate *priv = self->priv;
3149 const ClutterPaintVolume *pv;
3151 if (priv->last_paint_volume_valid)
3153 clutter_paint_volume_free (&priv->last_paint_volume);
3154 priv->last_paint_volume_valid = FALSE;
3157 pv = clutter_actor_get_paint_volume (self);
3160 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3161 "Actor failed to report a paint volume",
3162 _clutter_actor_get_debug_name (self));
3166 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3168 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3169 NULL); /* eye coordinates */
3171 priv->last_paint_volume_valid = TRUE;
3174 static inline gboolean
3175 actor_has_shader_data (ClutterActor *self)
3177 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3181 _clutter_actor_get_pick_id (ClutterActor *self)
3183 if (self->priv->pick_id < 0)
3186 return self->priv->pick_id;
3189 /* This is the same as clutter_actor_add_effect except that it doesn't
3190 queue a redraw and it doesn't notify on the effect property */
3192 _clutter_actor_add_effect_internal (ClutterActor *self,
3193 ClutterEffect *effect)
3195 ClutterActorPrivate *priv = self->priv;
3197 if (priv->effects == NULL)
3199 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3200 priv->effects->actor = self;
3203 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3206 /* This is the same as clutter_actor_remove_effect except that it doesn't
3207 queue a redraw and it doesn't notify on the effect property */
3209 _clutter_actor_remove_effect_internal (ClutterActor *self,
3210 ClutterEffect *effect)
3212 ClutterActorPrivate *priv = self->priv;
3214 if (priv->effects == NULL)
3217 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3221 needs_flatten_effect (ClutterActor *self)
3223 ClutterActorPrivate *priv = self->priv;
3225 if (G_UNLIKELY (clutter_paint_debug_flags &
3226 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3229 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3231 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3233 if (clutter_actor_get_paint_opacity (self) < 255 &&
3234 clutter_actor_has_overlaps (self))
3242 add_or_remove_flatten_effect (ClutterActor *self)
3244 ClutterActorPrivate *priv = self->priv;
3246 /* Add or remove the flatten effect depending on the
3247 offscreen-redirect property. */
3248 if (needs_flatten_effect (self))
3250 if (priv->flatten_effect == NULL)
3252 ClutterActorMeta *actor_meta;
3255 priv->flatten_effect = _clutter_flatten_effect_new ();
3256 /* Keep a reference to the effect so that we can queue
3258 g_object_ref_sink (priv->flatten_effect);
3260 /* Set the priority of the effect to high so that it will
3261 always be applied to the actor first. It uses an internal
3262 priority so that it won't be visible to applications */
3263 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3264 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3265 _clutter_actor_meta_set_priority (actor_meta, priority);
3267 /* This will add the effect without queueing a redraw */
3268 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3273 if (priv->flatten_effect != NULL)
3275 /* Destroy the effect so that it will lose its fbo cache of
3277 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3278 g_clear_object (&priv->flatten_effect);
3284 clutter_actor_real_paint (ClutterActor *actor)
3286 ClutterActorPrivate *priv = actor->priv;
3289 for (iter = priv->first_child;
3291 iter = iter->priv->next_sibling)
3293 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3294 _clutter_actor_get_debug_name (iter),
3295 _clutter_actor_get_debug_name (actor),
3296 iter->priv->allocation.x1,
3297 iter->priv->allocation.y1,
3298 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3299 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3301 clutter_actor_paint (iter);
3306 clutter_actor_paint_node (ClutterActor *actor,
3307 ClutterPaintNode *root)
3309 ClutterActorPrivate *priv = actor->priv;
3314 if (priv->bg_color_set &&
3315 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3317 ClutterPaintNode *node;
3318 ClutterColor bg_color;
3319 ClutterActorBox box;
3323 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3324 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3326 bg_color = priv->bg_color;
3327 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3328 * priv->bg_color.alpha
3331 node = clutter_color_node_new (&bg_color);
3332 clutter_paint_node_set_name (node, "backgroundColor");
3333 clutter_paint_node_add_rectangle (node, &box);
3334 clutter_paint_node_add_child (root, node);
3335 clutter_paint_node_unref (node);
3338 if (priv->content != NULL)
3339 _clutter_content_paint_content (priv->content, actor, root);
3341 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3342 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3344 if (clutter_paint_node_get_n_children (root) == 0)
3347 #ifdef CLUTTER_ENABLE_DEBUG
3348 if (CLUTTER_HAS_DEBUG (PAINT))
3350 /* dump the tree only if we have one */
3351 _clutter_paint_node_dump_tree (root);
3353 #endif /* CLUTTER_ENABLE_DEBUG */
3355 _clutter_paint_node_paint (root);
3358 /* XXX: Uncomment this when we disable emitting the paint signal */
3359 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3366 * clutter_actor_paint:
3367 * @self: A #ClutterActor
3369 * Renders the actor to display.
3371 * This function should not be called directly by applications.
3372 * Call clutter_actor_queue_redraw() to queue paints, instead.
3374 * This function is context-aware, and will either cause a
3375 * regular paint or a pick paint.
3377 * This function will emit the #ClutterActor::paint signal or
3378 * the #ClutterActor::pick signal, depending on the context.
3380 * This function does not paint the actor if the actor is set to 0,
3381 * unless it is performing a pick paint.
3384 clutter_actor_paint (ClutterActor *self)
3386 ClutterActorPrivate *priv;
3387 ClutterPickMode pick_mode;
3388 gboolean clip_set = FALSE;
3389 gboolean shader_applied = FALSE;
3391 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3392 "Actor real-paint counter",
3393 "Increments each time any actor is painted",
3394 0 /* no application private data */);
3395 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3396 "Actor pick-paint counter",
3397 "Increments each time any actor is painted "
3399 0 /* no application private data */);
3401 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3403 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3408 pick_mode = _clutter_context_get_pick_mode ();
3410 if (pick_mode == CLUTTER_PICK_NONE)
3411 priv->propagated_one_redraw = FALSE;
3413 /* It's an important optimization that we consider painting of
3414 * actors with 0 opacity to be a NOP... */
3415 if (pick_mode == CLUTTER_PICK_NONE &&
3416 /* ignore top-levels, since they might be transparent */
3417 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3418 /* Use the override opacity if its been set */
3419 ((priv->opacity_override >= 0) ?
3420 priv->opacity_override : priv->opacity) == 0)
3423 /* if we aren't paintable (not in a toplevel with all
3424 * parents paintable) then do nothing.
3426 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3429 /* mark that we are in the paint process */
3430 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3434 if (priv->enable_model_view_transform)
3438 /* XXX: It could be better to cache the modelview with the actor
3439 * instead of progressively building up the transformations on
3440 * the matrix stack every time we paint. */
3441 cogl_get_modelview_matrix (&matrix);
3442 _clutter_actor_apply_modelview_transform (self, &matrix);
3444 #ifdef CLUTTER_ENABLE_DEBUG
3445 /* Catch when out-of-band transforms have been made by actors not as part
3446 * of an apply_transform vfunc... */
3447 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3449 CoglMatrix expected_matrix;
3451 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3454 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3456 GString *buf = g_string_sized_new (1024);
3457 ClutterActor *parent;
3460 while (parent != NULL)
3462 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3464 if (parent->priv->parent != NULL)
3465 g_string_append (buf, "->");
3467 parent = parent->priv->parent;
3470 g_warning ("Unexpected transform found when painting actor "
3471 "\"%s\". This will be caused by one of the actor's "
3472 "ancestors (%s) using the Cogl API directly to transform "
3473 "children instead of using ::apply_transform().",
3474 _clutter_actor_get_debug_name (self),
3477 g_string_free (buf, TRUE);
3480 #endif /* CLUTTER_ENABLE_DEBUG */
3482 cogl_set_modelview_matrix (&matrix);
3487 cogl_clip_push_rectangle (priv->clip.x,
3489 priv->clip.x + priv->clip.width,
3490 priv->clip.y + priv->clip.height);
3493 else if (priv->clip_to_allocation)
3495 gfloat width, height;
3497 width = priv->allocation.x2 - priv->allocation.x1;
3498 height = priv->allocation.y2 - priv->allocation.y1;
3500 cogl_clip_push_rectangle (0, 0, width, height);
3504 if (pick_mode == CLUTTER_PICK_NONE)
3506 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3508 /* We check whether we need to add the flatten effect before
3509 each paint so that we can avoid having a mechanism for
3510 applications to notify when the value of the
3511 has_overlaps virtual changes. */
3512 add_or_remove_flatten_effect (self);
3515 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3517 /* We save the current paint volume so that the next time the
3518 * actor queues a redraw we can constrain the redraw to just
3519 * cover the union of the new bounding box and the old.
3521 * We also fetch the current paint volume to perform culling so
3522 * we can avoid painting actors outside the current clip region.
3524 * If we are painting inside a clone, we should neither update
3525 * the paint volume or use it to cull painting, since the paint
3526 * box represents the location of the source actor on the
3529 * XXX: We are starting to do a lot of vertex transforms on
3530 * the CPU in a typical paint, so at some point we should
3531 * audit these and consider caching some things.
3533 * NB: We don't perform culling while picking at this point because
3534 * clutter-stage.c doesn't setup the clipping planes appropriately.
3536 * NB: We don't want to update the last-paint-volume during picking
3537 * because the last-paint-volume is used to determine the old screen
3538 * space location of an actor that has moved so we can know the
3539 * minimal region to redraw to clear an old view of the actor. If we
3540 * update this during picking then by the time we come around to
3541 * paint then the last-paint-volume would likely represent the new
3542 * actor position not the old.
3544 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3547 /* annoyingly gcc warns if uninitialized even though
3548 * the initialization is redundant :-( */
3549 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3551 if (G_LIKELY ((clutter_paint_debug_flags &
3552 (CLUTTER_DEBUG_DISABLE_CULLING |
3553 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3554 (CLUTTER_DEBUG_DISABLE_CULLING |
3555 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3556 _clutter_actor_update_last_paint_volume (self);
3558 success = cull_actor (self, &result);
3560 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3561 _clutter_actor_paint_cull_result (self, success, result);
3562 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3566 if (priv->effects == NULL)
3568 if (pick_mode == CLUTTER_PICK_NONE &&
3569 actor_has_shader_data (self))
3571 _clutter_actor_shader_pre_paint (self, FALSE);
3572 shader_applied = TRUE;
3575 priv->next_effect_to_paint = NULL;
3578 priv->next_effect_to_paint =
3579 _clutter_meta_group_peek_metas (priv->effects);
3581 clutter_actor_continue_paint (self);
3584 _clutter_actor_shader_post_paint (self);
3586 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3587 pick_mode == CLUTTER_PICK_NONE))
3588 _clutter_actor_draw_paint_volume (self);
3591 /* If we make it here then the actor has run through a complete
3592 paint run including all the effects so it's no longer dirty */
3593 if (pick_mode == CLUTTER_PICK_NONE)
3594 priv->is_dirty = FALSE;
3601 /* paint sequence complete */
3602 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3606 * clutter_actor_continue_paint:
3607 * @self: A #ClutterActor
3609 * Run the next stage of the paint sequence. This function should only
3610 * be called within the implementation of the ‘run’ virtual of a
3611 * #ClutterEffect. It will cause the run method of the next effect to
3612 * be applied, or it will paint the actual actor if the current effect
3613 * is the last effect in the chain.
3618 clutter_actor_continue_paint (ClutterActor *self)
3620 ClutterActorPrivate *priv;
3622 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3623 /* This should only be called from with in the ‘run’ implementation
3624 of a ClutterEffect */
3625 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3629 /* Skip any effects that are disabled */
3630 while (priv->next_effect_to_paint &&
3631 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3632 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3634 /* If this has come from the last effect then we'll just paint the
3636 if (priv->next_effect_to_paint == NULL)
3638 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3640 ClutterPaintNode *dummy;
3642 /* XXX - this will go away in 2.0, when we can get rid of this
3643 * stuff and switch to a pure retained render tree of PaintNodes
3644 * for the entire frame, starting from the Stage; the paint()
3645 * virtual function can then be called directly.
3647 dummy = _clutter_dummy_node_new (self);
3648 clutter_paint_node_set_name (dummy, "Root");
3650 /* XXX - for 1.12, we use the return value of paint_node() to
3651 * decide whether we should emit the ::paint signal.
3653 clutter_actor_paint_node (self, dummy);
3654 clutter_paint_node_unref (dummy);
3656 g_signal_emit (self, actor_signals[PAINT], 0);
3660 ClutterColor col = { 0, };
3662 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3664 /* Actor will then paint silhouette of itself in supplied
3665 * color. See clutter_stage_get_actor_at_pos() for where
3666 * picking is enabled.
3668 g_signal_emit (self, actor_signals[PICK], 0, &col);
3673 ClutterEffect *old_current_effect;
3674 ClutterEffectPaintFlags run_flags = 0;
3676 /* Cache the current effect so that we can put it back before
3678 old_current_effect = priv->current_effect;
3680 priv->current_effect = priv->next_effect_to_paint->data;
3681 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3683 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3687 /* If there's an effect queued with this redraw then all
3688 effects up to that one will be considered dirty. It
3689 is expected the queued effect will paint the cached
3690 image and not call clutter_actor_continue_paint again
3691 (although it should work ok if it does) */
3692 if (priv->effect_to_redraw == NULL ||
3693 priv->current_effect != priv->effect_to_redraw)
3694 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3697 _clutter_effect_paint (priv->current_effect, run_flags);
3701 /* We can't determine when an actor has been modified since
3702 its last pick so lets just assume it has always been
3704 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3706 _clutter_effect_pick (priv->current_effect, run_flags);
3709 priv->current_effect = old_current_effect;
3713 static ClutterActorTraverseVisitFlags
3714 invalidate_queue_redraw_entry (ClutterActor *self,
3718 ClutterActorPrivate *priv = self->priv;
3720 if (priv->queue_redraw_entry != NULL)
3722 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3723 priv->queue_redraw_entry = NULL;
3726 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3730 remove_child (ClutterActor *self,
3731 ClutterActor *child)
3733 ClutterActor *prev_sibling, *next_sibling;
3735 prev_sibling = child->priv->prev_sibling;
3736 next_sibling = child->priv->next_sibling;
3738 if (prev_sibling != NULL)
3739 prev_sibling->priv->next_sibling = next_sibling;
3741 if (next_sibling != NULL)
3742 next_sibling->priv->prev_sibling = prev_sibling;
3744 if (self->priv->first_child == child)
3745 self->priv->first_child = next_sibling;
3747 if (self->priv->last_child == child)
3748 self->priv->last_child = prev_sibling;
3750 child->priv->parent = NULL;
3751 child->priv->prev_sibling = NULL;
3752 child->priv->next_sibling = NULL;
3756 REMOVE_CHILD_DESTROY_META = 1 << 0,
3757 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3758 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3759 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3760 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3761 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3763 /* default flags for public API */
3764 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3765 REMOVE_CHILD_EMIT_PARENT_SET |
3766 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3767 REMOVE_CHILD_CHECK_STATE |
3768 REMOVE_CHILD_FLUSH_QUEUE |
3769 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3771 /* flags for legacy/deprecated API */
3772 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3773 REMOVE_CHILD_FLUSH_QUEUE |
3774 REMOVE_CHILD_EMIT_PARENT_SET |
3775 REMOVE_CHILD_NOTIFY_FIRST_LAST
3776 } ClutterActorRemoveChildFlags;
3779 * clutter_actor_remove_child_internal:
3780 * @self: a #ClutterActor
3781 * @child: the child of @self that has to be removed
3782 * @flags: control the removal operations
3784 * Removes @child from the list of children of @self.
3787 clutter_actor_remove_child_internal (ClutterActor *self,
3788 ClutterActor *child,
3789 ClutterActorRemoveChildFlags flags)
3791 ClutterActor *old_first, *old_last;
3792 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3793 gboolean flush_queue;
3794 gboolean notify_first_last;
3795 gboolean was_mapped;
3797 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3798 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3799 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3800 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3801 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3802 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3804 g_object_freeze_notify (G_OBJECT (self));
3807 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3811 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3813 /* we need to unrealize *before* we set parent_actor to NULL,
3814 * because in an unrealize method actors are dissociating from the
3815 * stage, which means they need to be able to
3816 * clutter_actor_get_stage().
3818 * yhis should unmap and unrealize, unless we're reparenting.
3820 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3827 /* We take this opportunity to invalidate any queue redraw entry
3828 * associated with the actor and descendants since we won't be able to
3829 * determine the appropriate stage after this.
3831 * we do this after we updated the mapped state because actors might
3832 * end up queueing redraws inside their mapped/unmapped virtual
3833 * functions, and if we invalidate the redraw entry we could end up
3834 * with an inconsistent state and weird memory corruption. see
3837 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3838 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3840 _clutter_actor_traverse (child,
3842 invalidate_queue_redraw_entry,
3847 old_first = self->priv->first_child;
3848 old_last = self->priv->last_child;
3850 remove_child (self, child);
3852 self->priv->n_children -= 1;
3854 self->priv->age += 1;
3856 /* clutter_actor_reparent() will emit ::parent-set for us */
3857 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3858 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3860 /* if the child was mapped then we need to relayout ourselves to account
3861 * for the removed child
3864 clutter_actor_queue_relayout (self);
3866 /* we need to emit the signal before dropping the reference */
3867 if (emit_actor_removed)
3868 g_signal_emit_by_name (self, "actor-removed", child);
3870 if (notify_first_last)
3872 if (old_first != self->priv->first_child)
3873 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3875 if (old_last != self->priv->last_child)
3876 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3879 g_object_thaw_notify (G_OBJECT (self));
3881 /* remove the reference we acquired in clutter_actor_add_child() */
3882 g_object_unref (child);
3885 static const ClutterTransformInfo default_transform_info = {
3886 0.0, { 0, }, /* rotation-x */
3887 0.0, { 0, }, /* rotation-y */
3888 0.0, { 0, }, /* rotation-z */
3890 1.0, 1.0, { 0, }, /* scale */
3892 { 0, }, /* anchor */
3898 * _clutter_actor_get_transform_info_or_defaults:
3899 * @self: a #ClutterActor
3901 * Retrieves the ClutterTransformInfo structure associated to an actor.
3903 * If the actor does not have a ClutterTransformInfo structure associated
3904 * to it, then the default structure will be returned.
3906 * This function should only be used for getters.
3908 * Return value: a const pointer to the ClutterTransformInfo structure
3910 const ClutterTransformInfo *
3911 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3913 ClutterTransformInfo *info;
3915 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3919 return &default_transform_info;
3923 clutter_transform_info_free (gpointer data)
3926 g_slice_free (ClutterTransformInfo, data);
3930 * _clutter_actor_get_transform_info:
3931 * @self: a #ClutterActor
3933 * Retrieves a pointer to the ClutterTransformInfo structure.
3935 * If the actor does not have a ClutterTransformInfo associated to it, one
3936 * will be created and initialized to the default values.
3938 * This function should be used for setters.
3940 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3943 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3946 ClutterTransformInfo *
3947 _clutter_actor_get_transform_info (ClutterActor *self)
3949 ClutterTransformInfo *info;
3951 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3954 info = g_slice_new (ClutterTransformInfo);
3956 *info = default_transform_info;
3958 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3960 clutter_transform_info_free);
3967 * clutter_actor_set_rotation_angle_internal:
3968 * @self: a #ClutterActor
3969 * @axis: the axis of the angle to change
3970 * @angle: the angle of rotation
3972 * Sets the rotation angle on the given axis without affecting the
3973 * rotation center point.
3976 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3977 ClutterRotateAxis axis,
3980 GObject *obj = G_OBJECT (self);
3981 ClutterTransformInfo *info;
3983 info = _clutter_actor_get_transform_info (self);
3985 g_object_freeze_notify (obj);
3989 case CLUTTER_X_AXIS:
3990 info->rx_angle = angle;
3991 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3994 case CLUTTER_Y_AXIS:
3995 info->ry_angle = angle;
3996 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3999 case CLUTTER_Z_AXIS:
4000 info->rz_angle = angle;
4001 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4005 self->priv->transform_valid = FALSE;
4007 g_object_thaw_notify (obj);
4009 clutter_actor_queue_redraw (self);
4013 clutter_actor_set_rotation_angle (ClutterActor *self,
4014 ClutterRotateAxis axis,
4017 const ClutterTransformInfo *info;
4018 const double *cur_angle_p = NULL;
4019 GParamSpec *pspec = NULL;
4021 info = _clutter_actor_get_transform_info_or_defaults (self);
4025 case CLUTTER_X_AXIS:
4026 cur_angle_p = &info->rx_angle;
4027 pspec = obj_props[PROP_ROTATION_ANGLE_X];
4030 case CLUTTER_Y_AXIS:
4031 cur_angle_p = &info->ry_angle;
4032 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4035 case CLUTTER_Z_AXIS:
4036 cur_angle_p = &info->rz_angle;
4037 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4041 g_assert (pspec != NULL);
4042 g_assert (cur_angle_p != NULL);
4044 if (_clutter_actor_get_transition (self, pspec) == NULL)
4045 _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4047 _clutter_actor_update_transition (self, pspec, angle);
4049 clutter_actor_queue_redraw (self);
4053 * clutter_actor_set_rotation_center_internal:
4054 * @self: a #ClutterActor
4055 * @axis: the axis of the center to change
4056 * @center: the coordinates of the rotation center
4058 * Sets the rotation center on the given axis without affecting the
4062 clutter_actor_set_rotation_center_internal (ClutterActor *self,
4063 ClutterRotateAxis axis,
4064 const ClutterVertex *center)
4066 GObject *obj = G_OBJECT (self);
4067 ClutterTransformInfo *info;
4068 ClutterVertex v = { 0, 0, 0 };
4070 info = _clutter_actor_get_transform_info (self);
4075 g_object_freeze_notify (obj);
4079 case CLUTTER_X_AXIS:
4080 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4081 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4084 case CLUTTER_Y_AXIS:
4085 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4086 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4089 case CLUTTER_Z_AXIS:
4090 /* if the previously set rotation center was fractional, then
4091 * setting explicit coordinates will have to notify the
4092 * :rotation-center-z-gravity property as well
4094 if (info->rz_center.is_fractional)
4095 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4097 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4098 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4102 self->priv->transform_valid = FALSE;
4104 g_object_thaw_notify (obj);
4106 clutter_actor_queue_redraw (self);
4110 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4114 GObject *obj = G_OBJECT (self);
4115 ClutterTransformInfo *info;
4117 info = _clutter_actor_get_transform_info (self);
4119 if (pspec == obj_props[PROP_SCALE_X])
4120 info->scale_x = factor;
4122 info->scale_y = factor;
4124 self->priv->transform_valid = FALSE;
4125 clutter_actor_queue_redraw (self);
4126 g_object_notify_by_pspec (obj, pspec);
4130 clutter_actor_set_scale_factor (ClutterActor *self,
4131 ClutterRotateAxis axis,
4134 const ClutterTransformInfo *info;
4135 const double *scale_p = NULL;
4136 GParamSpec *pspec = NULL;
4138 info = _clutter_actor_get_transform_info_or_defaults (self);
4142 case CLUTTER_X_AXIS:
4143 pspec = obj_props[PROP_SCALE_X];
4144 scale_p = &info->scale_x;
4147 case CLUTTER_Y_AXIS:
4148 pspec = obj_props[PROP_SCALE_Y];
4149 scale_p = &info->scale_y;
4152 case CLUTTER_Z_AXIS:
4156 g_assert (pspec != NULL);
4157 g_assert (scale_p != NULL);
4159 if (_clutter_actor_get_transition (self, pspec) == NULL)
4160 _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4162 _clutter_actor_update_transition (self, pspec, factor);
4164 clutter_actor_queue_redraw (self);
4168 clutter_actor_set_scale_center (ClutterActor *self,
4169 ClutterRotateAxis axis,
4172 GObject *obj = G_OBJECT (self);
4173 ClutterTransformInfo *info;
4174 gfloat center_x, center_y;
4176 info = _clutter_actor_get_transform_info (self);
4178 g_object_freeze_notify (obj);
4180 /* get the current scale center coordinates */
4181 clutter_anchor_coord_get_units (self, &info->scale_center,
4186 /* we need to notify this too, because setting explicit coordinates will
4187 * change the gravity as a side effect
4189 if (info->scale_center.is_fractional)
4190 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4194 case CLUTTER_X_AXIS:
4195 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4196 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4199 case CLUTTER_Y_AXIS:
4200 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4201 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4205 g_assert_not_reached ();
4208 self->priv->transform_valid = FALSE;
4210 clutter_actor_queue_redraw (self);
4212 g_object_thaw_notify (obj);
4216 clutter_actor_set_scale_gravity (ClutterActor *self,
4217 ClutterGravity gravity)
4219 ClutterTransformInfo *info;
4222 info = _clutter_actor_get_transform_info (self);
4223 obj = G_OBJECT (self);
4225 if (gravity == CLUTTER_GRAVITY_NONE)
4226 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4228 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4230 self->priv->transform_valid = FALSE;
4232 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4233 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4234 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4236 clutter_actor_queue_redraw (self);
4240 clutter_actor_set_anchor_coord (ClutterActor *self,
4241 ClutterRotateAxis axis,
4244 GObject *obj = G_OBJECT (self);
4245 ClutterTransformInfo *info;
4246 gfloat anchor_x, anchor_y;
4248 info = _clutter_actor_get_transform_info (self);
4250 g_object_freeze_notify (obj);
4252 clutter_anchor_coord_get_units (self, &info->anchor,
4257 if (info->anchor.is_fractional)
4258 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4262 case CLUTTER_X_AXIS:
4263 clutter_anchor_coord_set_units (&info->anchor,
4267 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4270 case CLUTTER_Y_AXIS:
4271 clutter_anchor_coord_set_units (&info->anchor,
4275 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4279 g_assert_not_reached ();
4282 self->priv->transform_valid = FALSE;
4284 clutter_actor_queue_redraw (self);
4286 g_object_thaw_notify (obj);
4290 clutter_actor_set_property (GObject *object,
4292 const GValue *value,
4295 ClutterActor *actor = CLUTTER_ACTOR (object);
4296 ClutterActorPrivate *priv = actor->priv;
4301 clutter_actor_set_x (actor, g_value_get_float (value));
4305 clutter_actor_set_y (actor, g_value_get_float (value));
4309 clutter_actor_set_width (actor, g_value_get_float (value));
4313 clutter_actor_set_height (actor, g_value_get_float (value));
4317 clutter_actor_set_x (actor, g_value_get_float (value));
4321 clutter_actor_set_y (actor, g_value_get_float (value));
4324 case PROP_FIXED_POSITION_SET:
4325 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4328 case PROP_MIN_WIDTH:
4329 clutter_actor_set_min_width (actor, g_value_get_float (value));
4332 case PROP_MIN_HEIGHT:
4333 clutter_actor_set_min_height (actor, g_value_get_float (value));
4336 case PROP_NATURAL_WIDTH:
4337 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4340 case PROP_NATURAL_HEIGHT:
4341 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4344 case PROP_MIN_WIDTH_SET:
4345 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4348 case PROP_MIN_HEIGHT_SET:
4349 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4352 case PROP_NATURAL_WIDTH_SET:
4353 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4356 case PROP_NATURAL_HEIGHT_SET:
4357 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4360 case PROP_REQUEST_MODE:
4361 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4365 clutter_actor_set_depth (actor, g_value_get_float (value));
4369 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4372 case PROP_OFFSCREEN_REDIRECT:
4373 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4377 clutter_actor_set_name (actor, g_value_get_string (value));
4381 if (g_value_get_boolean (value) == TRUE)
4382 clutter_actor_show (actor);
4384 clutter_actor_hide (actor);
4388 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4389 g_value_get_double (value));
4393 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4394 g_value_get_double (value));
4397 case PROP_SCALE_CENTER_X:
4398 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4399 g_value_get_float (value));
4402 case PROP_SCALE_CENTER_Y:
4403 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4404 g_value_get_float (value));
4407 case PROP_SCALE_GRAVITY:
4408 clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4413 const ClutterGeometry *geom = g_value_get_boxed (value);
4415 clutter_actor_set_clip (actor,
4417 geom->width, geom->height);
4421 case PROP_CLIP_TO_ALLOCATION:
4422 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4426 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4429 case PROP_ROTATION_ANGLE_X:
4430 clutter_actor_set_rotation_angle (actor,
4432 g_value_get_double (value));
4435 case PROP_ROTATION_ANGLE_Y:
4436 clutter_actor_set_rotation_angle (actor,
4438 g_value_get_double (value));
4441 case PROP_ROTATION_ANGLE_Z:
4442 clutter_actor_set_rotation_angle (actor,
4444 g_value_get_double (value));
4447 case PROP_ROTATION_CENTER_X:
4448 clutter_actor_set_rotation_center_internal (actor,
4450 g_value_get_boxed (value));
4453 case PROP_ROTATION_CENTER_Y:
4454 clutter_actor_set_rotation_center_internal (actor,
4456 g_value_get_boxed (value));
4459 case PROP_ROTATION_CENTER_Z:
4460 clutter_actor_set_rotation_center_internal (actor,
4462 g_value_get_boxed (value));
4465 case PROP_ROTATION_CENTER_Z_GRAVITY:
4467 const ClutterTransformInfo *info;
4469 info = _clutter_actor_get_transform_info_or_defaults (actor);
4470 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4471 g_value_get_enum (value));
4476 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4477 g_value_get_float (value));
4481 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4482 g_value_get_float (value));
4485 case PROP_ANCHOR_GRAVITY:
4486 clutter_actor_set_anchor_point_from_gravity (actor,
4487 g_value_get_enum (value));
4490 case PROP_SHOW_ON_SET_PARENT:
4491 priv->show_on_set_parent = g_value_get_boolean (value);
4494 case PROP_TEXT_DIRECTION:
4495 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4499 clutter_actor_add_action (actor, g_value_get_object (value));
4502 case PROP_CONSTRAINTS:
4503 clutter_actor_add_constraint (actor, g_value_get_object (value));
4507 clutter_actor_add_effect (actor, g_value_get_object (value));
4510 case PROP_LAYOUT_MANAGER:
4511 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4515 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4519 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4522 case PROP_MARGIN_TOP:
4523 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4526 case PROP_MARGIN_BOTTOM:
4527 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4530 case PROP_MARGIN_LEFT:
4531 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4534 case PROP_MARGIN_RIGHT:
4535 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4538 case PROP_BACKGROUND_COLOR:
4539 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4543 clutter_actor_set_content (actor, g_value_get_object (value));
4546 case PROP_CONTENT_GRAVITY:
4547 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4550 case PROP_MINIFICATION_FILTER:
4551 clutter_actor_set_content_scaling_filters (actor,
4552 g_value_get_enum (value),
4553 actor->priv->mag_filter);
4556 case PROP_MAGNIFICATION_FILTER:
4557 clutter_actor_set_content_scaling_filters (actor,
4558 actor->priv->min_filter,
4559 g_value_get_enum (value));
4563 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4569 clutter_actor_get_property (GObject *object,
4574 ClutterActor *actor = CLUTTER_ACTOR (object);
4575 ClutterActorPrivate *priv = actor->priv;
4580 g_value_set_float (value, clutter_actor_get_x (actor));
4584 g_value_set_float (value, clutter_actor_get_y (actor));
4588 g_value_set_float (value, clutter_actor_get_width (actor));
4592 g_value_set_float (value, clutter_actor_get_height (actor));
4597 const ClutterLayoutInfo *info;
4599 info = _clutter_actor_get_layout_info_or_defaults (actor);
4600 g_value_set_float (value, info->fixed_x);
4606 const ClutterLayoutInfo *info;
4608 info = _clutter_actor_get_layout_info_or_defaults (actor);
4609 g_value_set_float (value, info->fixed_y);
4613 case PROP_FIXED_POSITION_SET:
4614 g_value_set_boolean (value, priv->position_set);
4617 case PROP_MIN_WIDTH:
4619 const ClutterLayoutInfo *info;
4621 info = _clutter_actor_get_layout_info_or_defaults (actor);
4622 g_value_set_float (value, info->min_width);
4626 case PROP_MIN_HEIGHT:
4628 const ClutterLayoutInfo *info;
4630 info = _clutter_actor_get_layout_info_or_defaults (actor);
4631 g_value_set_float (value, info->min_height);
4635 case PROP_NATURAL_WIDTH:
4637 const ClutterLayoutInfo *info;
4639 info = _clutter_actor_get_layout_info_or_defaults (actor);
4640 g_value_set_float (value, info->natural_width);
4644 case PROP_NATURAL_HEIGHT:
4646 const ClutterLayoutInfo *info;
4648 info = _clutter_actor_get_layout_info_or_defaults (actor);
4649 g_value_set_float (value, info->natural_height);
4653 case PROP_MIN_WIDTH_SET:
4654 g_value_set_boolean (value, priv->min_width_set);
4657 case PROP_MIN_HEIGHT_SET:
4658 g_value_set_boolean (value, priv->min_height_set);
4661 case PROP_NATURAL_WIDTH_SET:
4662 g_value_set_boolean (value, priv->natural_width_set);
4665 case PROP_NATURAL_HEIGHT_SET:
4666 g_value_set_boolean (value, priv->natural_height_set);
4669 case PROP_REQUEST_MODE:
4670 g_value_set_enum (value, priv->request_mode);
4673 case PROP_ALLOCATION:
4674 g_value_set_boxed (value, &priv->allocation);
4678 g_value_set_float (value, clutter_actor_get_depth (actor));
4682 g_value_set_uint (value, priv->opacity);
4685 case PROP_OFFSCREEN_REDIRECT:
4686 g_value_set_enum (value, priv->offscreen_redirect);
4690 g_value_set_string (value, priv->name);
4694 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4698 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4702 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4706 g_value_set_boolean (value, priv->has_clip);
4711 ClutterGeometry clip;
4713 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4714 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4715 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4716 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4718 g_value_set_boxed (value, &clip);
4722 case PROP_CLIP_TO_ALLOCATION:
4723 g_value_set_boolean (value, priv->clip_to_allocation);
4728 const ClutterTransformInfo *info;
4730 info = _clutter_actor_get_transform_info_or_defaults (actor);
4731 g_value_set_double (value, info->scale_x);
4737 const ClutterTransformInfo *info;
4739 info = _clutter_actor_get_transform_info_or_defaults (actor);
4740 g_value_set_double (value, info->scale_y);
4744 case PROP_SCALE_CENTER_X:
4748 clutter_actor_get_scale_center (actor, ¢er, NULL);
4750 g_value_set_float (value, center);
4754 case PROP_SCALE_CENTER_Y:
4758 clutter_actor_get_scale_center (actor, NULL, ¢er);
4760 g_value_set_float (value, center);
4764 case PROP_SCALE_GRAVITY:
4765 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4769 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4772 case PROP_ROTATION_ANGLE_X:
4774 const ClutterTransformInfo *info;
4776 info = _clutter_actor_get_transform_info_or_defaults (actor);
4777 g_value_set_double (value, info->rx_angle);
4781 case PROP_ROTATION_ANGLE_Y:
4783 const ClutterTransformInfo *info;
4785 info = _clutter_actor_get_transform_info_or_defaults (actor);
4786 g_value_set_double (value, info->ry_angle);
4790 case PROP_ROTATION_ANGLE_Z:
4792 const ClutterTransformInfo *info;
4794 info = _clutter_actor_get_transform_info_or_defaults (actor);
4795 g_value_set_double (value, info->rz_angle);
4799 case PROP_ROTATION_CENTER_X:
4801 ClutterVertex center;
4803 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4808 g_value_set_boxed (value, ¢er);
4812 case PROP_ROTATION_CENTER_Y:
4814 ClutterVertex center;
4816 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4821 g_value_set_boxed (value, ¢er);
4825 case PROP_ROTATION_CENTER_Z:
4827 ClutterVertex center;
4829 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4834 g_value_set_boxed (value, ¢er);
4838 case PROP_ROTATION_CENTER_Z_GRAVITY:
4839 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4844 const ClutterTransformInfo *info;
4847 info = _clutter_actor_get_transform_info_or_defaults (actor);
4848 clutter_anchor_coord_get_units (actor, &info->anchor,
4852 g_value_set_float (value, anchor_x);
4858 const ClutterTransformInfo *info;
4861 info = _clutter_actor_get_transform_info_or_defaults (actor);
4862 clutter_anchor_coord_get_units (actor, &info->anchor,
4866 g_value_set_float (value, anchor_y);
4870 case PROP_ANCHOR_GRAVITY:
4871 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4874 case PROP_SHOW_ON_SET_PARENT:
4875 g_value_set_boolean (value, priv->show_on_set_parent);
4878 case PROP_TEXT_DIRECTION:
4879 g_value_set_enum (value, priv->text_direction);
4882 case PROP_HAS_POINTER:
4883 g_value_set_boolean (value, priv->has_pointer);
4886 case PROP_LAYOUT_MANAGER:
4887 g_value_set_object (value, priv->layout_manager);
4892 const ClutterLayoutInfo *info;
4894 info = _clutter_actor_get_layout_info_or_defaults (actor);
4895 g_value_set_enum (value, info->x_align);
4901 const ClutterLayoutInfo *info;
4903 info = _clutter_actor_get_layout_info_or_defaults (actor);
4904 g_value_set_enum (value, info->y_align);
4908 case PROP_MARGIN_TOP:
4910 const ClutterLayoutInfo *info;
4912 info = _clutter_actor_get_layout_info_or_defaults (actor);
4913 g_value_set_float (value, info->margin.top);
4917 case PROP_MARGIN_BOTTOM:
4919 const ClutterLayoutInfo *info;
4921 info = _clutter_actor_get_layout_info_or_defaults (actor);
4922 g_value_set_float (value, info->margin.bottom);
4926 case PROP_MARGIN_LEFT:
4928 const ClutterLayoutInfo *info;
4930 info = _clutter_actor_get_layout_info_or_defaults (actor);
4931 g_value_set_float (value, info->margin.left);
4935 case PROP_MARGIN_RIGHT:
4937 const ClutterLayoutInfo *info;
4939 info = _clutter_actor_get_layout_info_or_defaults (actor);
4940 g_value_set_float (value, info->margin.right);
4944 case PROP_BACKGROUND_COLOR_SET:
4945 g_value_set_boolean (value, priv->bg_color_set);
4948 case PROP_BACKGROUND_COLOR:
4949 g_value_set_boxed (value, &priv->bg_color);
4952 case PROP_FIRST_CHILD:
4953 g_value_set_object (value, priv->first_child);
4956 case PROP_LAST_CHILD:
4957 g_value_set_object (value, priv->last_child);
4961 g_value_set_object (value, priv->content);
4964 case PROP_CONTENT_GRAVITY:
4965 g_value_set_enum (value, priv->content_gravity);
4968 case PROP_CONTENT_BOX:
4970 ClutterActorBox box = { 0, };
4972 clutter_actor_get_content_box (actor, &box);
4973 g_value_set_boxed (value, &box);
4977 case PROP_MINIFICATION_FILTER:
4978 g_value_set_enum (value, priv->min_filter);
4981 case PROP_MAGNIFICATION_FILTER:
4982 g_value_set_enum (value, priv->mag_filter);
4986 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4992 clutter_actor_dispose (GObject *object)
4994 ClutterActor *self = CLUTTER_ACTOR (object);
4995 ClutterActorPrivate *priv = self->priv;
4997 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4999 g_type_name (G_OBJECT_TYPE (self)),
5002 g_signal_emit (self, actor_signals[DESTROY], 0);
5004 /* avoid recursing when called from clutter_actor_destroy() */
5005 if (priv->parent != NULL)
5007 ClutterActor *parent = priv->parent;
5009 /* go through the Container implementation unless this
5010 * is an internal child and has been marked as such.
5012 * removing the actor from its parent will reset the
5013 * realized and mapped states.
5015 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5016 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5018 clutter_actor_remove_child_internal (parent, self,
5019 REMOVE_CHILD_LEGACY_FLAGS);
5022 /* parent must be gone at this point */
5023 g_assert (priv->parent == NULL);
5025 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5027 /* can't be mapped or realized with no parent */
5028 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5029 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5032 g_clear_object (&priv->pango_context);
5033 g_clear_object (&priv->actions);
5034 g_clear_object (&priv->constraints);
5035 g_clear_object (&priv->effects);
5036 g_clear_object (&priv->flatten_effect);
5038 if (priv->layout_manager != NULL)
5040 clutter_layout_manager_set_container (priv->layout_manager, NULL);
5041 g_clear_object (&priv->layout_manager);
5044 if (priv->content != NULL)
5046 _clutter_content_detached (priv->content, self);
5047 g_clear_object (&priv->content);
5050 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5054 clutter_actor_finalize (GObject *object)
5056 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5058 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5059 priv->name != NULL ? priv->name : "<none>",
5061 g_type_name (G_OBJECT_TYPE (object)));
5063 _clutter_context_release_id (priv->id);
5065 g_free (priv->name);
5067 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5072 * clutter_actor_get_accessible:
5073 * @self: a #ClutterActor
5075 * Returns the accessible object that describes the actor to an
5076 * assistive technology.
5078 * If no class-specific #AtkObject implementation is available for the
5079 * actor instance in question, it will inherit an #AtkObject
5080 * implementation from the first ancestor class for which such an
5081 * implementation is defined.
5083 * The documentation of the <ulink
5084 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5085 * library contains more information about accessible objects and
5088 * Returns: (transfer none): the #AtkObject associated with @actor
5091 clutter_actor_get_accessible (ClutterActor *self)
5093 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5095 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5099 clutter_actor_real_get_accessible (ClutterActor *actor)
5101 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5105 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5107 AtkObject *accessible;
5109 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5110 if (accessible != NULL)
5111 g_object_ref (accessible);
5117 atk_implementor_iface_init (AtkImplementorIface *iface)
5119 iface->ref_accessible = _clutter_actor_ref_accessible;
5123 clutter_actor_update_default_paint_volume (ClutterActor *self,
5124 ClutterPaintVolume *volume)
5126 ClutterActorPrivate *priv = self->priv;
5127 gboolean res = FALSE;
5129 /* we start from the allocation */
5130 clutter_paint_volume_set_width (volume,
5131 priv->allocation.x2 - priv->allocation.x1);
5132 clutter_paint_volume_set_height (volume,
5133 priv->allocation.y2 - priv->allocation.y1);
5135 /* if the actor has a clip set then we have a pretty definite
5136 * size for the paint volume: the actor cannot possibly paint
5137 * outside the clip region.
5139 if (priv->clip_to_allocation)
5141 /* the allocation has already been set, so we just flip the
5148 ClutterActor *child;
5150 if (priv->has_clip &&
5151 priv->clip.width >= 0 &&
5152 priv->clip.height >= 0)
5154 ClutterVertex origin;
5156 origin.x = priv->clip.x;
5157 origin.y = priv->clip.y;
5160 clutter_paint_volume_set_origin (volume, &origin);
5161 clutter_paint_volume_set_width (volume, priv->clip.width);
5162 clutter_paint_volume_set_height (volume, priv->clip.height);
5167 /* if we don't have children we just bail out here... */
5168 if (priv->n_children == 0)
5171 /* ...but if we have children then we ask for their paint volume in
5172 * our coordinates. if any of our children replies that it doesn't
5173 * have a paint volume, we bail out
5175 for (child = priv->first_child;
5177 child = child->priv->next_sibling)
5179 const ClutterPaintVolume *child_volume;
5181 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5182 if (child_volume == NULL)
5188 clutter_paint_volume_union (volume, child_volume);
5198 clutter_actor_real_get_paint_volume (ClutterActor *self,
5199 ClutterPaintVolume *volume)
5201 ClutterActorClass *klass;
5204 klass = CLUTTER_ACTOR_GET_CLASS (self);
5206 /* XXX - this thoroughly sucks, but we don't want to penalize users
5207 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5208 * redraw. This should go away in 2.0.
5210 if (klass->paint == clutter_actor_real_paint &&
5211 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5217 /* this is the default return value: we cannot know if a class
5218 * is going to paint outside its allocation, so we take the
5219 * conservative approach.
5224 if (clutter_actor_update_default_paint_volume (self, volume))
5231 * clutter_actor_get_default_paint_volume:
5232 * @self: a #ClutterActor
5234 * Retrieves the default paint volume for @self.
5236 * This function provides the same #ClutterPaintVolume that would be
5237 * computed by the default implementation inside #ClutterActor of the
5238 * #ClutterActorClass.get_paint_volume() virtual function.
5240 * This function should only be used by #ClutterActor subclasses that
5241 * cannot chain up to the parent implementation when computing their
5244 * Return value: (transfer none): a pointer to the default
5245 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5246 * the actor could not compute a valid paint volume. The returned value
5247 * is not guaranteed to be stable across multiple frames, so if you
5248 * want to retain it, you will need to copy it using
5249 * clutter_paint_volume_copy().
5253 const ClutterPaintVolume *
5254 clutter_actor_get_default_paint_volume (ClutterActor *self)
5256 ClutterPaintVolume volume;
5257 ClutterPaintVolume *res;
5259 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5262 _clutter_paint_volume_init_static (&volume, self);
5263 if (clutter_actor_update_default_paint_volume (self, &volume))
5265 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5269 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5270 _clutter_paint_volume_copy_static (&volume, res);
5274 clutter_paint_volume_free (&volume);
5280 clutter_actor_real_has_overlaps (ClutterActor *self)
5282 /* By default we'll assume that all actors need an offscreen redirect to get
5283 * the correct opacity. Actors such as ClutterTexture that would never need
5284 * an offscreen redirect can override this to return FALSE. */
5289 clutter_actor_real_destroy (ClutterActor *actor)
5291 ClutterActorIter iter;
5293 g_object_freeze_notify (G_OBJECT (actor));
5295 clutter_actor_iter_init (&iter, actor);
5296 while (clutter_actor_iter_next (&iter, NULL))
5297 clutter_actor_iter_destroy (&iter);
5299 g_object_thaw_notify (G_OBJECT (actor));
5303 clutter_actor_constructor (GType gtype,
5305 GObjectConstructParam *props)
5307 GObjectClass *gobject_class;
5311 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5312 retval = gobject_class->constructor (gtype, n_props, props);
5313 self = CLUTTER_ACTOR (retval);
5315 if (self->priv->layout_manager == NULL)
5317 ClutterLayoutManager *default_layout;
5319 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5321 default_layout = clutter_fixed_layout_new ();
5322 clutter_actor_set_layout_manager (self, default_layout);
5329 clutter_actor_class_init (ClutterActorClass *klass)
5331 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5333 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5334 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5335 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5336 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5338 object_class->constructor = clutter_actor_constructor;
5339 object_class->set_property = clutter_actor_set_property;
5340 object_class->get_property = clutter_actor_get_property;
5341 object_class->dispose = clutter_actor_dispose;
5342 object_class->finalize = clutter_actor_finalize;
5344 klass->show = clutter_actor_real_show;
5345 klass->show_all = clutter_actor_show;
5346 klass->hide = clutter_actor_real_hide;
5347 klass->hide_all = clutter_actor_hide;
5348 klass->map = clutter_actor_real_map;
5349 klass->unmap = clutter_actor_real_unmap;
5350 klass->unrealize = clutter_actor_real_unrealize;
5351 klass->pick = clutter_actor_real_pick;
5352 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5353 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5354 klass->allocate = clutter_actor_real_allocate;
5355 klass->queue_redraw = clutter_actor_real_queue_redraw;
5356 klass->queue_relayout = clutter_actor_real_queue_relayout;
5357 klass->apply_transform = clutter_actor_real_apply_transform;
5358 klass->get_accessible = clutter_actor_real_get_accessible;
5359 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5360 klass->has_overlaps = clutter_actor_real_has_overlaps;
5361 klass->paint = clutter_actor_real_paint;
5362 klass->destroy = clutter_actor_real_destroy;
5364 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5369 * X coordinate of the actor in pixels. If written, forces a fixed
5370 * position for the actor. If read, returns the fixed position if any,
5371 * otherwise the allocation if available, otherwise 0.
5373 * The #ClutterActor:x property is animatable.
5376 g_param_spec_float ("x",
5378 P_("X coordinate of the actor"),
5379 -G_MAXFLOAT, G_MAXFLOAT,
5382 G_PARAM_STATIC_STRINGS |
5383 CLUTTER_PARAM_ANIMATABLE);
5388 * Y coordinate of the actor in pixels. If written, forces a fixed
5389 * position for the actor. If read, returns the fixed position if
5390 * any, otherwise the allocation if available, otherwise 0.
5392 * The #ClutterActor:y property is animatable.
5395 g_param_spec_float ("y",
5397 P_("Y coordinate of the actor"),
5398 -G_MAXFLOAT, G_MAXFLOAT,
5401 G_PARAM_STATIC_STRINGS |
5402 CLUTTER_PARAM_ANIMATABLE);
5405 * ClutterActor:width:
5407 * Width of the actor (in pixels). If written, forces the minimum and
5408 * natural size request of the actor to the given width. If read, returns
5409 * the allocated width if available, otherwise the width request.
5411 * The #ClutterActor:width property is animatable.
5413 obj_props[PROP_WIDTH] =
5414 g_param_spec_float ("width",
5416 P_("Width of the actor"),
5420 G_PARAM_STATIC_STRINGS |
5421 CLUTTER_PARAM_ANIMATABLE);
5424 * ClutterActor:height:
5426 * Height of the actor (in pixels). If written, forces the minimum and
5427 * natural size request of the actor to the given height. If read, returns
5428 * the allocated height if available, otherwise the height request.
5430 * The #ClutterActor:height property is animatable.
5432 obj_props[PROP_HEIGHT] =
5433 g_param_spec_float ("height",
5435 P_("Height of the actor"),
5439 G_PARAM_STATIC_STRINGS |
5440 CLUTTER_PARAM_ANIMATABLE);
5443 * ClutterActor:fixed-x:
5445 * The fixed X position of the actor in pixels.
5447 * Writing this property sets #ClutterActor:fixed-position-set
5448 * property as well, as a side effect
5452 obj_props[PROP_FIXED_X] =
5453 g_param_spec_float ("fixed-x",
5455 P_("Forced X position of the actor"),
5456 -G_MAXFLOAT, G_MAXFLOAT,
5458 CLUTTER_PARAM_READWRITE);
5461 * ClutterActor:fixed-y:
5463 * The fixed Y position of the actor in pixels.
5465 * Writing this property sets the #ClutterActor:fixed-position-set
5466 * property as well, as a side effect
5470 obj_props[PROP_FIXED_Y] =
5471 g_param_spec_float ("fixed-y",
5473 P_("Forced Y position of the actor"),
5474 -G_MAXFLOAT, G_MAXFLOAT,
5476 CLUTTER_PARAM_READWRITE);
5479 * ClutterActor:fixed-position-set:
5481 * This flag controls whether the #ClutterActor:fixed-x and
5482 * #ClutterActor:fixed-y properties are used
5486 obj_props[PROP_FIXED_POSITION_SET] =
5487 g_param_spec_boolean ("fixed-position-set",
5488 P_("Fixed position set"),
5489 P_("Whether to use fixed positioning for the actor"),
5491 CLUTTER_PARAM_READWRITE);
5494 * ClutterActor:min-width:
5496 * A forced minimum width request for the actor, in pixels
5498 * Writing this property sets the #ClutterActor:min-width-set property
5499 * as well, as a side effect.
5501 *This property overrides the usual width request of the actor.
5505 obj_props[PROP_MIN_WIDTH] =
5506 g_param_spec_float ("min-width",
5508 P_("Forced minimum width request for the actor"),
5511 CLUTTER_PARAM_READWRITE);
5514 * ClutterActor:min-height:
5516 * A forced minimum height request for the actor, in pixels
5518 * Writing this property sets the #ClutterActor:min-height-set property
5519 * as well, as a side effect. This property overrides the usual height
5520 * request of the actor.
5524 obj_props[PROP_MIN_HEIGHT] =
5525 g_param_spec_float ("min-height",
5527 P_("Forced minimum height request for the actor"),
5530 CLUTTER_PARAM_READWRITE);
5533 * ClutterActor:natural-width:
5535 * A forced natural width request for the actor, in pixels
5537 * Writing this property sets the #ClutterActor:natural-width-set
5538 * property as well, as a side effect. This property overrides the
5539 * usual width request of the actor
5543 obj_props[PROP_NATURAL_WIDTH] =
5544 g_param_spec_float ("natural-width",
5545 P_("Natural Width"),
5546 P_("Forced natural width request for the actor"),
5549 CLUTTER_PARAM_READWRITE);
5552 * ClutterActor:natural-height:
5554 * A forced natural height request for the actor, in pixels
5556 * Writing this property sets the #ClutterActor:natural-height-set
5557 * property as well, as a side effect. This property overrides the
5558 * usual height request of the actor
5562 obj_props[PROP_NATURAL_HEIGHT] =
5563 g_param_spec_float ("natural-height",
5564 P_("Natural Height"),
5565 P_("Forced natural height request for the actor"),
5568 CLUTTER_PARAM_READWRITE);
5571 * ClutterActor:min-width-set:
5573 * This flag controls whether the #ClutterActor:min-width property
5578 obj_props[PROP_MIN_WIDTH_SET] =
5579 g_param_spec_boolean ("min-width-set",
5580 P_("Minimum width set"),
5581 P_("Whether to use the min-width property"),
5583 CLUTTER_PARAM_READWRITE);
5586 * ClutterActor:min-height-set:
5588 * This flag controls whether the #ClutterActor:min-height property
5593 obj_props[PROP_MIN_HEIGHT_SET] =
5594 g_param_spec_boolean ("min-height-set",
5595 P_("Minimum height set"),
5596 P_("Whether to use the min-height property"),
5598 CLUTTER_PARAM_READWRITE);
5601 * ClutterActor:natural-width-set:
5603 * This flag controls whether the #ClutterActor:natural-width property
5608 obj_props[PROP_NATURAL_WIDTH_SET] =
5609 g_param_spec_boolean ("natural-width-set",
5610 P_("Natural width set"),
5611 P_("Whether to use the natural-width property"),
5613 CLUTTER_PARAM_READWRITE);
5616 * ClutterActor:natural-height-set:
5618 * This flag controls whether the #ClutterActor:natural-height property
5623 obj_props[PROP_NATURAL_HEIGHT_SET] =
5624 g_param_spec_boolean ("natural-height-set",
5625 P_("Natural height set"),
5626 P_("Whether to use the natural-height property"),
5628 CLUTTER_PARAM_READWRITE);
5631 * ClutterActor:allocation:
5633 * The allocation for the actor, in pixels
5635 * This is property is read-only, but you might monitor it to know when an
5636 * actor moves or resizes
5640 obj_props[PROP_ALLOCATION] =
5641 g_param_spec_boxed ("allocation",
5643 P_("The actor's allocation"),
5644 CLUTTER_TYPE_ACTOR_BOX,
5645 CLUTTER_PARAM_READABLE);
5648 * ClutterActor:request-mode:
5650 * Request mode for the #ClutterActor. The request mode determines the
5651 * type of geometry management used by the actor, either height for width
5652 * (the default) or width for height.
5654 * For actors implementing height for width, the parent container should get
5655 * the preferred width first, and then the preferred height for that width.
5657 * For actors implementing width for height, the parent container should get
5658 * the preferred height first, and then the preferred width for that height.
5663 * ClutterRequestMode mode;
5664 * gfloat natural_width, min_width;
5665 * gfloat natural_height, min_height;
5667 * mode = clutter_actor_get_request_mode (child);
5668 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5670 * clutter_actor_get_preferred_width (child, -1,
5672 * &natural_width);
5673 * clutter_actor_get_preferred_height (child, natural_width,
5675 * &natural_height);
5679 * clutter_actor_get_preferred_height (child, -1,
5681 * &natural_height);
5682 * clutter_actor_get_preferred_width (child, natural_height,
5684 * &natural_width);
5688 * will retrieve the minimum and natural width and height depending on the
5689 * preferred request mode of the #ClutterActor "child".
5691 * The clutter_actor_get_preferred_size() function will implement this
5696 obj_props[PROP_REQUEST_MODE] =
5697 g_param_spec_enum ("request-mode",
5699 P_("The actor's request mode"),
5700 CLUTTER_TYPE_REQUEST_MODE,
5701 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5702 CLUTTER_PARAM_READWRITE);
5705 * ClutterActor:depth:
5707 * The position of the actor on the Z axis.
5709 * The #ClutterActor:depth property is relative to the parent's
5712 * The #ClutterActor:depth property is animatable.
5716 obj_props[PROP_DEPTH] =
5717 g_param_spec_float ("depth",
5719 P_("Position on the Z axis"),
5720 -G_MAXFLOAT, G_MAXFLOAT,
5723 G_PARAM_STATIC_STRINGS |
5724 CLUTTER_PARAM_ANIMATABLE);
5727 * ClutterActor:opacity:
5729 * Opacity of an actor, between 0 (fully transparent) and
5730 * 255 (fully opaque)
5732 * The #ClutterActor:opacity property is animatable.
5734 obj_props[PROP_OPACITY] =
5735 g_param_spec_uint ("opacity",
5737 P_("Opacity of an actor"),
5741 G_PARAM_STATIC_STRINGS |
5742 CLUTTER_PARAM_ANIMATABLE);
5745 * ClutterActor:offscreen-redirect:
5747 * Determines the conditions in which the actor will be redirected
5748 * to an offscreen framebuffer while being painted. For example this
5749 * can be used to cache an actor in a framebuffer or for improved
5750 * handling of transparent actors. See
5751 * clutter_actor_set_offscreen_redirect() for details.
5755 obj_props[PROP_OFFSCREEN_REDIRECT] =
5756 g_param_spec_flags ("offscreen-redirect",
5757 P_("Offscreen redirect"),
5758 P_("Flags controlling when to flatten the actor into a single image"),
5759 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5761 CLUTTER_PARAM_READWRITE);
5764 * ClutterActor:visible:
5766 * Whether the actor is set to be visible or not
5768 * See also #ClutterActor:mapped
5770 obj_props[PROP_VISIBLE] =
5771 g_param_spec_boolean ("visible",
5773 P_("Whether the actor is visible or not"),
5775 CLUTTER_PARAM_READWRITE);
5778 * ClutterActor:mapped:
5780 * Whether the actor is mapped (will be painted when the stage
5781 * to which it belongs is mapped)
5785 obj_props[PROP_MAPPED] =
5786 g_param_spec_boolean ("mapped",
5788 P_("Whether the actor will be painted"),
5790 CLUTTER_PARAM_READABLE);
5793 * ClutterActor:realized:
5795 * Whether the actor has been realized
5799 obj_props[PROP_REALIZED] =
5800 g_param_spec_boolean ("realized",
5802 P_("Whether the actor has been realized"),
5804 CLUTTER_PARAM_READABLE);
5807 * ClutterActor:reactive:
5809 * Whether the actor is reactive to events or not
5811 * Only reactive actors will emit event-related signals
5815 obj_props[PROP_REACTIVE] =
5816 g_param_spec_boolean ("reactive",
5818 P_("Whether the actor is reactive to events"),
5820 CLUTTER_PARAM_READWRITE);
5823 * ClutterActor:has-clip:
5825 * Whether the actor has the #ClutterActor:clip property set or not
5827 obj_props[PROP_HAS_CLIP] =
5828 g_param_spec_boolean ("has-clip",
5830 P_("Whether the actor has a clip set"),
5832 CLUTTER_PARAM_READABLE);
5835 * ClutterActor:clip:
5837 * The clip region for the actor, in actor-relative coordinates
5839 * Every part of the actor outside the clip region will not be
5842 obj_props[PROP_CLIP] =
5843 g_param_spec_boxed ("clip",
5845 P_("The clip region for the actor"),
5846 CLUTTER_TYPE_GEOMETRY,
5847 CLUTTER_PARAM_READWRITE);
5850 * ClutterActor:name:
5852 * The name of the actor
5856 obj_props[PROP_NAME] =
5857 g_param_spec_string ("name",
5859 P_("Name of the actor"),
5861 CLUTTER_PARAM_READWRITE);
5864 * ClutterActor:scale-x:
5866 * The horizontal scale of the actor.
5868 * The #ClutterActor:scale-x property is animatable.
5872 obj_props[PROP_SCALE_X] =
5873 g_param_spec_double ("scale-x",
5875 P_("Scale factor on the X axis"),
5879 G_PARAM_STATIC_STRINGS |
5880 CLUTTER_PARAM_ANIMATABLE);
5883 * ClutterActor:scale-y:
5885 * The vertical scale of the actor.
5887 * The #ClutterActor:scale-y property is animatable.
5891 obj_props[PROP_SCALE_Y] =
5892 g_param_spec_double ("scale-y",
5894 P_("Scale factor on the Y axis"),
5898 G_PARAM_STATIC_STRINGS |
5899 CLUTTER_PARAM_ANIMATABLE);
5902 * ClutterActor:scale-center-x:
5904 * The horizontal center point for scaling
5908 obj_props[PROP_SCALE_CENTER_X] =
5909 g_param_spec_float ("scale-center-x",
5910 P_("Scale Center X"),
5911 P_("Horizontal scale center"),
5912 -G_MAXFLOAT, G_MAXFLOAT,
5914 CLUTTER_PARAM_READWRITE);
5917 * ClutterActor:scale-center-y:
5919 * The vertical center point for scaling
5923 obj_props[PROP_SCALE_CENTER_Y] =
5924 g_param_spec_float ("scale-center-y",
5925 P_("Scale Center Y"),
5926 P_("Vertical scale center"),
5927 -G_MAXFLOAT, G_MAXFLOAT,
5929 CLUTTER_PARAM_READWRITE);
5932 * ClutterActor:scale-gravity:
5934 * The center point for scaling expressed as a #ClutterGravity
5938 obj_props[PROP_SCALE_GRAVITY] =
5939 g_param_spec_enum ("scale-gravity",
5940 P_("Scale Gravity"),
5941 P_("The center of scaling"),
5942 CLUTTER_TYPE_GRAVITY,
5943 CLUTTER_GRAVITY_NONE,
5944 CLUTTER_PARAM_READWRITE);
5947 * ClutterActor:rotation-angle-x:
5949 * The rotation angle on the X axis.
5951 * The #ClutterActor:rotation-angle-x property is animatable.
5955 obj_props[PROP_ROTATION_ANGLE_X] =
5956 g_param_spec_double ("rotation-angle-x",
5957 P_("Rotation Angle X"),
5958 P_("The rotation angle on the X axis"),
5959 -G_MAXDOUBLE, G_MAXDOUBLE,
5962 G_PARAM_STATIC_STRINGS |
5963 CLUTTER_PARAM_ANIMATABLE);
5966 * ClutterActor:rotation-angle-y:
5968 * The rotation angle on the Y axis
5970 * The #ClutterActor:rotation-angle-y property is animatable.
5974 obj_props[PROP_ROTATION_ANGLE_Y] =
5975 g_param_spec_double ("rotation-angle-y",
5976 P_("Rotation Angle Y"),
5977 P_("The rotation angle on the Y axis"),
5978 -G_MAXDOUBLE, G_MAXDOUBLE,
5981 G_PARAM_STATIC_STRINGS |
5982 CLUTTER_PARAM_ANIMATABLE);
5985 * ClutterActor:rotation-angle-z:
5987 * The rotation angle on the Z axis
5989 * The #ClutterActor:rotation-angle-z property is animatable.
5993 obj_props[PROP_ROTATION_ANGLE_Z] =
5994 g_param_spec_double ("rotation-angle-z",
5995 P_("Rotation Angle Z"),
5996 P_("The rotation angle on the Z axis"),
5997 -G_MAXDOUBLE, G_MAXDOUBLE,
6000 G_PARAM_STATIC_STRINGS |
6001 CLUTTER_PARAM_ANIMATABLE);
6004 * ClutterActor:rotation-center-x:
6006 * The rotation center on the X axis.
6010 obj_props[PROP_ROTATION_CENTER_X] =
6011 g_param_spec_boxed ("rotation-center-x",
6012 P_("Rotation Center X"),
6013 P_("The rotation center on the X axis"),
6014 CLUTTER_TYPE_VERTEX,
6015 CLUTTER_PARAM_READWRITE);
6018 * ClutterActor:rotation-center-y:
6020 * The rotation center on the Y axis.
6024 obj_props[PROP_ROTATION_CENTER_Y] =
6025 g_param_spec_boxed ("rotation-center-y",
6026 P_("Rotation Center Y"),
6027 P_("The rotation center on the Y axis"),
6028 CLUTTER_TYPE_VERTEX,
6029 CLUTTER_PARAM_READWRITE);
6032 * ClutterActor:rotation-center-z:
6034 * The rotation center on the Z axis.
6038 obj_props[PROP_ROTATION_CENTER_Z] =
6039 g_param_spec_boxed ("rotation-center-z",
6040 P_("Rotation Center Z"),
6041 P_("The rotation center on the Z axis"),
6042 CLUTTER_TYPE_VERTEX,
6043 CLUTTER_PARAM_READWRITE);
6046 * ClutterActor:rotation-center-z-gravity:
6048 * The rotation center on the Z axis expressed as a #ClutterGravity.
6052 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6053 g_param_spec_enum ("rotation-center-z-gravity",
6054 P_("Rotation Center Z Gravity"),
6055 P_("Center point for rotation around the Z axis"),
6056 CLUTTER_TYPE_GRAVITY,
6057 CLUTTER_GRAVITY_NONE,
6058 CLUTTER_PARAM_READWRITE);
6061 * ClutterActor:anchor-x:
6063 * The X coordinate of an actor's anchor point, relative to
6064 * the actor coordinate space, in pixels
6068 obj_props[PROP_ANCHOR_X] =
6069 g_param_spec_float ("anchor-x",
6071 P_("X coordinate of the anchor point"),
6072 -G_MAXFLOAT, G_MAXFLOAT,
6074 CLUTTER_PARAM_READWRITE);
6077 * ClutterActor:anchor-y:
6079 * The Y coordinate of an actor's anchor point, relative to
6080 * the actor coordinate space, in pixels
6084 obj_props[PROP_ANCHOR_Y] =
6085 g_param_spec_float ("anchor-y",
6087 P_("Y coordinate of the anchor point"),
6088 -G_MAXFLOAT, G_MAXFLOAT,
6090 CLUTTER_PARAM_READWRITE);
6093 * ClutterActor:anchor-gravity:
6095 * The anchor point expressed as a #ClutterGravity
6099 obj_props[PROP_ANCHOR_GRAVITY] =
6100 g_param_spec_enum ("anchor-gravity",
6101 P_("Anchor Gravity"),
6102 P_("The anchor point as a ClutterGravity"),
6103 CLUTTER_TYPE_GRAVITY,
6104 CLUTTER_GRAVITY_NONE,
6105 CLUTTER_PARAM_READWRITE);
6108 * ClutterActor:show-on-set-parent:
6110 * If %TRUE, the actor is automatically shown when parented.
6112 * Calling clutter_actor_hide() on an actor which has not been
6113 * parented will set this property to %FALSE as a side effect.
6117 obj_props[PROP_SHOW_ON_SET_PARENT] =
6118 g_param_spec_boolean ("show-on-set-parent",
6119 P_("Show on set parent"),
6120 P_("Whether the actor is shown when parented"),
6122 CLUTTER_PARAM_READWRITE);
6125 * ClutterActor:clip-to-allocation:
6127 * Whether the clip region should track the allocated area
6130 * This property is ignored if a clip area has been explicitly
6131 * set using clutter_actor_set_clip().
6135 obj_props[PROP_CLIP_TO_ALLOCATION] =
6136 g_param_spec_boolean ("clip-to-allocation",
6137 P_("Clip to Allocation"),
6138 P_("Sets the clip region to track the actor's allocation"),
6140 CLUTTER_PARAM_READWRITE);
6143 * ClutterActor:text-direction:
6145 * The direction of the text inside a #ClutterActor.
6149 obj_props[PROP_TEXT_DIRECTION] =
6150 g_param_spec_enum ("text-direction",
6151 P_("Text Direction"),
6152 P_("Direction of the text"),
6153 CLUTTER_TYPE_TEXT_DIRECTION,
6154 CLUTTER_TEXT_DIRECTION_LTR,
6155 CLUTTER_PARAM_READWRITE);
6158 * ClutterActor:has-pointer:
6160 * Whether the actor contains the pointer of a #ClutterInputDevice
6165 obj_props[PROP_HAS_POINTER] =
6166 g_param_spec_boolean ("has-pointer",
6168 P_("Whether the actor contains the pointer of an input device"),
6170 CLUTTER_PARAM_READABLE);
6173 * ClutterActor:actions:
6175 * Adds a #ClutterAction to the actor
6179 obj_props[PROP_ACTIONS] =
6180 g_param_spec_object ("actions",
6182 P_("Adds an action to the actor"),
6183 CLUTTER_TYPE_ACTION,
6184 CLUTTER_PARAM_WRITABLE);
6187 * ClutterActor:constraints:
6189 * Adds a #ClutterConstraint to the actor
6193 obj_props[PROP_CONSTRAINTS] =
6194 g_param_spec_object ("constraints",
6196 P_("Adds a constraint to the actor"),
6197 CLUTTER_TYPE_CONSTRAINT,
6198 CLUTTER_PARAM_WRITABLE);
6201 * ClutterActor:effect:
6203 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6207 obj_props[PROP_EFFECT] =
6208 g_param_spec_object ("effect",
6210 P_("Add an effect to be applied on the actor"),
6211 CLUTTER_TYPE_EFFECT,
6212 CLUTTER_PARAM_WRITABLE);
6215 * ClutterActor:layout-manager:
6217 * A delegate object for controlling the layout of the children of
6222 obj_props[PROP_LAYOUT_MANAGER] =
6223 g_param_spec_object ("layout-manager",
6224 P_("Layout Manager"),
6225 P_("The object controlling the layout of an actor's children"),
6226 CLUTTER_TYPE_LAYOUT_MANAGER,
6227 CLUTTER_PARAM_READWRITE);
6231 * ClutterActor:x-align:
6233 * The alignment of an actor on the X axis, if the actor has been given
6234 * extra space for its allocation.
6238 obj_props[PROP_X_ALIGN] =
6239 g_param_spec_enum ("x-align",
6241 P_("The alignment of the actor on the X axis within its allocation"),
6242 CLUTTER_TYPE_ACTOR_ALIGN,
6243 CLUTTER_ACTOR_ALIGN_FILL,
6244 CLUTTER_PARAM_READWRITE);
6247 * ClutterActor:y-align:
6249 * The alignment of an actor on the Y axis, if the actor has been given
6250 * extra space for its allocation.
6254 obj_props[PROP_Y_ALIGN] =
6255 g_param_spec_enum ("y-align",
6257 P_("The alignment of the actor on the Y axis within its allocation"),
6258 CLUTTER_TYPE_ACTOR_ALIGN,
6259 CLUTTER_ACTOR_ALIGN_FILL,
6260 CLUTTER_PARAM_READWRITE);
6263 * ClutterActor:margin-top:
6265 * The margin (in pixels) from the top of the actor.
6267 * This property adds a margin to the actor's preferred size; the margin
6268 * will be automatically taken into account when allocating the actor.
6272 obj_props[PROP_MARGIN_TOP] =
6273 g_param_spec_float ("margin-top",
6275 P_("Extra space at the top"),
6278 CLUTTER_PARAM_READWRITE);
6281 * ClutterActor:margin-bottom:
6283 * The margin (in pixels) from the bottom of the actor.
6285 * This property adds a margin to the actor's preferred size; the margin
6286 * will be automatically taken into account when allocating the actor.
6290 obj_props[PROP_MARGIN_BOTTOM] =
6291 g_param_spec_float ("margin-bottom",
6292 P_("Margin Bottom"),
6293 P_("Extra space at the bottom"),
6296 CLUTTER_PARAM_READWRITE);
6299 * ClutterActor:margin-left:
6301 * The margin (in pixels) from the left of the actor.
6303 * This property adds a margin to the actor's preferred size; the margin
6304 * will be automatically taken into account when allocating the actor.
6308 obj_props[PROP_MARGIN_LEFT] =
6309 g_param_spec_float ("margin-left",
6311 P_("Extra space at the left"),
6314 CLUTTER_PARAM_READWRITE);
6317 * ClutterActor:margin-right:
6319 * The margin (in pixels) from the right of the actor.
6321 * This property adds a margin to the actor's preferred size; the margin
6322 * will be automatically taken into account when allocating the actor.
6326 obj_props[PROP_MARGIN_RIGHT] =
6327 g_param_spec_float ("margin-right",
6329 P_("Extra space at the right"),
6332 CLUTTER_PARAM_READWRITE);
6335 * ClutterActor:background-color-set:
6337 * Whether the #ClutterActor:background-color property has been set.
6341 obj_props[PROP_BACKGROUND_COLOR_SET] =
6342 g_param_spec_boolean ("background-color-set",
6343 P_("Background Color Set"),
6344 P_("Whether the background color is set"),
6346 CLUTTER_PARAM_READABLE);
6349 * ClutterActor:background-color:
6351 * Paints a solid fill of the actor's allocation using the specified
6354 * The #ClutterActor:background-color property is animatable.
6358 obj_props[PROP_BACKGROUND_COLOR] =
6359 clutter_param_spec_color ("background-color",
6360 P_("Background color"),
6361 P_("The actor's background color"),
6362 CLUTTER_COLOR_Transparent,
6364 G_PARAM_STATIC_STRINGS |
6365 CLUTTER_PARAM_ANIMATABLE);
6368 * ClutterActor:first-child:
6370 * The actor's first child.
6374 obj_props[PROP_FIRST_CHILD] =
6375 g_param_spec_object ("first-child",
6377 P_("The actor's first child"),
6379 CLUTTER_PARAM_READABLE);
6382 * ClutterActor:last-child:
6384 * The actor's last child.
6388 obj_props[PROP_LAST_CHILD] =
6389 g_param_spec_object ("last-child",
6391 P_("The actor's last child"),
6393 CLUTTER_PARAM_READABLE);
6396 * ClutterActor:content:
6398 * The #ClutterContent implementation that controls the content
6403 obj_props[PROP_CONTENT] =
6404 g_param_spec_object ("content",
6406 P_("Delegate object for painting the actor's content"),
6407 CLUTTER_TYPE_CONTENT,
6408 CLUTTER_PARAM_READWRITE);
6411 * ClutterActor:content-gravity:
6413 * The alignment that should be honoured by the #ClutterContent
6414 * set with the #ClutterActor:content property.
6416 * Changing the value of this property will change the bounding box of
6417 * the content; you can use the #ClutterActor:content-box property to
6418 * get the position and size of the content within the actor's
6421 * This property is meaningful only for #ClutterContent implementations
6422 * that have a preferred size, and if the preferred size is smaller than
6423 * the actor's allocation.
6427 obj_props[PROP_CONTENT_GRAVITY] =
6428 g_param_spec_enum ("content-gravity",
6429 P_("Content Gravity"),
6430 P_("Alignment of the actor's content"),
6431 CLUTTER_TYPE_CONTENT_GRAVITY,
6432 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6433 CLUTTER_PARAM_READWRITE);
6436 * ClutterActor:content-box:
6438 * The bounding box for the #ClutterContent used by the actor.
6440 * The value of this property is controlled by the #ClutterActor:allocation
6441 * and #ClutterActor:content-gravity properties of #ClutterActor.
6443 * The bounding box for the content is guaranteed to never exceed the
6444 * allocation's of the actor.
6448 obj_props[PROP_CONTENT_BOX] =
6449 g_param_spec_boxed ("content-box",
6451 P_("The bounding box of the actor's content"),
6452 CLUTTER_TYPE_ACTOR_BOX,
6453 CLUTTER_PARAM_READABLE);
6455 obj_props[PROP_MINIFICATION_FILTER] =
6456 g_param_spec_enum ("minification-filter",
6457 P_("Minification Filter"),
6458 P_("The filter used when reducing the size of the content"),
6459 CLUTTER_TYPE_SCALING_FILTER,
6460 CLUTTER_SCALING_FILTER_LINEAR,
6461 CLUTTER_PARAM_READWRITE);
6463 obj_props[PROP_MAGNIFICATION_FILTER] =
6464 g_param_spec_enum ("magnification-filter",
6465 P_("Magnification Filter"),
6466 P_("The filter used when increasing the size of the content"),
6467 CLUTTER_TYPE_SCALING_FILTER,
6468 CLUTTER_SCALING_FILTER_LINEAR,
6469 CLUTTER_PARAM_READWRITE);
6471 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6474 * ClutterActor::destroy:
6475 * @actor: the #ClutterActor which emitted the signal
6477 * The ::destroy signal notifies that all references held on the
6478 * actor which emitted it should be released.
6480 * The ::destroy signal should be used by all holders of a reference
6483 * This signal might result in the finalization of the #ClutterActor
6484 * if all references are released.
6486 * Composite actors and actors implementing the #ClutterContainer
6487 * interface should override the default implementation of the
6488 * class handler of this signal and call clutter_actor_destroy() on
6489 * their children. When overriding the default class handler, it is
6490 * required to chain up to the parent's implementation.
6494 actor_signals[DESTROY] =
6495 g_signal_new (I_("destroy"),
6496 G_TYPE_FROM_CLASS (object_class),
6497 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6498 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6500 _clutter_marshal_VOID__VOID,
6503 * ClutterActor::show:
6504 * @actor: the object which received the signal
6506 * The ::show signal is emitted when an actor is visible and
6507 * rendered on the stage.
6511 actor_signals[SHOW] =
6512 g_signal_new (I_("show"),
6513 G_TYPE_FROM_CLASS (object_class),
6515 G_STRUCT_OFFSET (ClutterActorClass, show),
6517 _clutter_marshal_VOID__VOID,
6520 * ClutterActor::hide:
6521 * @actor: the object which received the signal
6523 * The ::hide signal is emitted when an actor is no longer rendered
6528 actor_signals[HIDE] =
6529 g_signal_new (I_("hide"),
6530 G_TYPE_FROM_CLASS (object_class),
6532 G_STRUCT_OFFSET (ClutterActorClass, hide),
6534 _clutter_marshal_VOID__VOID,
6537 * ClutterActor::parent-set:
6538 * @actor: the object which received the signal
6539 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6541 * This signal is emitted when the parent of the actor changes.
6545 actor_signals[PARENT_SET] =
6546 g_signal_new (I_("parent-set"),
6547 G_TYPE_FROM_CLASS (object_class),
6549 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6551 _clutter_marshal_VOID__OBJECT,
6553 CLUTTER_TYPE_ACTOR);
6556 * ClutterActor::queue-redraw:
6557 * @actor: the actor we're bubbling the redraw request through
6558 * @origin: the actor which initiated the redraw request
6560 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6561 * is called on @origin.
6563 * The default implementation for #ClutterActor chains up to the
6564 * parent actor and queues a redraw on the parent, thus "bubbling"
6565 * the redraw queue up through the actor graph. The default
6566 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6567 * in a main loop idle handler.
6569 * Note that the @origin actor may be the stage, or a container; it
6570 * does not have to be a leaf node in the actor graph.
6572 * Toolkits embedding a #ClutterStage which require a redraw and
6573 * relayout cycle can stop the emission of this signal using the
6574 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6579 * on_redraw_complete (gpointer data)
6581 * ClutterStage *stage = data;
6583 * /* execute the Clutter drawing pipeline */
6584 * clutter_stage_ensure_redraw (stage);
6588 * on_stage_queue_redraw (ClutterStage *stage)
6590 * /* this prevents the default handler to run */
6591 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6593 * /* queue a redraw with the host toolkit and call
6594 * * a function when the redraw has been completed
6596 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6600 * <note><para>This signal is emitted before the Clutter paint
6601 * pipeline is executed. If you want to know when the pipeline has
6602 * been completed you should connect to the ::paint signal on the
6603 * Stage with g_signal_connect_after().</para></note>
6607 actor_signals[QUEUE_REDRAW] =
6608 g_signal_new (I_("queue-redraw"),
6609 G_TYPE_FROM_CLASS (object_class),
6612 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6614 _clutter_marshal_VOID__OBJECT,
6616 CLUTTER_TYPE_ACTOR);
6619 * ClutterActor::queue-relayout
6620 * @actor: the actor being queued for relayout
6622 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6623 * is called on an actor.
6625 * The default implementation for #ClutterActor chains up to the
6626 * parent actor and queues a relayout on the parent, thus "bubbling"
6627 * the relayout queue up through the actor graph.
6629 * The main purpose of this signal is to allow relayout to be propagated
6630 * properly in the procense of #ClutterClone actors. Applications will
6631 * not normally need to connect to this signal.
6635 actor_signals[QUEUE_RELAYOUT] =
6636 g_signal_new (I_("queue-relayout"),
6637 G_TYPE_FROM_CLASS (object_class),
6640 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6642 _clutter_marshal_VOID__VOID,
6646 * ClutterActor::event:
6647 * @actor: the actor which received the event
6648 * @event: a #ClutterEvent
6650 * The ::event signal is emitted each time an event is received
6651 * by the @actor. This signal will be emitted on every actor,
6652 * following the hierarchy chain, until it reaches the top-level
6653 * container (the #ClutterStage).
6655 * Return value: %TRUE if the event has been handled by the actor,
6656 * or %FALSE to continue the emission.
6660 actor_signals[EVENT] =
6661 g_signal_new (I_("event"),
6662 G_TYPE_FROM_CLASS (object_class),
6664 G_STRUCT_OFFSET (ClutterActorClass, event),
6665 _clutter_boolean_handled_accumulator, NULL,
6666 _clutter_marshal_BOOLEAN__BOXED,
6668 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6670 * ClutterActor::button-press-event:
6671 * @actor: the actor which received the event
6672 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6674 * The ::button-press-event signal is emitted each time a mouse button
6675 * is pressed on @actor.
6677 * Return value: %TRUE if the event has been handled by the actor,
6678 * or %FALSE to continue the emission.
6682 actor_signals[BUTTON_PRESS_EVENT] =
6683 g_signal_new (I_("button-press-event"),
6684 G_TYPE_FROM_CLASS (object_class),
6686 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6687 _clutter_boolean_handled_accumulator, NULL,
6688 _clutter_marshal_BOOLEAN__BOXED,
6690 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6692 * ClutterActor::button-release-event:
6693 * @actor: the actor which received the event
6694 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6696 * The ::button-release-event signal is emitted each time a mouse button
6697 * is released on @actor.
6699 * Return value: %TRUE if the event has been handled by the actor,
6700 * or %FALSE to continue the emission.
6704 actor_signals[BUTTON_RELEASE_EVENT] =
6705 g_signal_new (I_("button-release-event"),
6706 G_TYPE_FROM_CLASS (object_class),
6708 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6709 _clutter_boolean_handled_accumulator, NULL,
6710 _clutter_marshal_BOOLEAN__BOXED,
6712 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6714 * ClutterActor::scroll-event:
6715 * @actor: the actor which received the event
6716 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6718 * The ::scroll-event signal is emitted each time the mouse is
6719 * scrolled on @actor
6721 * Return value: %TRUE if the event has been handled by the actor,
6722 * or %FALSE to continue the emission.
6726 actor_signals[SCROLL_EVENT] =
6727 g_signal_new (I_("scroll-event"),
6728 G_TYPE_FROM_CLASS (object_class),
6730 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6731 _clutter_boolean_handled_accumulator, NULL,
6732 _clutter_marshal_BOOLEAN__BOXED,
6734 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6736 * ClutterActor::key-press-event:
6737 * @actor: the actor which received the event
6738 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6740 * The ::key-press-event signal is emitted each time a keyboard button
6741 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6743 * Return value: %TRUE if the event has been handled by the actor,
6744 * or %FALSE to continue the emission.
6748 actor_signals[KEY_PRESS_EVENT] =
6749 g_signal_new (I_("key-press-event"),
6750 G_TYPE_FROM_CLASS (object_class),
6752 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6753 _clutter_boolean_handled_accumulator, NULL,
6754 _clutter_marshal_BOOLEAN__BOXED,
6756 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6758 * ClutterActor::key-release-event:
6759 * @actor: the actor which received the event
6760 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6762 * The ::key-release-event signal is emitted each time a keyboard button
6763 * is released while @actor has key focus (see
6764 * clutter_stage_set_key_focus()).
6766 * Return value: %TRUE if the event has been handled by the actor,
6767 * or %FALSE to continue the emission.
6771 actor_signals[KEY_RELEASE_EVENT] =
6772 g_signal_new (I_("key-release-event"),
6773 G_TYPE_FROM_CLASS (object_class),
6775 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6776 _clutter_boolean_handled_accumulator, NULL,
6777 _clutter_marshal_BOOLEAN__BOXED,
6779 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6781 * ClutterActor::motion-event:
6782 * @actor: the actor which received the event
6783 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6785 * The ::motion-event signal is emitted each time the mouse pointer is
6786 * moved over @actor.
6788 * Return value: %TRUE if the event has been handled by the actor,
6789 * or %FALSE to continue the emission.
6793 actor_signals[MOTION_EVENT] =
6794 g_signal_new (I_("motion-event"),
6795 G_TYPE_FROM_CLASS (object_class),
6797 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6798 _clutter_boolean_handled_accumulator, NULL,
6799 _clutter_marshal_BOOLEAN__BOXED,
6801 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6804 * ClutterActor::key-focus-in:
6805 * @actor: the actor which now has key focus
6807 * The ::key-focus-in signal is emitted when @actor receives key focus.
6811 actor_signals[KEY_FOCUS_IN] =
6812 g_signal_new (I_("key-focus-in"),
6813 G_TYPE_FROM_CLASS (object_class),
6815 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6817 _clutter_marshal_VOID__VOID,
6821 * ClutterActor::key-focus-out:
6822 * @actor: the actor which now has key focus
6824 * The ::key-focus-out signal is emitted when @actor loses key focus.
6828 actor_signals[KEY_FOCUS_OUT] =
6829 g_signal_new (I_("key-focus-out"),
6830 G_TYPE_FROM_CLASS (object_class),
6832 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6834 _clutter_marshal_VOID__VOID,
6838 * ClutterActor::enter-event:
6839 * @actor: the actor which the pointer has entered.
6840 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6842 * The ::enter-event signal is emitted when the pointer enters the @actor
6844 * Return value: %TRUE if the event has been handled by the actor,
6845 * or %FALSE to continue the emission.
6849 actor_signals[ENTER_EVENT] =
6850 g_signal_new (I_("enter-event"),
6851 G_TYPE_FROM_CLASS (object_class),
6853 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6854 _clutter_boolean_handled_accumulator, NULL,
6855 _clutter_marshal_BOOLEAN__BOXED,
6857 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6860 * ClutterActor::leave-event:
6861 * @actor: the actor which the pointer has left
6862 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6864 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6866 * Return value: %TRUE if the event has been handled by the actor,
6867 * or %FALSE to continue the emission.
6871 actor_signals[LEAVE_EVENT] =
6872 g_signal_new (I_("leave-event"),
6873 G_TYPE_FROM_CLASS (object_class),
6875 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6876 _clutter_boolean_handled_accumulator, NULL,
6877 _clutter_marshal_BOOLEAN__BOXED,
6879 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6882 * ClutterActor::captured-event:
6883 * @actor: the actor which received the signal
6884 * @event: a #ClutterEvent
6886 * The ::captured-event signal is emitted when an event is captured
6887 * by Clutter. This signal will be emitted starting from the top-level
6888 * container (the #ClutterStage) to the actor which received the event
6889 * going down the hierarchy. This signal can be used to intercept every
6890 * event before the specialized events (like
6891 * ClutterActor::button-press-event or ::key-released-event) are
6894 * Return value: %TRUE if the event has been handled by the actor,
6895 * or %FALSE to continue the emission.
6899 actor_signals[CAPTURED_EVENT] =
6900 g_signal_new (I_("captured-event"),
6901 G_TYPE_FROM_CLASS (object_class),
6903 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6904 _clutter_boolean_handled_accumulator, NULL,
6905 _clutter_marshal_BOOLEAN__BOXED,
6907 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6910 * ClutterActor::paint:
6911 * @actor: the #ClutterActor that received the signal
6913 * The ::paint signal is emitted each time an actor is being painted.
6915 * Subclasses of #ClutterActor should override the class signal handler
6916 * and paint themselves in that function.
6918 * It is possible to connect a handler to the ::paint signal in order
6919 * to set up some custom aspect of a paint.
6923 actor_signals[PAINT] =
6924 g_signal_new (I_("paint"),
6925 G_TYPE_FROM_CLASS (object_class),
6928 G_STRUCT_OFFSET (ClutterActorClass, paint),
6930 _clutter_marshal_VOID__VOID,
6933 * ClutterActor::realize:
6934 * @actor: the #ClutterActor that received the signal
6936 * The ::realize signal is emitted each time an actor is being
6941 actor_signals[REALIZE] =
6942 g_signal_new (I_("realize"),
6943 G_TYPE_FROM_CLASS (object_class),
6945 G_STRUCT_OFFSET (ClutterActorClass, realize),
6947 _clutter_marshal_VOID__VOID,
6950 * ClutterActor::unrealize:
6951 * @actor: the #ClutterActor that received the signal
6953 * The ::unrealize signal is emitted each time an actor is being
6958 actor_signals[UNREALIZE] =
6959 g_signal_new (I_("unrealize"),
6960 G_TYPE_FROM_CLASS (object_class),
6962 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6964 _clutter_marshal_VOID__VOID,
6968 * ClutterActor::pick:
6969 * @actor: the #ClutterActor that received the signal
6970 * @color: the #ClutterColor to be used when picking
6972 * The ::pick signal is emitted each time an actor is being painted
6973 * in "pick mode". The pick mode is used to identify the actor during
6974 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6975 * The actor should paint its shape using the passed @pick_color.
6977 * Subclasses of #ClutterActor should override the class signal handler
6978 * and paint themselves in that function.
6980 * It is possible to connect a handler to the ::pick signal in order
6981 * to set up some custom aspect of a paint in pick mode.
6985 actor_signals[PICK] =
6986 g_signal_new (I_("pick"),
6987 G_TYPE_FROM_CLASS (object_class),
6989 G_STRUCT_OFFSET (ClutterActorClass, pick),
6991 _clutter_marshal_VOID__BOXED,
6993 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6996 * ClutterActor::allocation-changed:
6997 * @actor: the #ClutterActor that emitted the signal
6998 * @box: a #ClutterActorBox with the new allocation
6999 * @flags: #ClutterAllocationFlags for the allocation
7001 * The ::allocation-changed signal is emitted when the
7002 * #ClutterActor:allocation property changes. Usually, application
7003 * code should just use the notifications for the :allocation property
7004 * but if you want to track the allocation flags as well, for instance
7005 * to know whether the absolute origin of @actor changed, then you might
7006 * want use this signal instead.
7010 actor_signals[ALLOCATION_CHANGED] =
7011 g_signal_new (I_("allocation-changed"),
7012 G_TYPE_FROM_CLASS (object_class),
7016 _clutter_marshal_VOID__BOXED_FLAGS,
7018 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7019 CLUTTER_TYPE_ALLOCATION_FLAGS);
7022 * ClutterActor::transitions-completed:
7023 * @actor: a #ClutterActor
7025 * The ::transitions-completed signal is emitted once all transitions
7026 * involving @actor are complete.
7030 actor_signals[TRANSITIONS_COMPLETED] =
7031 g_signal_new (I_("transitions-completed"),
7032 G_TYPE_FROM_CLASS (object_class),
7036 _clutter_marshal_VOID__VOID,
7041 clutter_actor_init (ClutterActor *self)
7043 ClutterActorPrivate *priv;
7045 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7047 priv->id = _clutter_context_acquire_id (self);
7050 priv->opacity = 0xff;
7051 priv->show_on_set_parent = TRUE;
7053 priv->needs_width_request = TRUE;
7054 priv->needs_height_request = TRUE;
7055 priv->needs_allocation = TRUE;
7057 priv->cached_width_age = 1;
7058 priv->cached_height_age = 1;
7060 priv->opacity_override = -1;
7061 priv->enable_model_view_transform = TRUE;
7063 /* Initialize an empty paint volume to start with */
7064 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7065 priv->last_paint_volume_valid = TRUE;
7067 priv->transform_valid = FALSE;
7069 /* the default is to stretch the content, to match the
7070 * current behaviour of basically all actors. also, it's
7071 * the easiest thing to compute.
7073 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7074 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7075 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7079 * clutter_actor_new:
7081 * Creates a new #ClutterActor.
7083 * A newly created actor has a floating reference, which will be sunk
7084 * when it is added to another actor.
7086 * Return value: (transfer full): the newly created #ClutterActor
7091 clutter_actor_new (void)
7093 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7097 * clutter_actor_destroy:
7098 * @self: a #ClutterActor
7100 * Destroys an actor. When an actor is destroyed, it will break any
7101 * references it holds to other objects. If the actor is inside a
7102 * container, the actor will be removed.
7104 * When you destroy a container, its children will be destroyed as well.
7106 * Note: you cannot destroy the #ClutterStage returned by
7107 * clutter_stage_get_default().
7110 clutter_actor_destroy (ClutterActor *self)
7112 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7114 g_object_ref (self);
7116 /* avoid recursion while destroying */
7117 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7119 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7121 g_object_run_dispose (G_OBJECT (self));
7123 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7126 g_object_unref (self);
7130 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7131 ClutterPaintVolume *clip)
7133 ClutterActorPrivate *priv = self->priv;
7134 ClutterPaintVolume *pv;
7137 /* Remove queue entry early in the process, otherwise a new
7138 queue_redraw() during signal handling could put back this
7139 object in the stage redraw list (but the entry is freed as
7140 soon as we return from this function, causing a segfault
7143 priv->queue_redraw_entry = NULL;
7145 /* If we've been explicitly passed a clip volume then there's
7146 * nothing more to calculate, but otherwise the only thing we know
7147 * is that the change is constrained to the given actor.
7149 * The idea is that if we know the paint volume for where the actor
7150 * was last drawn (in eye coordinates) and we also have the paint
7151 * volume for where it will be drawn next (in actor coordinates)
7152 * then if we queue a redraw for both these volumes that will cover
7153 * everything that needs to be redrawn to clear the old view and
7154 * show the latest view of the actor.
7156 * Don't clip this redraw if we don't know what position we had for
7157 * the previous redraw since we don't know where to set the clip so
7158 * it will clear the actor as it is currently.
7162 _clutter_actor_set_queue_redraw_clip (self, clip);
7165 else if (G_LIKELY (priv->last_paint_volume_valid))
7167 pv = _clutter_actor_get_paint_volume_mutable (self);
7170 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7172 /* make sure we redraw the actors old position... */
7173 _clutter_actor_set_queue_redraw_clip (stage,
7174 &priv->last_paint_volume);
7175 _clutter_actor_signal_queue_redraw (stage, stage);
7176 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7178 /* XXX: Ideally the redraw signal would take a clip volume
7179 * argument, but that would be an ABI break. Until we can
7180 * break the ABI we pass the argument out-of-band
7183 /* setup the clip for the actors new position... */
7184 _clutter_actor_set_queue_redraw_clip (self, pv);
7193 _clutter_actor_signal_queue_redraw (self, self);
7195 /* Just in case anyone is manually firing redraw signals without
7196 * using the public queue_redraw() API we are careful to ensure that
7197 * our out-of-band clip member is cleared before returning...
7199 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7201 if (G_LIKELY (clipped))
7202 _clutter_actor_set_queue_redraw_clip (self, NULL);
7206 _clutter_actor_get_allocation_clip (ClutterActor *self,
7207 ClutterActorBox *clip)
7209 ClutterActorBox allocation;
7211 /* XXX: we don't care if we get an out of date allocation here
7212 * because clutter_actor_queue_redraw_with_clip knows to ignore
7213 * the clip if the actor's allocation is invalid.
7215 * This is noted because clutter_actor_get_allocation_box does some
7216 * unnecessary work to support buggy code with a comment suggesting
7217 * that it could be changed later which would be good for this use
7220 clutter_actor_get_allocation_box (self, &allocation);
7222 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7223 * actor's own coordinate space but the allocation is in parent
7227 clip->x2 = allocation.x2 - allocation.x1;
7228 clip->y2 = allocation.y2 - allocation.y1;
7232 _clutter_actor_queue_redraw_full (ClutterActor *self,
7233 ClutterRedrawFlags flags,
7234 ClutterPaintVolume *volume,
7235 ClutterEffect *effect)
7237 ClutterActorPrivate *priv = self->priv;
7238 ClutterPaintVolume allocation_pv;
7239 ClutterPaintVolume *pv;
7240 gboolean should_free_pv;
7241 ClutterActor *stage;
7243 /* Here's an outline of the actor queue redraw mechanism:
7245 * The process starts in one of the following two functions which
7246 * are wrappers for this function:
7247 * clutter_actor_queue_redraw
7248 * _clutter_actor_queue_redraw_with_clip
7250 * additionally, an effect can queue a redraw by wrapping this
7251 * function in clutter_effect_queue_rerun
7253 * This functions queues an entry in a list associated with the
7254 * stage which is a list of actors that queued a redraw while
7255 * updating the timelines, performing layouting and processing other
7256 * mainloop sources before the next paint starts.
7258 * We aim to minimize the processing done at this point because
7259 * there is a good chance other events will happen while updating
7260 * the scenegraph that would invalidate any expensive work we might
7261 * otherwise try to do here. For example we don't try and resolve
7262 * the screen space bounding box of an actor at this stage so as to
7263 * minimize how much of the screen redraw because it's possible
7264 * something else will happen which will force a full redraw anyway.
7266 * When all updates are complete and we come to paint the stage then
7267 * we iterate this list and actually emit the "queue-redraw" signals
7268 * for each of the listed actors which will bubble up to the stage
7269 * for each actor and at that point we will transform the actors
7270 * paint volume into screen coordinates to determine the clip region
7271 * for what needs to be redrawn in the next paint.
7273 * Besides minimizing redundant work another reason for this
7274 * deferred design is that it's more likely we will be able to
7275 * determine the paint volume of an actor once we've finished
7276 * updating the scenegraph because its allocation should be up to
7277 * date. NB: If we can't determine an actors paint volume then we
7278 * can't automatically queue a clipped redraw which can make a big
7279 * difference to performance.
7281 * So the control flow goes like this:
7282 * One of clutter_actor_queue_redraw,
7283 * _clutter_actor_queue_redraw_with_clip
7284 * or clutter_effect_queue_rerun
7286 * then control moves to:
7287 * _clutter_stage_queue_actor_redraw
7289 * later during _clutter_stage_do_update, once relayouting is done
7290 * and the scenegraph has been updated we will call:
7291 * _clutter_stage_finish_queue_redraws
7293 * _clutter_stage_finish_queue_redraws will call
7294 * _clutter_actor_finish_queue_redraw for each listed actor.
7295 * Note: actors *are* allowed to queue further redraws during this
7296 * process (considering clone actors or texture_new_from_actor which
7297 * respond to their source queueing a redraw by queuing a redraw
7298 * themselves). We repeat the process until the list is empty.
7300 * This will result in the "queue-redraw" signal being fired for
7301 * each actor which will pass control to the default signal handler:
7302 * clutter_actor_real_queue_redraw
7304 * This will bubble up to the stages handler:
7305 * clutter_stage_real_queue_redraw
7307 * clutter_stage_real_queue_redraw will transform the actors paint
7308 * volume into screen space and add it as a clip region for the next
7312 /* ignore queueing a redraw for actors being destroyed */
7313 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7316 stage = _clutter_actor_get_stage_internal (self);
7318 /* Ignore queueing a redraw for actors not descended from a stage */
7322 /* ignore queueing a redraw on stages that are being destroyed */
7323 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7326 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7328 ClutterActorBox allocation_clip;
7329 ClutterVertex origin;
7331 /* If the actor doesn't have a valid allocation then we will
7332 * queue a full stage redraw. */
7333 if (priv->needs_allocation)
7335 /* NB: NULL denotes an undefined clip which will result in a
7337 _clutter_actor_set_queue_redraw_clip (self, NULL);
7338 _clutter_actor_signal_queue_redraw (self, self);
7342 _clutter_paint_volume_init_static (&allocation_pv, self);
7343 pv = &allocation_pv;
7345 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7347 origin.x = allocation_clip.x1;
7348 origin.y = allocation_clip.y1;
7350 clutter_paint_volume_set_origin (pv, &origin);
7351 clutter_paint_volume_set_width (pv,
7352 allocation_clip.x2 - allocation_clip.x1);
7353 clutter_paint_volume_set_height (pv,
7354 allocation_clip.y2 -
7355 allocation_clip.y1);
7356 should_free_pv = TRUE;
7361 should_free_pv = FALSE;
7364 self->priv->queue_redraw_entry =
7365 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7366 priv->queue_redraw_entry,
7371 clutter_paint_volume_free (pv);
7373 /* If this is the first redraw queued then we can directly use the
7375 if (!priv->is_dirty)
7376 priv->effect_to_redraw = effect;
7377 /* Otherwise we need to merge it with the existing effect parameter */
7378 else if (effect != NULL)
7380 /* If there's already an effect then we need to use whichever is
7381 later in the chain of actors. Otherwise a full redraw has
7382 already been queued on the actor so we need to ignore the
7384 if (priv->effect_to_redraw != NULL)
7386 if (priv->effects == NULL)
7387 g_warning ("Redraw queued with an effect that is "
7388 "not applied to the actor");
7393 for (l = _clutter_meta_group_peek_metas (priv->effects);
7397 if (l->data == priv->effect_to_redraw ||
7399 priv->effect_to_redraw = l->data;
7406 /* If no effect is specified then we need to redraw the whole
7408 priv->effect_to_redraw = NULL;
7411 priv->is_dirty = TRUE;
7415 * clutter_actor_queue_redraw:
7416 * @self: A #ClutterActor
7418 * Queues up a redraw of an actor and any children. The redraw occurs
7419 * once the main loop becomes idle (after the current batch of events
7420 * has been processed, roughly).
7422 * Applications rarely need to call this, as redraws are handled
7423 * automatically by modification functions.
7425 * This function will not do anything if @self is not visible, or
7426 * if the actor is inside an invisible part of the scenegraph.
7428 * Also be aware that painting is a NOP for actors with an opacity of
7431 * When you are implementing a custom actor you must queue a redraw
7432 * whenever some private state changes that will affect painting or
7433 * picking of your actor.
7436 clutter_actor_queue_redraw (ClutterActor *self)
7438 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7440 _clutter_actor_queue_redraw_full (self,
7442 NULL, /* clip volume */
7447 * _clutter_actor_queue_redraw_with_clip:
7448 * @self: A #ClutterActor
7449 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7450 * this queue redraw.
7451 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7452 * redrawn or %NULL if you are just using a @flag to state your
7455 * Queues up a clipped redraw of an actor and any children. The redraw
7456 * occurs once the main loop becomes idle (after the current batch of
7457 * events has been processed, roughly).
7459 * If no flags are given the clip volume is defined by @volume
7460 * specified in actor coordinates and tells Clutter that only content
7461 * within this volume has been changed so Clutter can optionally
7462 * optimize the redraw.
7464 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7465 * should be %NULL and this tells Clutter to use the actor's current
7466 * allocation as a clip box. This flag can only be used for 2D actors,
7467 * because any actor with depth may be projected outside its
7470 * Applications rarely need to call this, as redraws are handled
7471 * automatically by modification functions.
7473 * This function will not do anything if @self is not visible, or if
7474 * the actor is inside an invisible part of the scenegraph.
7476 * Also be aware that painting is a NOP for actors with an opacity of
7479 * When you are implementing a custom actor you must queue a redraw
7480 * whenever some private state changes that will affect painting or
7481 * picking of your actor.
7484 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7485 ClutterRedrawFlags flags,
7486 ClutterPaintVolume *volume)
7488 _clutter_actor_queue_redraw_full (self,
7490 volume, /* clip volume */
7495 _clutter_actor_queue_only_relayout (ClutterActor *self)
7497 ClutterActorPrivate *priv = self->priv;
7499 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7502 if (priv->needs_width_request &&
7503 priv->needs_height_request &&
7504 priv->needs_allocation)
7505 return; /* save some cpu cycles */
7507 #if CLUTTER_ENABLE_DEBUG
7508 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7510 g_warning ("The actor '%s' is currently inside an allocation "
7511 "cycle; calling clutter_actor_queue_relayout() is "
7513 _clutter_actor_get_debug_name (self));
7515 #endif /* CLUTTER_ENABLE_DEBUG */
7517 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7521 * clutter_actor_queue_redraw_with_clip:
7522 * @self: a #ClutterActor
7523 * @clip: (allow-none): a rectangular clip region, or %NULL
7525 * Queues a redraw on @self limited to a specific, actor-relative
7528 * If @clip is %NULL this function is equivalent to
7529 * clutter_actor_queue_redraw().
7534 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7535 const cairo_rectangle_int_t *clip)
7537 ClutterPaintVolume volume;
7538 ClutterVertex origin;
7540 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7544 clutter_actor_queue_redraw (self);
7548 _clutter_paint_volume_init_static (&volume, self);
7554 clutter_paint_volume_set_origin (&volume, &origin);
7555 clutter_paint_volume_set_width (&volume, clip->width);
7556 clutter_paint_volume_set_height (&volume, clip->height);
7558 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7560 clutter_paint_volume_free (&volume);
7564 * clutter_actor_queue_relayout:
7565 * @self: A #ClutterActor
7567 * Indicates that the actor's size request or other layout-affecting
7568 * properties may have changed. This function is used inside #ClutterActor
7569 * subclass implementations, not by applications directly.
7571 * Queueing a new layout automatically queues a redraw as well.
7576 clutter_actor_queue_relayout (ClutterActor *self)
7578 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7580 _clutter_actor_queue_only_relayout (self);
7581 clutter_actor_queue_redraw (self);
7585 * clutter_actor_get_preferred_size:
7586 * @self: a #ClutterActor
7587 * @min_width_p: (out) (allow-none): return location for the minimum
7589 * @min_height_p: (out) (allow-none): return location for the minimum
7591 * @natural_width_p: (out) (allow-none): return location for the natural
7593 * @natural_height_p: (out) (allow-none): return location for the natural
7596 * Computes the preferred minimum and natural size of an actor, taking into
7597 * account the actor's geometry management (either height-for-width
7598 * or width-for-height).
7600 * The width and height used to compute the preferred height and preferred
7601 * width are the actor's natural ones.
7603 * If you need to control the height for the preferred width, or the width for
7604 * the preferred height, you should use clutter_actor_get_preferred_width()
7605 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7606 * geometry management using the #ClutterActor:request-mode property.
7611 clutter_actor_get_preferred_size (ClutterActor *self,
7612 gfloat *min_width_p,
7613 gfloat *min_height_p,
7614 gfloat *natural_width_p,
7615 gfloat *natural_height_p)
7617 ClutterActorPrivate *priv;
7618 gfloat min_width, min_height;
7619 gfloat natural_width, natural_height;
7621 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7625 min_width = min_height = 0;
7626 natural_width = natural_height = 0;
7628 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7630 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7631 clutter_actor_get_preferred_width (self, -1,
7634 clutter_actor_get_preferred_height (self, natural_width,
7640 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7641 clutter_actor_get_preferred_height (self, -1,
7644 clutter_actor_get_preferred_width (self, natural_height,
7650 *min_width_p = min_width;
7653 *min_height_p = min_height;
7655 if (natural_width_p)
7656 *natural_width_p = natural_width;
7658 if (natural_height_p)
7659 *natural_height_p = natural_height;
7664 * @align: a #ClutterActorAlign
7665 * @direction: a #ClutterTextDirection
7667 * Retrieves the correct alignment depending on the text direction
7669 * Return value: the effective alignment
7671 static ClutterActorAlign
7672 effective_align (ClutterActorAlign align,
7673 ClutterTextDirection direction)
7675 ClutterActorAlign res;
7679 case CLUTTER_ACTOR_ALIGN_START:
7680 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7681 ? CLUTTER_ACTOR_ALIGN_END
7682 : CLUTTER_ACTOR_ALIGN_START;
7685 case CLUTTER_ACTOR_ALIGN_END:
7686 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7687 ? CLUTTER_ACTOR_ALIGN_START
7688 : CLUTTER_ACTOR_ALIGN_END;
7700 adjust_for_margin (float margin_start,
7702 float *minimum_size,
7703 float *natural_size,
7704 float *allocated_start,
7705 float *allocated_end)
7707 *minimum_size -= (margin_start + margin_end);
7708 *natural_size -= (margin_start + margin_end);
7709 *allocated_start += margin_start;
7710 *allocated_end -= margin_end;
7714 adjust_for_alignment (ClutterActorAlign alignment,
7716 float *allocated_start,
7717 float *allocated_end)
7719 float allocated_size = *allocated_end - *allocated_start;
7723 case CLUTTER_ACTOR_ALIGN_FILL:
7727 case CLUTTER_ACTOR_ALIGN_START:
7729 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7732 case CLUTTER_ACTOR_ALIGN_END:
7733 if (allocated_size > natural_size)
7735 *allocated_start += (allocated_size - natural_size);
7736 *allocated_end = *allocated_start + natural_size;
7740 case CLUTTER_ACTOR_ALIGN_CENTER:
7741 if (allocated_size > natural_size)
7743 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7744 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7751 * clutter_actor_adjust_width:
7752 * @self: a #ClutterActor
7753 * @minimum_width: (inout): the actor's preferred minimum width, which
7754 * will be adjusted depending on the margin
7755 * @natural_width: (inout): the actor's preferred natural width, which
7756 * will be adjusted depending on the margin
7757 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7758 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7760 * Adjusts the preferred and allocated position and size of an actor,
7761 * depending on the margin and alignment properties.
7764 clutter_actor_adjust_width (ClutterActor *self,
7765 gfloat *minimum_width,
7766 gfloat *natural_width,
7767 gfloat *adjusted_x1,
7768 gfloat *adjusted_x2)
7770 ClutterTextDirection text_dir;
7771 const ClutterLayoutInfo *info;
7773 info = _clutter_actor_get_layout_info_or_defaults (self);
7774 text_dir = clutter_actor_get_text_direction (self);
7776 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7778 /* this will tweak natural_width to remove the margin, so that
7779 * adjust_for_alignment() will use the correct size
7781 adjust_for_margin (info->margin.left, info->margin.right,
7782 minimum_width, natural_width,
7783 adjusted_x1, adjusted_x2);
7785 adjust_for_alignment (effective_align (info->x_align, text_dir),
7787 adjusted_x1, adjusted_x2);
7791 * clutter_actor_adjust_height:
7792 * @self: a #ClutterActor
7793 * @minimum_height: (inout): the actor's preferred minimum height, which
7794 * will be adjusted depending on the margin
7795 * @natural_height: (inout): the actor's preferred natural height, which
7796 * will be adjusted depending on the margin
7797 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7798 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7800 * Adjusts the preferred and allocated position and size of an actor,
7801 * depending on the margin and alignment properties.
7804 clutter_actor_adjust_height (ClutterActor *self,
7805 gfloat *minimum_height,
7806 gfloat *natural_height,
7807 gfloat *adjusted_y1,
7808 gfloat *adjusted_y2)
7810 const ClutterLayoutInfo *info;
7812 info = _clutter_actor_get_layout_info_or_defaults (self);
7814 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7816 /* this will tweak natural_height to remove the margin, so that
7817 * adjust_for_alignment() will use the correct size
7819 adjust_for_margin (info->margin.top, info->margin.bottom,
7820 minimum_height, natural_height,
7824 /* we don't use effective_align() here, because text direction
7825 * only affects the horizontal axis
7827 adjust_for_alignment (info->y_align,
7834 /* looks for a cached size request for this for_size. If not
7835 * found, returns the oldest entry so it can be overwritten */
7837 _clutter_actor_get_cached_size_request (gfloat for_size,
7838 SizeRequest *cached_size_requests,
7839 SizeRequest **result)
7843 *result = &cached_size_requests[0];
7845 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7849 sr = &cached_size_requests[i];
7852 sr->for_size == for_size)
7854 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7858 else if (sr->age < (*result)->age)
7864 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7870 * clutter_actor_get_preferred_width:
7871 * @self: A #ClutterActor
7872 * @for_height: available height when computing the preferred width,
7873 * or a negative value to indicate that no height is defined
7874 * @min_width_p: (out) (allow-none): return location for minimum width,
7876 * @natural_width_p: (out) (allow-none): return location for the natural
7879 * Computes the requested minimum and natural widths for an actor,
7880 * optionally depending on the specified height, or if they are
7881 * already computed, returns the cached values.
7883 * An actor may not get its request - depending on the layout
7884 * manager that's in effect.
7886 * A request should not incorporate the actor's scale or anchor point;
7887 * those transformations do not affect layout, only rendering.
7892 clutter_actor_get_preferred_width (ClutterActor *self,
7894 gfloat *min_width_p,
7895 gfloat *natural_width_p)
7897 float request_min_width, request_natural_width;
7898 SizeRequest *cached_size_request;
7899 const ClutterLayoutInfo *info;
7900 ClutterActorPrivate *priv;
7901 gboolean found_in_cache;
7903 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7907 info = _clutter_actor_get_layout_info_or_defaults (self);
7909 /* we shortcircuit the case of a fixed size set using set_width() */
7910 if (priv->min_width_set && priv->natural_width_set)
7912 if (min_width_p != NULL)
7913 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7915 if (natural_width_p != NULL)
7916 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7921 /* the remaining cases are:
7923 * - either min_width or natural_width have been set
7924 * - neither min_width or natural_width have been set
7926 * in both cases, we go through the cache (and through the actor in case
7927 * of cache misses) and determine the authoritative value depending on
7931 if (!priv->needs_width_request)
7934 _clutter_actor_get_cached_size_request (for_height,
7935 priv->width_requests,
7936 &cached_size_request);
7940 /* if the actor needs a width request we use the first slot */
7941 found_in_cache = FALSE;
7942 cached_size_request = &priv->width_requests[0];
7945 if (!found_in_cache)
7947 gfloat minimum_width, natural_width;
7948 ClutterActorClass *klass;
7950 minimum_width = natural_width = 0;
7952 /* adjust for the margin */
7953 if (for_height >= 0)
7955 for_height -= (info->margin.top + info->margin.bottom);
7960 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7962 klass = CLUTTER_ACTOR_GET_CLASS (self);
7963 klass->get_preferred_width (self, for_height,
7967 /* adjust for the margin */
7968 minimum_width += (info->margin.left + info->margin.right);
7969 natural_width += (info->margin.left + info->margin.right);
7971 /* Due to accumulated float errors, it's better not to warn
7972 * on this, but just fix it.
7974 if (natural_width < minimum_width)
7975 natural_width = minimum_width;
7977 cached_size_request->min_size = minimum_width;
7978 cached_size_request->natural_size = natural_width;
7979 cached_size_request->for_size = for_height;
7980 cached_size_request->age = priv->cached_width_age;
7982 priv->cached_width_age += 1;
7983 priv->needs_width_request = FALSE;
7986 if (!priv->min_width_set)
7987 request_min_width = cached_size_request->min_size;
7989 request_min_width = info->min_width;
7991 if (!priv->natural_width_set)
7992 request_natural_width = cached_size_request->natural_size;
7994 request_natural_width = info->natural_width;
7997 *min_width_p = request_min_width;
7999 if (natural_width_p)
8000 *natural_width_p = request_natural_width;
8004 * clutter_actor_get_preferred_height:
8005 * @self: A #ClutterActor
8006 * @for_width: available width to assume in computing desired height,
8007 * or a negative value to indicate that no width is defined
8008 * @min_height_p: (out) (allow-none): return location for minimum height,
8010 * @natural_height_p: (out) (allow-none): return location for natural
8013 * Computes the requested minimum and natural heights for an actor,
8014 * or if they are already computed, returns the cached values.
8016 * An actor may not get its request - depending on the layout
8017 * manager that's in effect.
8019 * A request should not incorporate the actor's scale or anchor point;
8020 * those transformations do not affect layout, only rendering.
8025 clutter_actor_get_preferred_height (ClutterActor *self,
8027 gfloat *min_height_p,
8028 gfloat *natural_height_p)
8030 float request_min_height, request_natural_height;
8031 SizeRequest *cached_size_request;
8032 const ClutterLayoutInfo *info;
8033 ClutterActorPrivate *priv;
8034 gboolean found_in_cache;
8036 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8040 info = _clutter_actor_get_layout_info_or_defaults (self);
8042 /* we shortcircuit the case of a fixed size set using set_height() */
8043 if (priv->min_height_set && priv->natural_height_set)
8045 if (min_height_p != NULL)
8046 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8048 if (natural_height_p != NULL)
8049 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8054 /* the remaining cases are:
8056 * - either min_height or natural_height have been set
8057 * - neither min_height or natural_height have been set
8059 * in both cases, we go through the cache (and through the actor in case
8060 * of cache misses) and determine the authoritative value depending on
8064 if (!priv->needs_height_request)
8067 _clutter_actor_get_cached_size_request (for_width,
8068 priv->height_requests,
8069 &cached_size_request);
8073 found_in_cache = FALSE;
8074 cached_size_request = &priv->height_requests[0];
8077 if (!found_in_cache)
8079 gfloat minimum_height, natural_height;
8080 ClutterActorClass *klass;
8082 minimum_height = natural_height = 0;
8084 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8086 /* adjust for margin */
8089 for_width -= (info->margin.left + info->margin.right);
8094 klass = CLUTTER_ACTOR_GET_CLASS (self);
8095 klass->get_preferred_height (self, for_width,
8099 /* adjust for margin */
8100 minimum_height += (info->margin.top + info->margin.bottom);
8101 natural_height += (info->margin.top + info->margin.bottom);
8103 /* Due to accumulated float errors, it's better not to warn
8104 * on this, but just fix it.
8106 if (natural_height < minimum_height)
8107 natural_height = minimum_height;
8109 cached_size_request->min_size = minimum_height;
8110 cached_size_request->natural_size = natural_height;
8111 cached_size_request->for_size = for_width;
8112 cached_size_request->age = priv->cached_height_age;
8114 priv->cached_height_age += 1;
8115 priv->needs_height_request = FALSE;
8118 if (!priv->min_height_set)
8119 request_min_height = cached_size_request->min_size;
8121 request_min_height = info->min_height;
8123 if (!priv->natural_height_set)
8124 request_natural_height = cached_size_request->natural_size;
8126 request_natural_height = info->natural_height;
8129 *min_height_p = request_min_height;
8131 if (natural_height_p)
8132 *natural_height_p = request_natural_height;
8136 * clutter_actor_get_allocation_box:
8137 * @self: A #ClutterActor
8138 * @box: (out): the function fills this in with the actor's allocation
8140 * Gets the layout box an actor has been assigned. The allocation can
8141 * only be assumed valid inside a paint() method; anywhere else, it
8142 * may be out-of-date.
8144 * An allocation does not incorporate the actor's scale or anchor point;
8145 * those transformations do not affect layout, only rendering.
8147 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8148 * of functions inside the implementation of the get_preferred_width()
8149 * or get_preferred_height() virtual functions.</note>
8154 clutter_actor_get_allocation_box (ClutterActor *self,
8155 ClutterActorBox *box)
8157 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8159 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8160 * which limits calling get_allocation to inside paint() basically; or
8161 * we can 2) force a layout, which could be expensive if someone calls
8162 * get_allocation somewhere silly; or we can 3) just return the latest
8163 * value, allowing it to be out-of-date, and assume people know what
8166 * The least-surprises approach that keeps existing code working is
8167 * likely to be 2). People can end up doing some inefficient things,
8168 * though, and in general code that requires 2) is probably broken.
8171 /* this implements 2) */
8172 if (G_UNLIKELY (self->priv->needs_allocation))
8174 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8176 /* do not queue a relayout on an unparented actor */
8178 _clutter_stage_maybe_relayout (stage);
8181 /* commenting out the code above and just keeping this assigment
8184 *box = self->priv->allocation;
8188 * clutter_actor_get_allocation_geometry:
8189 * @self: A #ClutterActor
8190 * @geom: (out): allocation geometry in pixels
8192 * Gets the layout box an actor has been assigned. The allocation can
8193 * only be assumed valid inside a paint() method; anywhere else, it
8194 * may be out-of-date.
8196 * An allocation does not incorporate the actor's scale or anchor point;
8197 * those transformations do not affect layout, only rendering.
8199 * The returned rectangle is in pixels.
8204 clutter_actor_get_allocation_geometry (ClutterActor *self,
8205 ClutterGeometry *geom)
8207 ClutterActorBox box;
8209 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8210 g_return_if_fail (geom != NULL);
8212 clutter_actor_get_allocation_box (self, &box);
8214 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8215 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8216 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8217 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8221 clutter_actor_update_constraints (ClutterActor *self,
8222 ClutterActorBox *allocation)
8224 ClutterActorPrivate *priv = self->priv;
8225 const GList *constraints, *l;
8227 if (priv->constraints == NULL)
8230 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8231 for (l = constraints; l != NULL; l = l->next)
8233 ClutterConstraint *constraint = l->data;
8234 ClutterActorMeta *meta = l->data;
8236 if (clutter_actor_meta_get_enabled (meta))
8238 _clutter_constraint_update_allocation (constraint,
8242 CLUTTER_NOTE (LAYOUT,
8243 "Allocation of '%s' after constraint '%s': "
8244 "{ %.2f, %.2f, %.2f, %.2f }",
8245 _clutter_actor_get_debug_name (self),
8246 _clutter_actor_meta_get_debug_name (meta),
8256 * clutter_actor_adjust_allocation:
8257 * @self: a #ClutterActor
8258 * @allocation: (inout): the allocation to adjust
8260 * Adjusts the passed allocation box taking into account the actor's
8261 * layout information, like alignment, expansion, and margin.
8264 clutter_actor_adjust_allocation (ClutterActor *self,
8265 ClutterActorBox *allocation)
8267 ClutterActorBox adj_allocation;
8268 float alloc_width, alloc_height;
8269 float min_width, min_height;
8270 float nat_width, nat_height;
8271 ClutterRequestMode req_mode;
8273 adj_allocation = *allocation;
8275 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8277 /* we want to hit the cache, so we use the public API */
8278 req_mode = clutter_actor_get_request_mode (self);
8280 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8282 clutter_actor_get_preferred_width (self, -1,
8285 clutter_actor_get_preferred_height (self, alloc_width,
8289 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8291 clutter_actor_get_preferred_height (self, -1,
8294 clutter_actor_get_preferred_height (self, alloc_height,
8299 #ifdef CLUTTER_ENABLE_DEBUG
8300 /* warn about underallocations */
8301 if (_clutter_diagnostic_enabled () &&
8302 (floorf (min_width - alloc_width) > 0 ||
8303 floorf (min_height - alloc_height) > 0))
8305 ClutterActor *parent = clutter_actor_get_parent (self);
8307 /* the only actors that are allowed to be underallocated are the Stage,
8308 * as it doesn't have an implicit size, and Actors that specifically
8309 * told us that they want to opt-out from layout control mechanisms
8310 * through the NO_LAYOUT escape hatch.
8312 if (parent != NULL &&
8313 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8315 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8316 "of %.2f x %.2f from its parent actor '%s', but its "
8317 "requested minimum size is of %.2f x %.2f",
8318 _clutter_actor_get_debug_name (self),
8319 alloc_width, alloc_height,
8320 _clutter_actor_get_debug_name (parent),
8321 min_width, min_height);
8326 clutter_actor_adjust_width (self,
8330 &adj_allocation.x2);
8332 clutter_actor_adjust_height (self,
8336 &adj_allocation.y2);
8338 /* we maintain the invariant that an allocation cannot be adjusted
8339 * to be outside the parent-given box
8341 if (adj_allocation.x1 < allocation->x1 ||
8342 adj_allocation.y1 < allocation->y1 ||
8343 adj_allocation.x2 > allocation->x2 ||
8344 adj_allocation.y2 > allocation->y2)
8346 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8347 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8348 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8349 _clutter_actor_get_debug_name (self),
8350 adj_allocation.x1, adj_allocation.y1,
8351 adj_allocation.x2 - adj_allocation.x1,
8352 adj_allocation.y2 - adj_allocation.y1,
8353 allocation->x1, allocation->y1,
8354 allocation->x2 - allocation->x1,
8355 allocation->y2 - allocation->y1);
8359 *allocation = adj_allocation;
8363 * clutter_actor_allocate:
8364 * @self: A #ClutterActor
8365 * @box: new allocation of the actor, in parent-relative coordinates
8366 * @flags: flags that control the allocation
8368 * Called by the parent of an actor to assign the actor its size.
8369 * Should never be called by applications (except when implementing
8370 * a container or layout manager).
8372 * Actors can know from their allocation box whether they have moved
8373 * with respect to their parent actor. The @flags parameter describes
8374 * additional information about the allocation, for instance whether
8375 * the parent has moved with respect to the stage, for example because
8376 * a grandparent's origin has moved.
8381 clutter_actor_allocate (ClutterActor *self,
8382 const ClutterActorBox *box,
8383 ClutterAllocationFlags flags)
8385 ClutterActorPrivate *priv;
8386 ClutterActorClass *klass;
8387 ClutterActorBox old_allocation, real_allocation;
8388 gboolean origin_changed, child_moved, size_changed;
8389 gboolean stage_allocation_changed;
8391 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8392 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8394 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8395 "which isn't a descendent of the stage!\n",
8396 self, _clutter_actor_get_debug_name (self));
8402 old_allocation = priv->allocation;
8403 real_allocation = *box;
8405 /* constraints are allowed to modify the allocation only here; we do
8406 * this prior to all the other checks so that we can bail out if the
8407 * allocation did not change
8409 clutter_actor_update_constraints (self, &real_allocation);
8411 /* adjust the allocation depending on the align/margin properties */
8412 clutter_actor_adjust_allocation (self, &real_allocation);
8414 if (real_allocation.x2 < real_allocation.x1 ||
8415 real_allocation.y2 < real_allocation.y1)
8417 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8418 _clutter_actor_get_debug_name (self),
8419 real_allocation.x2 - real_allocation.x1,
8420 real_allocation.y2 - real_allocation.y1);
8423 /* we allow 0-sized actors, but not negative-sized ones */
8424 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8425 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8427 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8429 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8430 real_allocation.y1 != old_allocation.y1);
8432 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8433 real_allocation.y2 != old_allocation.y2);
8435 if (origin_changed || child_moved || size_changed)
8436 stage_allocation_changed = TRUE;
8438 stage_allocation_changed = FALSE;
8440 /* If we get an allocation "out of the blue"
8441 * (we did not queue relayout), then we want to
8442 * ignore it. But if we have needs_allocation set,
8443 * we want to guarantee that allocate() virtual
8444 * method is always called, i.e. that queue_relayout()
8445 * always results in an allocate() invocation on
8448 * The optimization here is to avoid re-allocating
8449 * actors that did not queue relayout and were
8452 if (!priv->needs_allocation && !stage_allocation_changed)
8454 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8458 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8459 * clutter_actor_allocate(), it indicates whether the parent has its
8460 * absolute origin moved; when passed in to ClutterActor::allocate()
8461 * virtual method though, it indicates whether the child has its
8462 * absolute origin moved. So we set it when child_moved is TRUE
8465 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8467 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8469 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8470 _clutter_actor_get_debug_name (self));
8472 klass = CLUTTER_ACTOR_GET_CLASS (self);
8473 klass->allocate (self, &real_allocation, flags);
8475 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8477 if (stage_allocation_changed)
8478 clutter_actor_queue_redraw (self);
8482 * clutter_actor_set_allocation:
8483 * @self: a #ClutterActor
8484 * @box: a #ClutterActorBox
8485 * @flags: allocation flags
8487 * Stores the allocation of @self as defined by @box.
8489 * This function can only be called from within the implementation of
8490 * the #ClutterActorClass.allocate() virtual function.
8492 * The allocation should have been adjusted to take into account constraints,
8493 * alignment, and margin properties. If you are implementing a #ClutterActor
8494 * subclass that provides its own layout management policy for its children
8495 * instead of using a #ClutterLayoutManager delegate, you should not call
8496 * this function on the children of @self; instead, you should call
8497 * clutter_actor_allocate(), which will adjust the allocation box for
8500 * This function should only be used by subclasses of #ClutterActor
8501 * that wish to store their allocation but cannot chain up to the
8502 * parent's implementation; the default implementation of the
8503 * #ClutterActorClass.allocate() virtual function will call this
8506 * It is important to note that, while chaining up was the recommended
8507 * behaviour for #ClutterActor subclasses prior to the introduction of
8508 * this function, it is recommended to call clutter_actor_set_allocation()
8511 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8512 * to handle the allocation of its children, this function will call
8513 * the clutter_layout_manager_allocate() function only if the
8514 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8515 * expected that the subclass will call clutter_layout_manager_allocate()
8516 * by itself. For instance, the following code:
8520 * my_actor_allocate (ClutterActor *actor,
8521 * const ClutterActorBox *allocation,
8522 * ClutterAllocationFlags flags)
8524 * ClutterActorBox new_alloc;
8525 * ClutterAllocationFlags new_flags;
8527 * adjust_allocation (allocation, &new_alloc);
8529 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8531 * /* this will use the layout manager set on the actor */
8532 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8536 * is equivalent to this:
8540 * my_actor_allocate (ClutterActor *actor,
8541 * const ClutterActorBox *allocation,
8542 * ClutterAllocationFlags flags)
8544 * ClutterLayoutManager *layout;
8545 * ClutterActorBox new_alloc;
8547 * adjust_allocation (allocation, &new_alloc);
8549 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8551 * layout = clutter_actor_get_layout_manager (actor);
8552 * clutter_layout_manager_allocate (layout,
8553 * CLUTTER_CONTAINER (actor),
8562 clutter_actor_set_allocation (ClutterActor *self,
8563 const ClutterActorBox *box,
8564 ClutterAllocationFlags flags)
8566 ClutterActorPrivate *priv;
8569 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8570 g_return_if_fail (box != NULL);
8572 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8574 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8575 "can only be called from within the implementation of "
8576 "the ClutterActor::allocate() virtual function.");
8582 g_object_freeze_notify (G_OBJECT (self));
8584 changed = clutter_actor_set_allocation_internal (self, box, flags);
8586 /* we allocate our children before we notify changes in our geometry,
8587 * so that people connecting to properties will be able to get valid
8588 * data out of the sub-tree of the scene graph that has this actor at
8591 clutter_actor_maybe_layout_children (self, box, flags);
8595 ClutterActorBox signal_box = priv->allocation;
8596 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8598 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8603 g_object_thaw_notify (G_OBJECT (self));
8607 * clutter_actor_set_geometry:
8608 * @self: A #ClutterActor
8609 * @geometry: A #ClutterGeometry
8611 * Sets the actor's fixed position and forces its minimum and natural
8612 * size, in pixels. This means the untransformed actor will have the
8613 * given geometry. This is the same as calling clutter_actor_set_position()
8614 * and clutter_actor_set_size().
8616 * Deprecated: 1.10: Use clutter_actor_set_position() and
8617 * clutter_actor_set_size() instead.
8620 clutter_actor_set_geometry (ClutterActor *self,
8621 const ClutterGeometry *geometry)
8623 g_object_freeze_notify (G_OBJECT (self));
8625 clutter_actor_set_position (self, geometry->x, geometry->y);
8626 clutter_actor_set_size (self, geometry->width, geometry->height);
8628 g_object_thaw_notify (G_OBJECT (self));
8632 * clutter_actor_get_geometry:
8633 * @self: A #ClutterActor
8634 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8636 * Gets the size and position of an actor relative to its parent
8637 * actor. This is the same as calling clutter_actor_get_position() and
8638 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8639 * requested size and position if the actor's allocation is invalid.
8641 * Deprecated: 1.10: Use clutter_actor_get_position() and
8642 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8646 clutter_actor_get_geometry (ClutterActor *self,
8647 ClutterGeometry *geometry)
8649 gfloat x, y, width, height;
8651 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8652 g_return_if_fail (geometry != NULL);
8654 clutter_actor_get_position (self, &x, &y);
8655 clutter_actor_get_size (self, &width, &height);
8657 geometry->x = (int) x;
8658 geometry->y = (int) y;
8659 geometry->width = (int) width;
8660 geometry->height = (int) height;
8664 * clutter_actor_set_position:
8665 * @self: A #ClutterActor
8666 * @x: New left position of actor in pixels.
8667 * @y: New top position of actor in pixels.
8669 * Sets the actor's fixed position in pixels relative to any parent
8672 * If a layout manager is in use, this position will override the
8673 * layout manager and force a fixed position.
8676 clutter_actor_set_position (ClutterActor *self,
8680 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8682 g_object_freeze_notify (G_OBJECT (self));
8684 clutter_actor_set_x (self, x);
8685 clutter_actor_set_y (self, y);
8687 g_object_thaw_notify (G_OBJECT (self));
8691 * clutter_actor_get_fixed_position_set:
8692 * @self: A #ClutterActor
8694 * Checks whether an actor has a fixed position set (and will thus be
8695 * unaffected by any layout manager).
8697 * Return value: %TRUE if the fixed position is set on the actor
8702 clutter_actor_get_fixed_position_set (ClutterActor *self)
8704 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8706 return self->priv->position_set;
8710 * clutter_actor_set_fixed_position_set:
8711 * @self: A #ClutterActor
8712 * @is_set: whether to use fixed position
8714 * Sets whether an actor has a fixed position set (and will thus be
8715 * unaffected by any layout manager).
8720 clutter_actor_set_fixed_position_set (ClutterActor *self,
8723 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8725 if (self->priv->position_set == (is_set != FALSE))
8728 self->priv->position_set = is_set != FALSE;
8729 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8731 clutter_actor_queue_relayout (self);
8735 * clutter_actor_move_by:
8736 * @self: A #ClutterActor
8737 * @dx: Distance to move Actor on X axis.
8738 * @dy: Distance to move Actor on Y axis.
8740 * Moves an actor by the specified distance relative to its current
8741 * position in pixels.
8743 * This function modifies the fixed position of an actor and thus removes
8744 * it from any layout management. Another way to move an actor is with an
8745 * anchor point, see clutter_actor_set_anchor_point().
8750 clutter_actor_move_by (ClutterActor *self,
8754 const ClutterLayoutInfo *info;
8757 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8759 info = _clutter_actor_get_layout_info_or_defaults (self);
8763 clutter_actor_set_position (self, x + dx, y + dy);
8767 clutter_actor_set_min_width (ClutterActor *self,
8770 ClutterActorPrivate *priv = self->priv;
8771 ClutterActorBox old = { 0, };
8772 ClutterLayoutInfo *info;
8774 /* if we are setting the size on a top-level actor and the
8775 * backend only supports static top-levels (e.g. framebuffers)
8776 * then we ignore the passed value and we override it with
8777 * the stage implementation's preferred size.
8779 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8780 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8783 info = _clutter_actor_get_layout_info (self);
8785 if (priv->min_width_set && min_width == info->min_width)
8788 g_object_freeze_notify (G_OBJECT (self));
8790 clutter_actor_store_old_geometry (self, &old);
8792 info->min_width = min_width;
8793 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8794 clutter_actor_set_min_width_set (self, TRUE);
8796 clutter_actor_notify_if_geometry_changed (self, &old);
8798 g_object_thaw_notify (G_OBJECT (self));
8800 clutter_actor_queue_relayout (self);
8804 clutter_actor_set_min_height (ClutterActor *self,
8808 ClutterActorPrivate *priv = self->priv;
8809 ClutterActorBox old = { 0, };
8810 ClutterLayoutInfo *info;
8812 /* if we are setting the size on a top-level actor and the
8813 * backend only supports static top-levels (e.g. framebuffers)
8814 * then we ignore the passed value and we override it with
8815 * the stage implementation's preferred size.
8817 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8818 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8821 info = _clutter_actor_get_layout_info (self);
8823 if (priv->min_height_set && min_height == info->min_height)
8826 g_object_freeze_notify (G_OBJECT (self));
8828 clutter_actor_store_old_geometry (self, &old);
8830 info->min_height = min_height;
8831 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8832 clutter_actor_set_min_height_set (self, TRUE);
8834 clutter_actor_notify_if_geometry_changed (self, &old);
8836 g_object_thaw_notify (G_OBJECT (self));
8838 clutter_actor_queue_relayout (self);
8842 clutter_actor_set_natural_width (ClutterActor *self,
8843 gfloat natural_width)
8845 ClutterActorPrivate *priv = self->priv;
8846 ClutterActorBox old = { 0, };
8847 ClutterLayoutInfo *info;
8849 /* if we are setting the size on a top-level actor and the
8850 * backend only supports static top-levels (e.g. framebuffers)
8851 * then we ignore the passed value and we override it with
8852 * the stage implementation's preferred size.
8854 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8855 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8858 info = _clutter_actor_get_layout_info (self);
8860 if (priv->natural_width_set && natural_width == info->natural_width)
8863 g_object_freeze_notify (G_OBJECT (self));
8865 clutter_actor_store_old_geometry (self, &old);
8867 info->natural_width = natural_width;
8868 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8869 clutter_actor_set_natural_width_set (self, TRUE);
8871 clutter_actor_notify_if_geometry_changed (self, &old);
8873 g_object_thaw_notify (G_OBJECT (self));
8875 clutter_actor_queue_relayout (self);
8879 clutter_actor_set_natural_height (ClutterActor *self,
8880 gfloat natural_height)
8882 ClutterActorPrivate *priv = self->priv;
8883 ClutterActorBox old = { 0, };
8884 ClutterLayoutInfo *info;
8886 /* if we are setting the size on a top-level actor and the
8887 * backend only supports static top-levels (e.g. framebuffers)
8888 * then we ignore the passed value and we override it with
8889 * the stage implementation's preferred size.
8891 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8892 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8895 info = _clutter_actor_get_layout_info (self);
8897 if (priv->natural_height_set && natural_height == info->natural_height)
8900 g_object_freeze_notify (G_OBJECT (self));
8902 clutter_actor_store_old_geometry (self, &old);
8904 info->natural_height = natural_height;
8905 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8906 clutter_actor_set_natural_height_set (self, TRUE);
8908 clutter_actor_notify_if_geometry_changed (self, &old);
8910 g_object_thaw_notify (G_OBJECT (self));
8912 clutter_actor_queue_relayout (self);
8916 clutter_actor_set_min_width_set (ClutterActor *self,
8917 gboolean use_min_width)
8919 ClutterActorPrivate *priv = self->priv;
8920 ClutterActorBox old = { 0, };
8922 if (priv->min_width_set == (use_min_width != FALSE))
8925 clutter_actor_store_old_geometry (self, &old);
8927 priv->min_width_set = use_min_width != FALSE;
8928 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8930 clutter_actor_notify_if_geometry_changed (self, &old);
8932 clutter_actor_queue_relayout (self);
8936 clutter_actor_set_min_height_set (ClutterActor *self,
8937 gboolean use_min_height)
8939 ClutterActorPrivate *priv = self->priv;
8940 ClutterActorBox old = { 0, };
8942 if (priv->min_height_set == (use_min_height != FALSE))
8945 clutter_actor_store_old_geometry (self, &old);
8947 priv->min_height_set = use_min_height != FALSE;
8948 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8950 clutter_actor_notify_if_geometry_changed (self, &old);
8952 clutter_actor_queue_relayout (self);
8956 clutter_actor_set_natural_width_set (ClutterActor *self,
8957 gboolean use_natural_width)
8959 ClutterActorPrivate *priv = self->priv;
8960 ClutterActorBox old = { 0, };
8962 if (priv->natural_width_set == (use_natural_width != FALSE))
8965 clutter_actor_store_old_geometry (self, &old);
8967 priv->natural_width_set = use_natural_width != FALSE;
8968 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8970 clutter_actor_notify_if_geometry_changed (self, &old);
8972 clutter_actor_queue_relayout (self);
8976 clutter_actor_set_natural_height_set (ClutterActor *self,
8977 gboolean use_natural_height)
8979 ClutterActorPrivate *priv = self->priv;
8980 ClutterActorBox old = { 0, };
8982 if (priv->natural_height_set == (use_natural_height != FALSE))
8985 clutter_actor_store_old_geometry (self, &old);
8987 priv->natural_height_set = use_natural_height != FALSE;
8988 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8990 clutter_actor_notify_if_geometry_changed (self, &old);
8992 clutter_actor_queue_relayout (self);
8996 * clutter_actor_set_request_mode:
8997 * @self: a #ClutterActor
8998 * @mode: the request mode
9000 * Sets the geometry request mode of @self.
9002 * The @mode determines the order for invoking
9003 * clutter_actor_get_preferred_width() and
9004 * clutter_actor_get_preferred_height()
9009 clutter_actor_set_request_mode (ClutterActor *self,
9010 ClutterRequestMode mode)
9012 ClutterActorPrivate *priv;
9014 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9018 if (priv->request_mode == mode)
9021 priv->request_mode = mode;
9023 priv->needs_width_request = TRUE;
9024 priv->needs_height_request = TRUE;
9026 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9028 clutter_actor_queue_relayout (self);
9032 * clutter_actor_get_request_mode:
9033 * @self: a #ClutterActor
9035 * Retrieves the geometry request mode of @self
9037 * Return value: the request mode for the actor
9042 clutter_actor_get_request_mode (ClutterActor *self)
9044 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9045 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9047 return self->priv->request_mode;
9050 /* variant of set_width() without checks and without notification
9051 * freeze+thaw, for internal usage only
9054 clutter_actor_set_width_internal (ClutterActor *self,
9059 /* the Stage will use the :min-width to control the minimum
9060 * width to be resized to, so we should not be setting it
9061 * along with the :natural-width
9063 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9064 clutter_actor_set_min_width (self, width);
9066 clutter_actor_set_natural_width (self, width);
9070 /* we only unset the :natural-width for the Stage */
9071 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9072 clutter_actor_set_min_width_set (self, FALSE);
9074 clutter_actor_set_natural_width_set (self, FALSE);
9078 /* variant of set_height() without checks and without notification
9079 * freeze+thaw, for internal usage only
9082 clutter_actor_set_height_internal (ClutterActor *self,
9087 /* see the comment above in set_width_internal() */
9088 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9089 clutter_actor_set_min_height (self, height);
9091 clutter_actor_set_natural_height (self, height);
9095 /* see the comment above in set_width_internal() */
9096 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9097 clutter_actor_set_min_height_set (self, FALSE);
9099 clutter_actor_set_natural_height_set (self, FALSE);
9104 * clutter_actor_set_size:
9105 * @self: A #ClutterActor
9106 * @width: New width of actor in pixels, or -1
9107 * @height: New height of actor in pixels, or -1
9109 * Sets the actor's size request in pixels. This overrides any
9110 * "normal" size request the actor would have. For example
9111 * a text actor might normally request the size of the text;
9112 * this function would force a specific size instead.
9114 * If @width and/or @height are -1 the actor will use its
9115 * "normal" size request instead of overriding it, i.e.
9116 * you can "unset" the size with -1.
9118 * This function sets or unsets both the minimum and natural size.
9121 clutter_actor_set_size (ClutterActor *self,
9125 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9127 g_object_freeze_notify (G_OBJECT (self));
9129 clutter_actor_set_width (self, width);
9130 clutter_actor_set_height (self, height);
9132 g_object_thaw_notify (G_OBJECT (self));
9136 * clutter_actor_get_size:
9137 * @self: A #ClutterActor
9138 * @width: (out) (allow-none): return location for the width, or %NULL.
9139 * @height: (out) (allow-none): return location for the height, or %NULL.
9141 * This function tries to "do what you mean" and return
9142 * the size an actor will have. If the actor has a valid
9143 * allocation, the allocation will be returned; otherwise,
9144 * the actors natural size request will be returned.
9146 * If you care whether you get the request vs. the allocation, you
9147 * should probably call a different function like
9148 * clutter_actor_get_allocation_box() or
9149 * clutter_actor_get_preferred_width().
9154 clutter_actor_get_size (ClutterActor *self,
9158 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9161 *width = clutter_actor_get_width (self);
9164 *height = clutter_actor_get_height (self);
9168 * clutter_actor_get_position:
9169 * @self: a #ClutterActor
9170 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9171 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9173 * This function tries to "do what you mean" and tell you where the
9174 * actor is, prior to any transformations. Retrieves the fixed
9175 * position of an actor in pixels, if one has been set; otherwise, if
9176 * the allocation is valid, returns the actor's allocated position;
9177 * otherwise, returns 0,0.
9179 * The returned position is in pixels.
9184 clutter_actor_get_position (ClutterActor *self,
9188 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9191 *x = clutter_actor_get_x (self);
9194 *y = clutter_actor_get_y (self);
9198 * clutter_actor_get_transformed_position:
9199 * @self: A #ClutterActor
9200 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9201 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9203 * Gets the absolute position of an actor, in pixels relative to the stage.
9208 clutter_actor_get_transformed_position (ClutterActor *self,
9215 v1.x = v1.y = v1.z = 0;
9216 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9226 * clutter_actor_get_transformed_size:
9227 * @self: A #ClutterActor
9228 * @width: (out) (allow-none): return location for the width, or %NULL
9229 * @height: (out) (allow-none): return location for the height, or %NULL
9231 * Gets the absolute size of an actor in pixels, taking into account the
9234 * If the actor has a valid allocation, the allocated size will be used.
9235 * If the actor has not a valid allocation then the preferred size will
9236 * be transformed and returned.
9238 * If you want the transformed allocation, see
9239 * clutter_actor_get_abs_allocation_vertices() instead.
9241 * <note>When the actor (or one of its ancestors) is rotated around the
9242 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9243 * as a generic quadrangle; in that case this function returns the size
9244 * of the smallest rectangle that encapsulates the entire quad. Please
9245 * note that in this case no assumptions can be made about the relative
9246 * position of this envelope to the absolute position of the actor, as
9247 * returned by clutter_actor_get_transformed_position(); if you need this
9248 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9249 * to get the coords of the actual quadrangle.</note>
9254 clutter_actor_get_transformed_size (ClutterActor *self,
9258 ClutterActorPrivate *priv;
9260 gfloat x_min, x_max, y_min, y_max;
9263 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9267 /* if the actor hasn't been allocated yet, get the preferred
9268 * size and transform that
9270 if (priv->needs_allocation)
9272 gfloat natural_width, natural_height;
9273 ClutterActorBox box;
9275 /* Make a fake allocation to transform.
9277 * NB: _clutter_actor_transform_and_project_box expects a box in
9278 * the actor's coordinate space... */
9283 natural_width = natural_height = 0;
9284 clutter_actor_get_preferred_size (self, NULL, NULL,
9288 box.x2 = natural_width;
9289 box.y2 = natural_height;
9291 _clutter_actor_transform_and_project_box (self, &box, v);
9294 clutter_actor_get_abs_allocation_vertices (self, v);
9296 x_min = x_max = v[0].x;
9297 y_min = y_max = v[0].y;
9299 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9315 *width = x_max - x_min;
9318 *height = y_max - y_min;
9322 * clutter_actor_get_width:
9323 * @self: A #ClutterActor
9325 * Retrieves the width of a #ClutterActor.
9327 * If the actor has a valid allocation, this function will return the
9328 * width of the allocated area given to the actor.
9330 * If the actor does not have a valid allocation, this function will
9331 * return the actor's natural width, that is the preferred width of
9334 * If you care whether you get the preferred width or the width that
9335 * has been assigned to the actor, you should probably call a different
9336 * function like clutter_actor_get_allocation_box() to retrieve the
9337 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9340 * If an actor has a fixed width, for instance a width that has been
9341 * assigned using clutter_actor_set_width(), the width returned will
9342 * be the same value.
9344 * Return value: the width of the actor, in pixels
9347 clutter_actor_get_width (ClutterActor *self)
9349 ClutterActorPrivate *priv;
9351 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9355 if (priv->needs_allocation)
9357 gfloat natural_width = 0;
9359 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9360 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9363 gfloat natural_height = 0;
9365 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9366 clutter_actor_get_preferred_width (self, natural_height,
9371 return natural_width;
9374 return priv->allocation.x2 - priv->allocation.x1;
9378 * clutter_actor_get_height:
9379 * @self: A #ClutterActor
9381 * Retrieves the height of a #ClutterActor.
9383 * If the actor has a valid allocation, this function will return the
9384 * height of the allocated area given to the actor.
9386 * If the actor does not have a valid allocation, this function will
9387 * return the actor's natural height, that is the preferred height of
9390 * If you care whether you get the preferred height or the height that
9391 * has been assigned to the actor, you should probably call a different
9392 * function like clutter_actor_get_allocation_box() to retrieve the
9393 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9396 * If an actor has a fixed height, for instance a height that has been
9397 * assigned using clutter_actor_set_height(), the height returned will
9398 * be the same value.
9400 * Return value: the height of the actor, in pixels
9403 clutter_actor_get_height (ClutterActor *self)
9405 ClutterActorPrivate *priv;
9407 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9411 if (priv->needs_allocation)
9413 gfloat natural_height = 0;
9415 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9417 gfloat natural_width = 0;
9419 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9420 clutter_actor_get_preferred_height (self, natural_width,
9421 NULL, &natural_height);
9424 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9426 return natural_height;
9429 return priv->allocation.y2 - priv->allocation.y1;
9433 * clutter_actor_set_width:
9434 * @self: A #ClutterActor
9435 * @width: Requested new width for the actor, in pixels, or -1
9437 * Forces a width on an actor, causing the actor's preferred width
9438 * and height (if any) to be ignored.
9440 * If @width is -1 the actor will use its preferred width request
9441 * instead of overriding it, i.e. you can "unset" the width with -1.
9443 * This function sets both the minimum and natural size of the actor.
9448 clutter_actor_set_width (ClutterActor *self,
9451 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9453 if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9455 float cur_size = clutter_actor_get_width (self);
9457 _clutter_actor_create_transition (self,
9458 obj_props[PROP_WIDTH],
9463 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9465 clutter_actor_queue_relayout (self);
9469 * clutter_actor_set_height:
9470 * @self: A #ClutterActor
9471 * @height: Requested new height for the actor, in pixels, or -1
9473 * Forces a height on an actor, causing the actor's preferred width
9474 * and height (if any) to be ignored.
9476 * If @height is -1 the actor will use its preferred height instead of
9477 * overriding it, i.e. you can "unset" the height with -1.
9479 * This function sets both the minimum and natural size of the actor.
9484 clutter_actor_set_height (ClutterActor *self,
9487 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9489 if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9491 float cur_size = clutter_actor_get_height (self);
9493 _clutter_actor_create_transition (self,
9494 obj_props[PROP_HEIGHT],
9499 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9501 clutter_actor_queue_relayout (self);
9505 clutter_actor_set_x_internal (ClutterActor *self,
9508 ClutterActorPrivate *priv = self->priv;
9509 ClutterLayoutInfo *linfo;
9510 ClutterActorBox old = { 0, };
9512 linfo = _clutter_actor_get_layout_info (self);
9514 if (priv->position_set && linfo->fixed_x == x)
9517 clutter_actor_store_old_geometry (self, &old);
9520 clutter_actor_set_fixed_position_set (self, TRUE);
9522 clutter_actor_notify_if_geometry_changed (self, &old);
9524 clutter_actor_queue_relayout (self);
9528 clutter_actor_set_y_internal (ClutterActor *self,
9531 ClutterActorPrivate *priv = self->priv;
9532 ClutterLayoutInfo *linfo;
9533 ClutterActorBox old = { 0, };
9535 linfo = _clutter_actor_get_layout_info (self);
9537 if (priv->position_set && linfo->fixed_y == y)
9540 clutter_actor_store_old_geometry (self, &old);
9543 clutter_actor_set_fixed_position_set (self, TRUE);
9545 clutter_actor_notify_if_geometry_changed (self, &old);
9547 clutter_actor_queue_relayout (self);
9551 * clutter_actor_set_x:
9552 * @self: a #ClutterActor
9553 * @x: the actor's position on the X axis
9555 * Sets the actor's X coordinate, relative to its parent, in pixels.
9557 * Overrides any layout manager and forces a fixed position for
9560 * The #ClutterActor:x property is animatable.
9565 clutter_actor_set_x (ClutterActor *self,
9568 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9570 if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9572 float cur_position = clutter_actor_get_x (self);
9574 _clutter_actor_create_transition (self, obj_props[PROP_X],
9579 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9581 clutter_actor_queue_relayout (self);
9585 * clutter_actor_set_y:
9586 * @self: a #ClutterActor
9587 * @y: the actor's position on the Y axis
9589 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9591 * Overrides any layout manager and forces a fixed position for
9594 * The #ClutterActor:y property is animatable.
9599 clutter_actor_set_y (ClutterActor *self,
9602 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9604 if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9606 float cur_position = clutter_actor_get_y (self);
9608 _clutter_actor_create_transition (self, obj_props[PROP_Y],
9613 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9615 clutter_actor_queue_relayout (self);
9619 * clutter_actor_get_x:
9620 * @self: A #ClutterActor
9622 * Retrieves the X coordinate of a #ClutterActor.
9624 * This function tries to "do what you mean", by returning the
9625 * correct value depending on the actor's state.
9627 * If the actor has a valid allocation, this function will return
9628 * the X coordinate of the origin of the allocation box.
9630 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9631 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9632 * function will return that coordinate.
9634 * If both the allocation and a fixed position are missing, this function
9637 * Return value: the X coordinate, in pixels, ignoring any
9638 * transformation (i.e. scaling, rotation)
9641 clutter_actor_get_x (ClutterActor *self)
9643 ClutterActorPrivate *priv;
9645 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9649 if (priv->needs_allocation)
9651 if (priv->position_set)
9653 const ClutterLayoutInfo *info;
9655 info = _clutter_actor_get_layout_info_or_defaults (self);
9657 return info->fixed_x;
9663 return priv->allocation.x1;
9667 * clutter_actor_get_y:
9668 * @self: A #ClutterActor
9670 * Retrieves the Y coordinate of a #ClutterActor.
9672 * This function tries to "do what you mean", by returning the
9673 * correct value depending on the actor's state.
9675 * If the actor has a valid allocation, this function will return
9676 * the Y coordinate of the origin of the allocation box.
9678 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9679 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9680 * function will return that coordinate.
9682 * If both the allocation and a fixed position are missing, this function
9685 * Return value: the Y coordinate, in pixels, ignoring any
9686 * transformation (i.e. scaling, rotation)
9689 clutter_actor_get_y (ClutterActor *self)
9691 ClutterActorPrivate *priv;
9693 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9697 if (priv->needs_allocation)
9699 if (priv->position_set)
9701 const ClutterLayoutInfo *info;
9703 info = _clutter_actor_get_layout_info_or_defaults (self);
9705 return info->fixed_y;
9711 return priv->allocation.y1;
9715 * clutter_actor_set_scale:
9716 * @self: A #ClutterActor
9717 * @scale_x: double factor to scale actor by horizontally.
9718 * @scale_y: double factor to scale actor by vertically.
9720 * Scales an actor with the given factors. The scaling is relative to
9721 * the scale center and the anchor point. The scale center is
9722 * unchanged by this function and defaults to 0,0.
9724 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9730 clutter_actor_set_scale (ClutterActor *self,
9734 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9736 g_object_freeze_notify (G_OBJECT (self));
9738 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9739 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9741 g_object_thaw_notify (G_OBJECT (self));
9745 * clutter_actor_set_scale_full:
9746 * @self: A #ClutterActor
9747 * @scale_x: double factor to scale actor by horizontally.
9748 * @scale_y: double factor to scale actor by vertically.
9749 * @center_x: X coordinate of the center of the scale.
9750 * @center_y: Y coordinate of the center of the scale
9752 * Scales an actor with the given factors around the given center
9753 * point. The center point is specified in pixels relative to the
9754 * anchor point (usually the top left corner of the actor).
9756 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9762 clutter_actor_set_scale_full (ClutterActor *self,
9768 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9770 g_object_freeze_notify (G_OBJECT (self));
9772 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9773 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9774 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9775 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9777 g_object_thaw_notify (G_OBJECT (self));
9781 * clutter_actor_set_scale_with_gravity:
9782 * @self: A #ClutterActor
9783 * @scale_x: double factor to scale actor by horizontally.
9784 * @scale_y: double factor to scale actor by vertically.
9785 * @gravity: the location of the scale center expressed as a compass
9788 * Scales an actor with the given factors around the given
9789 * center point. The center point is specified as one of the compass
9790 * directions in #ClutterGravity. For example, setting it to north
9791 * will cause the top of the actor to remain unchanged and the rest of
9792 * the actor to expand left, right and downwards.
9794 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9800 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9803 ClutterGravity gravity)
9805 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9807 g_object_freeze_notify (G_OBJECT (self));
9809 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9810 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9811 clutter_actor_set_scale_gravity (self, gravity);
9813 g_object_thaw_notify (G_OBJECT (self));
9817 * clutter_actor_get_scale:
9818 * @self: A #ClutterActor
9819 * @scale_x: (out) (allow-none): Location to store horizonal
9820 * scale factor, or %NULL.
9821 * @scale_y: (out) (allow-none): Location to store vertical
9822 * scale factor, or %NULL.
9824 * Retrieves an actors scale factors.
9829 clutter_actor_get_scale (ClutterActor *self,
9833 const ClutterTransformInfo *info;
9835 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9837 info = _clutter_actor_get_transform_info_or_defaults (self);
9840 *scale_x = info->scale_x;
9843 *scale_y = info->scale_y;
9847 * clutter_actor_get_scale_center:
9848 * @self: A #ClutterActor
9849 * @center_x: (out) (allow-none): Location to store the X position
9850 * of the scale center, or %NULL.
9851 * @center_y: (out) (allow-none): Location to store the Y position
9852 * of the scale center, or %NULL.
9854 * Retrieves the scale center coordinate in pixels relative to the top
9855 * left corner of the actor. If the scale center was specified using a
9856 * #ClutterGravity this will calculate the pixel offset using the
9857 * current size of the actor.
9862 clutter_actor_get_scale_center (ClutterActor *self,
9866 const ClutterTransformInfo *info;
9868 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9870 info = _clutter_actor_get_transform_info_or_defaults (self);
9872 clutter_anchor_coord_get_units (self, &info->scale_center,
9879 * clutter_actor_get_scale_gravity:
9880 * @self: A #ClutterActor
9882 * Retrieves the scale center as a compass direction. If the scale
9883 * center was specified in pixels or units this will return
9884 * %CLUTTER_GRAVITY_NONE.
9886 * Return value: the scale gravity
9891 clutter_actor_get_scale_gravity (ClutterActor *self)
9893 const ClutterTransformInfo *info;
9895 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9897 info = _clutter_actor_get_transform_info_or_defaults (self);
9899 return clutter_anchor_coord_get_gravity (&info->scale_center);
9903 clutter_actor_set_opacity_internal (ClutterActor *self,
9906 ClutterActorPrivate *priv = self->priv;
9908 if (priv->opacity != opacity)
9910 priv->opacity = opacity;
9912 /* Queue a redraw from the flatten effect so that it can use
9913 its cached image if available instead of having to redraw the
9914 actual actor. If it doesn't end up using the FBO then the
9915 effect is still able to continue the paint anyway. If there
9916 is no flatten effect yet then this is equivalent to queueing
9918 _clutter_actor_queue_redraw_full (self,
9921 priv->flatten_effect);
9923 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9928 * clutter_actor_set_opacity:
9929 * @self: A #ClutterActor
9930 * @opacity: New opacity value for the actor.
9932 * Sets the actor's opacity, with zero being completely transparent and
9933 * 255 (0xff) being fully opaque.
9935 * The #ClutterActor:opacity property is animatable.
9938 clutter_actor_set_opacity (ClutterActor *self,
9941 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9943 if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
9945 _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
9946 self->priv->opacity,
9950 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9952 clutter_actor_queue_redraw (self);
9956 * clutter_actor_get_paint_opacity_internal:
9957 * @self: a #ClutterActor
9959 * Retrieves the absolute opacity of the actor, as it appears on the stage
9961 * This function does not do type checks
9963 * Return value: the absolute opacity of the actor
9966 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9968 ClutterActorPrivate *priv = self->priv;
9969 ClutterActor *parent;
9971 /* override the top-level opacity to always be 255; even in
9972 * case of ClutterStage:use-alpha being TRUE we want the rest
9973 * of the scene to be painted
9975 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9978 if (priv->opacity_override >= 0)
9979 return priv->opacity_override;
9981 parent = priv->parent;
9983 /* Factor in the actual actors opacity with parents */
9986 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9988 if (opacity != 0xff)
9989 return (opacity * priv->opacity) / 0xff;
9992 return priv->opacity;
9997 * clutter_actor_get_paint_opacity:
9998 * @self: A #ClutterActor
10000 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10002 * This function traverses the hierarchy chain and composites the opacity of
10003 * the actor with that of its parents.
10005 * This function is intended for subclasses to use in the paint virtual
10006 * function, to paint themselves with the correct opacity.
10008 * Return value: The actor opacity value.
10013 clutter_actor_get_paint_opacity (ClutterActor *self)
10015 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10017 return clutter_actor_get_paint_opacity_internal (self);
10021 * clutter_actor_get_opacity:
10022 * @self: a #ClutterActor
10024 * Retrieves the opacity value of an actor, as set by
10025 * clutter_actor_set_opacity().
10027 * For retrieving the absolute opacity of the actor inside a paint
10028 * virtual function, see clutter_actor_get_paint_opacity().
10030 * Return value: the opacity of the actor
10033 clutter_actor_get_opacity (ClutterActor *self)
10035 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10037 return self->priv->opacity;
10041 * clutter_actor_set_offscreen_redirect:
10042 * @self: A #ClutterActor
10043 * @redirect: New offscreen redirect flags for the actor.
10045 * Defines the circumstances where the actor should be redirected into
10046 * an offscreen image. The offscreen image is used to flatten the
10047 * actor into a single image while painting for two main reasons.
10048 * Firstly, when the actor is painted a second time without any of its
10049 * contents changing it can simply repaint the cached image without
10050 * descending further down the actor hierarchy. Secondly, it will make
10051 * the opacity look correct even if there are overlapping primitives
10054 * Caching the actor could in some cases be a performance win and in
10055 * some cases be a performance lose so it is important to determine
10056 * which value is right for an actor before modifying this value. For
10057 * example, there is never any reason to flatten an actor that is just
10058 * a single texture (such as a #ClutterTexture) because it is
10059 * effectively already cached in an image so the offscreen would be
10060 * redundant. Also if the actor contains primitives that are far apart
10061 * with a large transparent area in the middle (such as a large
10062 * CluterGroup with a small actor in the top left and a small actor in
10063 * the bottom right) then the cached image will contain the entire
10064 * image of the large area and the paint will waste time blending all
10065 * of the transparent pixels in the middle.
10067 * The default method of implementing opacity on a container simply
10068 * forwards on the opacity to all of the children. If the children are
10069 * overlapping then it will appear as if they are two separate glassy
10070 * objects and there will be a break in the color where they
10071 * overlap. By redirecting to an offscreen buffer it will be as if the
10072 * two opaque objects are combined into one and then made transparent
10073 * which is usually what is expected.
10075 * The image below demonstrates the difference between redirecting and
10076 * not. The image shows two Clutter groups, each containing a red and
10077 * a green rectangle which overlap. The opacity on the group is set to
10078 * 128 (which is 50%). When the offscreen redirect is not used, the
10079 * red rectangle can be seen through the blue rectangle as if the two
10080 * rectangles were separately transparent. When the redirect is used
10081 * the group as a whole is transparent instead so the red rectangle is
10082 * not visible where they overlap.
10084 * <figure id="offscreen-redirect">
10085 * <title>Sample of using an offscreen redirect for transparency</title>
10086 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10089 * The default value for this property is 0, so we effectively will
10090 * never redirect an actor offscreen by default. This means that there
10091 * are times that transparent actors may look glassy as described
10092 * above. The reason this is the default is because there is a
10093 * performance trade off between quality and performance here. In many
10094 * cases the default form of glassy opacity looks good enough, but if
10095 * it's not you will need to set the
10096 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10097 * redirection for opacity.
10099 * Custom actors that don't contain any overlapping primitives are
10100 * recommended to override the has_overlaps() virtual to return %FALSE
10101 * for maximum efficiency.
10106 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10107 ClutterOffscreenRedirect redirect)
10109 ClutterActorPrivate *priv;
10111 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10115 if (priv->offscreen_redirect != redirect)
10117 priv->offscreen_redirect = redirect;
10119 /* Queue a redraw from the effect so that it can use its cached
10120 image if available instead of having to redraw the actual
10121 actor. If it doesn't end up using the FBO then the effect is
10122 still able to continue the paint anyway. If there is no
10123 effect then this is equivalent to queuing a full redraw */
10124 _clutter_actor_queue_redraw_full (self,
10127 priv->flatten_effect);
10129 g_object_notify_by_pspec (G_OBJECT (self),
10130 obj_props[PROP_OFFSCREEN_REDIRECT]);
10135 * clutter_actor_get_offscreen_redirect:
10136 * @self: a #ClutterActor
10138 * Retrieves whether to redirect the actor to an offscreen buffer, as
10139 * set by clutter_actor_set_offscreen_redirect().
10141 * Return value: the value of the offscreen-redirect property of the actor
10145 ClutterOffscreenRedirect
10146 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10148 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10150 return self->priv->offscreen_redirect;
10154 * clutter_actor_set_name:
10155 * @self: A #ClutterActor
10156 * @name: Textual tag to apply to actor
10158 * Sets the given name to @self. The name can be used to identify
10162 clutter_actor_set_name (ClutterActor *self,
10165 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10167 g_free (self->priv->name);
10168 self->priv->name = g_strdup (name);
10170 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10174 * clutter_actor_get_name:
10175 * @self: A #ClutterActor
10177 * Retrieves the name of @self.
10179 * Return value: the name of the actor, or %NULL. The returned string is
10180 * owned by the actor and should not be modified or freed.
10183 clutter_actor_get_name (ClutterActor *self)
10185 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10187 return self->priv->name;
10191 * clutter_actor_get_gid:
10192 * @self: A #ClutterActor
10194 * Retrieves the unique id for @self.
10196 * Return value: Globally unique value for this object instance.
10200 * Deprecated: 1.8: The id is not used any longer.
10203 clutter_actor_get_gid (ClutterActor *self)
10205 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10207 return self->priv->id;
10211 clutter_actor_set_depth_internal (ClutterActor *self,
10214 ClutterTransformInfo *info;
10216 info = _clutter_actor_get_transform_info (self);
10218 if (info->depth != depth)
10220 /* Sets Z value - XXX 2.0: should we invert? */
10221 info->depth = depth;
10223 self->priv->transform_valid = FALSE;
10225 /* FIXME - remove this crap; sadly, there are still containers
10226 * in Clutter that depend on this utter brain damage
10228 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10230 clutter_actor_queue_redraw (self);
10232 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10237 * clutter_actor_set_depth:
10238 * @self: a #ClutterActor
10241 * Sets the Z coordinate of @self to @depth.
10243 * The unit used by @depth is dependant on the perspective setup. See
10244 * also clutter_stage_set_perspective().
10247 clutter_actor_set_depth (ClutterActor *self,
10250 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10252 if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10254 const ClutterTransformInfo *info;
10256 info = _clutter_actor_get_transform_info_or_defaults (self);
10258 _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10263 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10265 clutter_actor_queue_redraw (self);
10269 * clutter_actor_get_depth:
10270 * @self: a #ClutterActor
10272 * Retrieves the depth of @self.
10274 * Return value: the depth of the actor
10277 clutter_actor_get_depth (ClutterActor *self)
10279 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10281 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10285 * clutter_actor_set_rotation:
10286 * @self: a #ClutterActor
10287 * @axis: the axis of rotation
10288 * @angle: the angle of rotation
10289 * @x: X coordinate of the rotation center
10290 * @y: Y coordinate of the rotation center
10291 * @z: Z coordinate of the rotation center
10293 * Sets the rotation angle of @self around the given axis.
10295 * The rotation center coordinates used depend on the value of @axis:
10297 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10298 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10299 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10302 * The rotation coordinates are relative to the anchor point of the
10303 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10304 * point is set, the upper left corner is assumed as the origin.
10309 clutter_actor_set_rotation (ClutterActor *self,
10310 ClutterRotateAxis axis,
10318 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10324 g_object_freeze_notify (G_OBJECT (self));
10326 clutter_actor_set_rotation_angle (self, axis, angle);
10327 clutter_actor_set_rotation_center_internal (self, axis, &v);
10329 g_object_thaw_notify (G_OBJECT (self));
10333 * clutter_actor_set_z_rotation_from_gravity:
10334 * @self: a #ClutterActor
10335 * @angle: the angle of rotation
10336 * @gravity: the center point of the rotation
10338 * Sets the rotation angle of @self around the Z axis using the center
10339 * point specified as a compass point. For example to rotate such that
10340 * the center of the actor remains static you can use
10341 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10342 * will move accordingly.
10347 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10349 ClutterGravity gravity)
10351 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10353 if (gravity == CLUTTER_GRAVITY_NONE)
10354 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10357 GObject *obj = G_OBJECT (self);
10358 ClutterTransformInfo *info;
10360 info = _clutter_actor_get_transform_info (self);
10362 g_object_freeze_notify (obj);
10364 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10366 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10367 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10368 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10370 g_object_thaw_notify (obj);
10375 * clutter_actor_get_rotation:
10376 * @self: a #ClutterActor
10377 * @axis: the axis of rotation
10378 * @x: (out): return value for the X coordinate of the center of rotation
10379 * @y: (out): return value for the Y coordinate of the center of rotation
10380 * @z: (out): return value for the Z coordinate of the center of rotation
10382 * Retrieves the angle and center of rotation on the given axis,
10383 * set using clutter_actor_set_rotation().
10385 * Return value: the angle of rotation
10390 clutter_actor_get_rotation (ClutterActor *self,
10391 ClutterRotateAxis axis,
10396 const ClutterTransformInfo *info;
10397 const AnchorCoord *anchor_coord;
10398 gdouble retval = 0;
10400 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10402 info = _clutter_actor_get_transform_info_or_defaults (self);
10406 case CLUTTER_X_AXIS:
10407 anchor_coord = &info->rx_center;
10408 retval = info->rx_angle;
10411 case CLUTTER_Y_AXIS:
10412 anchor_coord = &info->ry_center;
10413 retval = info->ry_angle;
10416 case CLUTTER_Z_AXIS:
10417 anchor_coord = &info->rz_center;
10418 retval = info->rz_angle;
10422 anchor_coord = NULL;
10427 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10433 * clutter_actor_get_z_rotation_gravity:
10434 * @self: A #ClutterActor
10436 * Retrieves the center for the rotation around the Z axis as a
10437 * compass direction. If the center was specified in pixels or units
10438 * this will return %CLUTTER_GRAVITY_NONE.
10440 * Return value: the Z rotation center
10445 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10447 const ClutterTransformInfo *info;
10449 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10451 info = _clutter_actor_get_transform_info_or_defaults (self);
10453 return clutter_anchor_coord_get_gravity (&info->rz_center);
10457 * clutter_actor_set_clip:
10458 * @self: A #ClutterActor
10459 * @xoff: X offset of the clip rectangle
10460 * @yoff: Y offset of the clip rectangle
10461 * @width: Width of the clip rectangle
10462 * @height: Height of the clip rectangle
10464 * Sets clip area for @self. The clip area is always computed from the
10465 * upper left corner of the actor, even if the anchor point is set
10471 clutter_actor_set_clip (ClutterActor *self,
10477 ClutterActorPrivate *priv;
10479 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10483 if (priv->has_clip &&
10484 priv->clip.x == xoff &&
10485 priv->clip.y == yoff &&
10486 priv->clip.width == width &&
10487 priv->clip.height == height)
10490 priv->clip.x = xoff;
10491 priv->clip.y = yoff;
10492 priv->clip.width = width;
10493 priv->clip.height = height;
10495 priv->has_clip = TRUE;
10497 clutter_actor_queue_redraw (self);
10499 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10500 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10504 * clutter_actor_remove_clip:
10505 * @self: A #ClutterActor
10507 * Removes clip area from @self.
10510 clutter_actor_remove_clip (ClutterActor *self)
10512 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10514 if (!self->priv->has_clip)
10517 self->priv->has_clip = FALSE;
10519 clutter_actor_queue_redraw (self);
10521 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10525 * clutter_actor_has_clip:
10526 * @self: a #ClutterActor
10528 * Determines whether the actor has a clip area set or not.
10530 * Return value: %TRUE if the actor has a clip area set.
10535 clutter_actor_has_clip (ClutterActor *self)
10537 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10539 return self->priv->has_clip;
10543 * clutter_actor_get_clip:
10544 * @self: a #ClutterActor
10545 * @xoff: (out) (allow-none): return location for the X offset of
10546 * the clip rectangle, or %NULL
10547 * @yoff: (out) (allow-none): return location for the Y offset of
10548 * the clip rectangle, or %NULL
10549 * @width: (out) (allow-none): return location for the width of
10550 * the clip rectangle, or %NULL
10551 * @height: (out) (allow-none): return location for the height of
10552 * the clip rectangle, or %NULL
10554 * Gets the clip area for @self, if any is set
10559 clutter_actor_get_clip (ClutterActor *self,
10565 ClutterActorPrivate *priv;
10567 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10571 if (!priv->has_clip)
10575 *xoff = priv->clip.x;
10578 *yoff = priv->clip.y;
10581 *width = priv->clip.width;
10583 if (height != NULL)
10584 *height = priv->clip.height;
10588 * clutter_actor_get_children:
10589 * @self: a #ClutterActor
10591 * Retrieves the list of children of @self.
10593 * Return value: (transfer container) (element-type ClutterActor): A newly
10594 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10600 clutter_actor_get_children (ClutterActor *self)
10602 ClutterActor *iter;
10605 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10607 /* we walk the list backward so that we can use prepend(),
10610 for (iter = self->priv->last_child, res = NULL;
10612 iter = iter->priv->prev_sibling)
10614 res = g_list_prepend (res, iter);
10621 * insert_child_at_depth:
10622 * @self: a #ClutterActor
10623 * @child: a #ClutterActor
10625 * Inserts @child inside the list of children held by @self, using
10626 * the depth as the insertion criteria.
10628 * This sadly makes the insertion not O(1), but we can keep the
10629 * list sorted so that the painters algorithm we use for painting
10630 * the children will work correctly.
10633 insert_child_at_depth (ClutterActor *self,
10634 ClutterActor *child,
10635 gpointer dummy G_GNUC_UNUSED)
10637 ClutterActor *iter;
10640 child->priv->parent = self;
10643 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10645 /* special-case the first child */
10646 if (self->priv->n_children == 0)
10648 self->priv->first_child = child;
10649 self->priv->last_child = child;
10651 child->priv->next_sibling = NULL;
10652 child->priv->prev_sibling = NULL;
10657 /* Find the right place to insert the child so that it will still be
10658 sorted and the child will be after all of the actors at the same
10660 for (iter = self->priv->first_child;
10662 iter = iter->priv->next_sibling)
10667 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10669 if (iter_depth > child_depth)
10675 ClutterActor *tmp = iter->priv->prev_sibling;
10678 tmp->priv->next_sibling = child;
10680 /* Insert the node before the found one */
10681 child->priv->prev_sibling = iter->priv->prev_sibling;
10682 child->priv->next_sibling = iter;
10683 iter->priv->prev_sibling = child;
10687 ClutterActor *tmp = self->priv->last_child;
10690 tmp->priv->next_sibling = child;
10692 /* insert the node at the end of the list */
10693 child->priv->prev_sibling = self->priv->last_child;
10694 child->priv->next_sibling = NULL;
10697 if (child->priv->prev_sibling == NULL)
10698 self->priv->first_child = child;
10700 if (child->priv->next_sibling == NULL)
10701 self->priv->last_child = child;
10705 insert_child_at_index (ClutterActor *self,
10706 ClutterActor *child,
10709 gint index_ = GPOINTER_TO_INT (data_);
10711 child->priv->parent = self;
10715 ClutterActor *tmp = self->priv->first_child;
10718 tmp->priv->prev_sibling = child;
10720 child->priv->prev_sibling = NULL;
10721 child->priv->next_sibling = tmp;
10723 else if (index_ < 0 || index_ >= self->priv->n_children)
10725 ClutterActor *tmp = self->priv->last_child;
10728 tmp->priv->next_sibling = child;
10730 child->priv->prev_sibling = tmp;
10731 child->priv->next_sibling = NULL;
10735 ClutterActor *iter;
10738 for (iter = self->priv->first_child, i = 0;
10740 iter = iter->priv->next_sibling, i += 1)
10744 ClutterActor *tmp = iter->priv->prev_sibling;
10746 child->priv->prev_sibling = tmp;
10747 child->priv->next_sibling = iter;
10749 iter->priv->prev_sibling = child;
10752 tmp->priv->next_sibling = child;
10759 if (child->priv->prev_sibling == NULL)
10760 self->priv->first_child = child;
10762 if (child->priv->next_sibling == NULL)
10763 self->priv->last_child = child;
10767 insert_child_above (ClutterActor *self,
10768 ClutterActor *child,
10771 ClutterActor *sibling = data;
10773 child->priv->parent = self;
10775 if (sibling == NULL)
10776 sibling = self->priv->last_child;
10778 child->priv->prev_sibling = sibling;
10780 if (sibling != NULL)
10782 ClutterActor *tmp = sibling->priv->next_sibling;
10784 child->priv->next_sibling = tmp;
10787 tmp->priv->prev_sibling = child;
10789 sibling->priv->next_sibling = child;
10792 child->priv->next_sibling = NULL;
10794 if (child->priv->prev_sibling == NULL)
10795 self->priv->first_child = child;
10797 if (child->priv->next_sibling == NULL)
10798 self->priv->last_child = child;
10802 insert_child_below (ClutterActor *self,
10803 ClutterActor *child,
10806 ClutterActor *sibling = data;
10808 child->priv->parent = self;
10810 if (sibling == NULL)
10811 sibling = self->priv->first_child;
10813 child->priv->next_sibling = sibling;
10815 if (sibling != NULL)
10817 ClutterActor *tmp = sibling->priv->prev_sibling;
10819 child->priv->prev_sibling = tmp;
10822 tmp->priv->next_sibling = child;
10824 sibling->priv->prev_sibling = child;
10827 child->priv->prev_sibling = NULL;
10829 if (child->priv->prev_sibling == NULL)
10830 self->priv->first_child = child;
10832 if (child->priv->next_sibling == NULL)
10833 self->priv->last_child = child;
10836 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10837 ClutterActor *child,
10841 ADD_CHILD_CREATE_META = 1 << 0,
10842 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10843 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10844 ADD_CHILD_CHECK_STATE = 1 << 3,
10845 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10847 /* default flags for public API */
10848 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10849 ADD_CHILD_EMIT_PARENT_SET |
10850 ADD_CHILD_EMIT_ACTOR_ADDED |
10851 ADD_CHILD_CHECK_STATE |
10852 ADD_CHILD_NOTIFY_FIRST_LAST,
10854 /* flags for legacy/deprecated API */
10855 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10856 ADD_CHILD_CHECK_STATE |
10857 ADD_CHILD_NOTIFY_FIRST_LAST
10858 } ClutterActorAddChildFlags;
10861 * clutter_actor_add_child_internal:
10862 * @self: a #ClutterActor
10863 * @child: a #ClutterActor
10864 * @flags: control flags for actions
10865 * @add_func: delegate function
10866 * @data: (closure): data to pass to @add_func
10868 * Adds @child to the list of children of @self.
10870 * The actual insertion inside the list is delegated to @add_func: this
10871 * function will just set up the state, perform basic checks, and emit
10874 * The @flags argument is used to perform additional operations.
10877 clutter_actor_add_child_internal (ClutterActor *self,
10878 ClutterActor *child,
10879 ClutterActorAddChildFlags flags,
10880 ClutterActorAddChildFunc add_func,
10883 ClutterTextDirection text_dir;
10884 gboolean create_meta;
10885 gboolean emit_parent_set, emit_actor_added;
10886 gboolean check_state;
10887 gboolean notify_first_last;
10888 ClutterActor *old_first_child, *old_last_child;
10890 if (child->priv->parent != NULL)
10892 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10893 "use clutter_actor_remove_child() first.",
10894 _clutter_actor_get_debug_name (child),
10895 _clutter_actor_get_debug_name (child->priv->parent));
10899 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10901 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10902 "a child of another actor.",
10903 _clutter_actor_get_debug_name (child));
10908 /* XXX - this check disallows calling methods that change the stacking
10909 * order within the destruction sequence, by triggering a critical
10910 * warning first, and leaving the actor in an undefined state, which
10911 * then ends up being caught by an assertion.
10913 * the reproducible sequence is:
10915 * - actor gets destroyed;
10916 * - another actor, linked to the first, will try to change the
10917 * stacking order of the first actor;
10918 * - changing the stacking order is a composite operation composed
10919 * by the following steps:
10920 * 1. ref() the child;
10921 * 2. remove_child_internal(), which removes the reference;
10922 * 3. add_child_internal(), which adds a reference;
10923 * - the state of the actor is not changed between (2) and (3), as
10924 * it could be an expensive recomputation;
10925 * - if (3) bails out, then the actor is in an undefined state, but
10927 * - the destruction sequence terminates, but the actor is unparented
10928 * while its state indicates being parented instead.
10929 * - assertion failure.
10931 * the obvious fix would be to decompose each set_child_*_sibling()
10932 * method into proper remove_child()/add_child(), with state validation;
10933 * this may cause excessive work, though, and trigger a cascade of other
10934 * bugs in code that assumes that a change in the stacking order is an
10935 * atomic operation.
10937 * another potential fix is to just remove this check here, and let
10938 * code doing stacking order changes inside the destruction sequence
10939 * of an actor continue doing the work.
10941 * the third fix is to silently bail out early from every
10942 * set_child_*_sibling() and set_child_at_index() method, and avoid
10945 * I have a preference for the second solution, since it involves the
10946 * least amount of work, and the least amount of code duplication.
10948 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10950 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10952 g_warning ("The actor '%s' is currently being destroyed, and "
10953 "cannot be added as a child of another actor.",
10954 _clutter_actor_get_debug_name (child));
10959 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10960 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10961 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10962 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10963 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10965 old_first_child = self->priv->first_child;
10966 old_last_child = self->priv->last_child;
10968 g_object_freeze_notify (G_OBJECT (self));
10971 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10973 g_object_ref_sink (child);
10974 child->priv->parent = NULL;
10975 child->priv->next_sibling = NULL;
10976 child->priv->prev_sibling = NULL;
10978 /* delegate the actual insertion */
10979 add_func (self, child, data);
10981 g_assert (child->priv->parent == self);
10983 self->priv->n_children += 1;
10985 self->priv->age += 1;
10987 /* if push_internal() has been called then we automatically set
10988 * the flag on the actor
10990 if (self->priv->internal_child)
10991 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10993 /* clutter_actor_reparent() will emit ::parent-set for us */
10994 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10995 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10999 /* If parent is mapped or realized, we need to also be mapped or
11000 * realized once we're inside the parent.
11002 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11004 /* propagate the parent's text direction to the child */
11005 text_dir = clutter_actor_get_text_direction (self);
11006 clutter_actor_set_text_direction (child, text_dir);
11009 if (child->priv->show_on_set_parent)
11010 clutter_actor_show (child);
11012 if (CLUTTER_ACTOR_IS_MAPPED (child))
11013 clutter_actor_queue_redraw (child);
11015 /* maintain the invariant that if an actor needs layout,
11016 * its parents do as well
11018 if (child->priv->needs_width_request ||
11019 child->priv->needs_height_request ||
11020 child->priv->needs_allocation)
11022 /* we work around the short-circuiting we do
11023 * in clutter_actor_queue_relayout() since we
11024 * want to force a relayout
11026 child->priv->needs_width_request = TRUE;
11027 child->priv->needs_height_request = TRUE;
11028 child->priv->needs_allocation = TRUE;
11030 clutter_actor_queue_relayout (child->priv->parent);
11033 if (emit_actor_added)
11034 g_signal_emit_by_name (self, "actor-added", child);
11036 if (notify_first_last)
11038 if (old_first_child != self->priv->first_child)
11039 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11041 if (old_last_child != self->priv->last_child)
11042 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11045 g_object_thaw_notify (G_OBJECT (self));
11049 * clutter_actor_add_child:
11050 * @self: a #ClutterActor
11051 * @child: a #ClutterActor
11053 * Adds @child to the children of @self.
11055 * This function will acquire a reference on @child that will only
11056 * be released when calling clutter_actor_remove_child().
11058 * This function will take into consideration the #ClutterActor:depth
11059 * of @child, and will keep the list of children sorted.
11061 * This function will emit the #ClutterContainer::actor-added signal
11067 clutter_actor_add_child (ClutterActor *self,
11068 ClutterActor *child)
11070 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11071 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11072 g_return_if_fail (self != child);
11073 g_return_if_fail (child->priv->parent == NULL);
11075 clutter_actor_add_child_internal (self, child,
11076 ADD_CHILD_DEFAULT_FLAGS,
11077 insert_child_at_depth,
11082 * clutter_actor_insert_child_at_index:
11083 * @self: a #ClutterActor
11084 * @child: a #ClutterActor
11085 * @index_: the index
11087 * Inserts @child into the list of children of @self, using the
11088 * given @index_. If @index_ is greater than the number of children
11089 * in @self, or is less than 0, then the new child is added at the end.
11091 * This function will acquire a reference on @child that will only
11092 * be released when calling clutter_actor_remove_child().
11094 * This function will not take into consideration the #ClutterActor:depth
11097 * This function will emit the #ClutterContainer::actor-added signal
11103 clutter_actor_insert_child_at_index (ClutterActor *self,
11104 ClutterActor *child,
11107 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11108 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11109 g_return_if_fail (self != child);
11110 g_return_if_fail (child->priv->parent == NULL);
11112 clutter_actor_add_child_internal (self, child,
11113 ADD_CHILD_DEFAULT_FLAGS,
11114 insert_child_at_index,
11115 GINT_TO_POINTER (index_));
11119 * clutter_actor_insert_child_above:
11120 * @self: a #ClutterActor
11121 * @child: a #ClutterActor
11122 * @sibling: (allow-none): a child of @self, or %NULL
11124 * Inserts @child into the list of children of @self, above another
11125 * child of @self or, if @sibling is %NULL, above all the children
11128 * This function will acquire a reference on @child that will only
11129 * be released when calling clutter_actor_remove_child().
11131 * This function will not take into consideration the #ClutterActor:depth
11134 * This function will emit the #ClutterContainer::actor-added signal
11140 clutter_actor_insert_child_above (ClutterActor *self,
11141 ClutterActor *child,
11142 ClutterActor *sibling)
11144 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11145 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11146 g_return_if_fail (self != child);
11147 g_return_if_fail (child != sibling);
11148 g_return_if_fail (child->priv->parent == NULL);
11149 g_return_if_fail (sibling == NULL ||
11150 (CLUTTER_IS_ACTOR (sibling) &&
11151 sibling->priv->parent == self));
11153 clutter_actor_add_child_internal (self, child,
11154 ADD_CHILD_DEFAULT_FLAGS,
11155 insert_child_above,
11160 * clutter_actor_insert_child_below:
11161 * @self: a #ClutterActor
11162 * @child: a #ClutterActor
11163 * @sibling: (allow-none): a child of @self, or %NULL
11165 * Inserts @child into the list of children of @self, below another
11166 * child of @self or, if @sibling is %NULL, below all the children
11169 * This function will acquire a reference on @child that will only
11170 * be released when calling clutter_actor_remove_child().
11172 * This function will not take into consideration the #ClutterActor:depth
11175 * This function will emit the #ClutterContainer::actor-added signal
11181 clutter_actor_insert_child_below (ClutterActor *self,
11182 ClutterActor *child,
11183 ClutterActor *sibling)
11185 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11186 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11187 g_return_if_fail (self != child);
11188 g_return_if_fail (child != sibling);
11189 g_return_if_fail (child->priv->parent == NULL);
11190 g_return_if_fail (sibling == NULL ||
11191 (CLUTTER_IS_ACTOR (sibling) &&
11192 sibling->priv->parent == self));
11194 clutter_actor_add_child_internal (self, child,
11195 ADD_CHILD_DEFAULT_FLAGS,
11196 insert_child_below,
11201 * clutter_actor_set_parent:
11202 * @self: A #ClutterActor
11203 * @parent: A new #ClutterActor parent
11205 * Sets the parent of @self to @parent.
11207 * This function will result in @parent acquiring a reference on @self,
11208 * eventually by sinking its floating reference first. The reference
11209 * will be released by clutter_actor_unparent().
11211 * This function should only be called by legacy #ClutterActor<!-- -->s
11212 * implementing the #ClutterContainer interface.
11214 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11217 clutter_actor_set_parent (ClutterActor *self,
11218 ClutterActor *parent)
11220 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11221 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11222 g_return_if_fail (self != parent);
11223 g_return_if_fail (self->priv->parent == NULL);
11225 /* as this function will be called inside ClutterContainer::add
11226 * implementations or when building up a composite actor, we have
11227 * to preserve the old behaviour, and not create child meta or
11228 * emit the ::actor-added signal, to avoid recursion or double
11231 clutter_actor_add_child_internal (parent, self,
11232 ADD_CHILD_LEGACY_FLAGS,
11233 insert_child_at_depth,
11238 * clutter_actor_get_parent:
11239 * @self: A #ClutterActor
11241 * Retrieves the parent of @self.
11243 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11244 * if no parent is set
11247 clutter_actor_get_parent (ClutterActor *self)
11249 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11251 return self->priv->parent;
11255 * clutter_actor_get_paint_visibility:
11256 * @self: A #ClutterActor
11258 * Retrieves the 'paint' visibility of an actor recursively checking for non
11261 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11263 * Return Value: %TRUE if the actor is visibile and will be painted.
11268 clutter_actor_get_paint_visibility (ClutterActor *actor)
11270 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11272 return CLUTTER_ACTOR_IS_MAPPED (actor);
11276 * clutter_actor_remove_child:
11277 * @self: a #ClutterActor
11278 * @child: a #ClutterActor
11280 * Removes @child from the children of @self.
11282 * This function will release the reference added by
11283 * clutter_actor_add_child(), so if you want to keep using @child
11284 * you will have to acquire a referenced on it before calling this
11287 * This function will emit the #ClutterContainer::actor-removed
11293 clutter_actor_remove_child (ClutterActor *self,
11294 ClutterActor *child)
11296 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11297 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11298 g_return_if_fail (self != child);
11299 g_return_if_fail (child->priv->parent != NULL);
11300 g_return_if_fail (child->priv->parent == self);
11302 clutter_actor_remove_child_internal (self, child,
11303 REMOVE_CHILD_DEFAULT_FLAGS);
11307 * clutter_actor_remove_all_children:
11308 * @self: a #ClutterActor
11310 * Removes all children of @self.
11312 * This function releases the reference added by inserting a child actor
11313 * in the list of children of @self.
11315 * If the reference count of a child drops to zero, the child will be
11316 * destroyed. If you want to ensure the destruction of all the children
11317 * of @self, use clutter_actor_destroy_all_children().
11322 clutter_actor_remove_all_children (ClutterActor *self)
11324 ClutterActorIter iter;
11326 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11328 if (self->priv->n_children == 0)
11331 g_object_freeze_notify (G_OBJECT (self));
11333 clutter_actor_iter_init (&iter, self);
11334 while (clutter_actor_iter_next (&iter, NULL))
11335 clutter_actor_iter_remove (&iter);
11337 g_object_thaw_notify (G_OBJECT (self));
11340 g_assert (self->priv->first_child == NULL);
11341 g_assert (self->priv->last_child == NULL);
11342 g_assert (self->priv->n_children == 0);
11346 * clutter_actor_destroy_all_children:
11347 * @self: a #ClutterActor
11349 * Destroys all children of @self.
11351 * This function releases the reference added by inserting a child
11352 * actor in the list of children of @self, and ensures that the
11353 * #ClutterActor::destroy signal is emitted on each child of the
11356 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11357 * when its reference count drops to 0; the default handler of the
11358 * #ClutterActor::destroy signal will destroy all the children of an
11359 * actor. This function ensures that all children are destroyed, instead
11360 * of just removed from @self, unlike clutter_actor_remove_all_children()
11361 * which will merely release the reference and remove each child.
11363 * Unless you acquired an additional reference on each child of @self
11364 * prior to calling clutter_actor_remove_all_children() and want to reuse
11365 * the actors, you should use clutter_actor_destroy_all_children() in
11366 * order to make sure that children are destroyed and signal handlers
11367 * are disconnected even in cases where circular references prevent this
11368 * from automatically happening through reference counting alone.
11373 clutter_actor_destroy_all_children (ClutterActor *self)
11375 ClutterActorIter iter;
11377 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11379 if (self->priv->n_children == 0)
11382 g_object_freeze_notify (G_OBJECT (self));
11384 clutter_actor_iter_init (&iter, self);
11385 while (clutter_actor_iter_next (&iter, NULL))
11386 clutter_actor_iter_destroy (&iter);
11388 g_object_thaw_notify (G_OBJECT (self));
11391 g_assert (self->priv->first_child == NULL);
11392 g_assert (self->priv->last_child == NULL);
11393 g_assert (self->priv->n_children == 0);
11396 typedef struct _InsertBetweenData {
11397 ClutterActor *prev_sibling;
11398 ClutterActor *next_sibling;
11399 } InsertBetweenData;
11402 insert_child_between (ClutterActor *self,
11403 ClutterActor *child,
11406 InsertBetweenData *data = data_;
11407 ClutterActor *prev_sibling = data->prev_sibling;
11408 ClutterActor *next_sibling = data->next_sibling;
11410 child->priv->parent = self;
11411 child->priv->prev_sibling = prev_sibling;
11412 child->priv->next_sibling = next_sibling;
11414 if (prev_sibling != NULL)
11415 prev_sibling->priv->next_sibling = child;
11417 if (next_sibling != NULL)
11418 next_sibling->priv->prev_sibling = child;
11420 if (child->priv->prev_sibling == NULL)
11421 self->priv->first_child = child;
11423 if (child->priv->next_sibling == NULL)
11424 self->priv->last_child = child;
11428 * clutter_actor_replace_child:
11429 * @self: a #ClutterActor
11430 * @old_child: the child of @self to replace
11431 * @new_child: the #ClutterActor to replace @old_child
11433 * Replaces @old_child with @new_child in the list of children of @self.
11438 clutter_actor_replace_child (ClutterActor *self,
11439 ClutterActor *old_child,
11440 ClutterActor *new_child)
11442 ClutterActor *prev_sibling, *next_sibling;
11443 InsertBetweenData clos;
11445 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11446 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11447 g_return_if_fail (old_child->priv->parent == self);
11448 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11449 g_return_if_fail (old_child != new_child);
11450 g_return_if_fail (new_child != self);
11451 g_return_if_fail (new_child->priv->parent == NULL);
11453 prev_sibling = old_child->priv->prev_sibling;
11454 next_sibling = old_child->priv->next_sibling;
11455 clutter_actor_remove_child_internal (self, old_child,
11456 REMOVE_CHILD_DEFAULT_FLAGS);
11458 clos.prev_sibling = prev_sibling;
11459 clos.next_sibling = next_sibling;
11460 clutter_actor_add_child_internal (self, new_child,
11461 ADD_CHILD_DEFAULT_FLAGS,
11462 insert_child_between,
11467 * clutter_actor_unparent:
11468 * @self: a #ClutterActor
11470 * Removes the parent of @self.
11472 * This will cause the parent of @self to release the reference
11473 * acquired when calling clutter_actor_set_parent(), so if you
11474 * want to keep @self you will have to acquire a reference of
11475 * your own, through g_object_ref().
11477 * This function should only be called by legacy #ClutterActor<!-- -->s
11478 * implementing the #ClutterContainer interface.
11482 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11485 clutter_actor_unparent (ClutterActor *self)
11487 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11489 if (self->priv->parent == NULL)
11492 clutter_actor_remove_child_internal (self->priv->parent, self,
11493 REMOVE_CHILD_LEGACY_FLAGS);
11497 * clutter_actor_reparent:
11498 * @self: a #ClutterActor
11499 * @new_parent: the new #ClutterActor parent
11501 * Resets the parent actor of @self.
11503 * This function is logically equivalent to calling clutter_actor_unparent()
11504 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11505 * ensures the child is not finalized when unparented, and emits the
11506 * #ClutterActor::parent-set signal only once.
11508 * In reality, calling this function is less useful than it sounds, as some
11509 * application code may rely on changes in the intermediate state between
11510 * removal and addition of the actor from its old parent to the @new_parent.
11511 * Thus, it is strongly encouraged to avoid using this function in application
11516 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11517 * clutter_actor_add_child() instead; remember to take a reference on
11518 * the actor being removed before calling clutter_actor_remove_child()
11519 * to avoid the reference count dropping to zero and the actor being
11523 clutter_actor_reparent (ClutterActor *self,
11524 ClutterActor *new_parent)
11526 ClutterActorPrivate *priv;
11528 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11529 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11530 g_return_if_fail (self != new_parent);
11532 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11534 g_warning ("Cannot set a parent on a toplevel actor");
11538 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11540 g_warning ("Cannot set a parent currently being destroyed");
11546 if (priv->parent != new_parent)
11548 ClutterActor *old_parent;
11550 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11552 old_parent = priv->parent;
11554 g_object_ref (self);
11556 if (old_parent != NULL)
11558 /* go through the Container implementation if this is a regular
11559 * child and not an internal one
11561 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11563 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11565 /* this will have to call unparent() */
11566 clutter_container_remove_actor (parent, self);
11569 clutter_actor_remove_child_internal (old_parent, self,
11570 REMOVE_CHILD_LEGACY_FLAGS);
11573 /* Note, will call set_parent() */
11574 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11575 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11577 clutter_actor_add_child_internal (new_parent, self,
11578 ADD_CHILD_LEGACY_FLAGS,
11579 insert_child_at_depth,
11582 /* we emit the ::parent-set signal once */
11583 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11585 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11587 /* the IN_REPARENT flag suspends state updates */
11588 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11590 g_object_unref (self);
11595 * clutter_actor_contains:
11596 * @self: A #ClutterActor
11597 * @descendant: A #ClutterActor, possibly contained in @self
11599 * Determines if @descendant is contained inside @self (either as an
11600 * immediate child, or as a deeper descendant). If @self and
11601 * @descendant point to the same actor then it will also return %TRUE.
11603 * Return value: whether @descendent is contained within @self
11608 clutter_actor_contains (ClutterActor *self,
11609 ClutterActor *descendant)
11611 ClutterActor *actor;
11613 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11614 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11616 for (actor = descendant; actor; actor = actor->priv->parent)
11624 * clutter_actor_set_child_above_sibling:
11625 * @self: a #ClutterActor
11626 * @child: a #ClutterActor child of @self
11627 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11629 * Sets @child to be above @sibling in the list of children of @self.
11631 * If @sibling is %NULL, @child will be the new last child of @self.
11633 * This function is logically equivalent to removing @child and using
11634 * clutter_actor_insert_child_above(), but it will not emit signals
11635 * or change state on @child.
11640 clutter_actor_set_child_above_sibling (ClutterActor *self,
11641 ClutterActor *child,
11642 ClutterActor *sibling)
11644 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11645 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11646 g_return_if_fail (child->priv->parent == self);
11647 g_return_if_fail (child != sibling);
11648 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11650 if (sibling != NULL)
11651 g_return_if_fail (sibling->priv->parent == self);
11653 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11654 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11655 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11658 /* we don't want to change the state of child, or emit signals, or
11659 * regenerate ChildMeta instances here, but we still want to follow
11660 * the correct sequence of steps encoded in remove_child() and
11661 * add_child(), so that correctness is ensured, and we only go
11662 * through one known code path.
11664 g_object_ref (child);
11665 clutter_actor_remove_child_internal (self, child, 0);
11666 clutter_actor_add_child_internal (self, child,
11667 ADD_CHILD_NOTIFY_FIRST_LAST,
11668 insert_child_above,
11671 clutter_actor_queue_relayout (self);
11675 * clutter_actor_set_child_below_sibling:
11676 * @self: a #ClutterActor
11677 * @child: a #ClutterActor child of @self
11678 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11680 * Sets @child to be below @sibling in the list of children of @self.
11682 * If @sibling is %NULL, @child will be the new first child of @self.
11684 * This function is logically equivalent to removing @self and using
11685 * clutter_actor_insert_child_below(), but it will not emit signals
11686 * or change state on @child.
11691 clutter_actor_set_child_below_sibling (ClutterActor *self,
11692 ClutterActor *child,
11693 ClutterActor *sibling)
11695 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11696 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11697 g_return_if_fail (child->priv->parent == self);
11698 g_return_if_fail (child != sibling);
11699 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11701 if (sibling != NULL)
11702 g_return_if_fail (sibling->priv->parent == self);
11704 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11705 CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11706 (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11709 /* see the comment in set_child_above_sibling() */
11710 g_object_ref (child);
11711 clutter_actor_remove_child_internal (self, child, 0);
11712 clutter_actor_add_child_internal (self, child,
11713 ADD_CHILD_NOTIFY_FIRST_LAST,
11714 insert_child_below,
11717 clutter_actor_queue_relayout (self);
11721 * clutter_actor_set_child_at_index:
11722 * @self: a #ClutterActor
11723 * @child: a #ClutterActor child of @self
11724 * @index_: the new index for @child
11726 * Changes the index of @child in the list of children of @self.
11728 * This function is logically equivalent to removing @child and
11729 * calling clutter_actor_insert_child_at_index(), but it will not
11730 * emit signals or change state on @child.
11735 clutter_actor_set_child_at_index (ClutterActor *self,
11736 ClutterActor *child,
11739 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11740 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11741 g_return_if_fail (child->priv->parent == self);
11742 g_return_if_fail (index_ <= self->priv->n_children);
11744 if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11745 CLUTTER_ACTOR_IN_DESTRUCTION (child))
11748 g_object_ref (child);
11749 clutter_actor_remove_child_internal (self, child, 0);
11750 clutter_actor_add_child_internal (self, child,
11751 ADD_CHILD_NOTIFY_FIRST_LAST,
11752 insert_child_at_index,
11753 GINT_TO_POINTER (index_));
11755 clutter_actor_queue_relayout (self);
11759 * clutter_actor_raise:
11760 * @self: A #ClutterActor
11761 * @below: (allow-none): A #ClutterActor to raise above.
11763 * Puts @self above @below.
11765 * Both actors must have the same parent, and the parent must implement
11766 * the #ClutterContainer interface
11768 * This function calls clutter_container_raise_child() internally.
11770 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11773 clutter_actor_raise (ClutterActor *self,
11774 ClutterActor *below)
11776 ClutterActor *parent;
11778 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11780 parent = clutter_actor_get_parent (self);
11781 if (parent == NULL)
11783 g_warning ("%s: Actor '%s' is not inside a container",
11785 _clutter_actor_get_debug_name (self));
11791 if (parent != clutter_actor_get_parent (below))
11793 g_warning ("%s Actor '%s' is not in the same container as "
11796 _clutter_actor_get_debug_name (self),
11797 _clutter_actor_get_debug_name (below));
11802 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11806 * clutter_actor_lower:
11807 * @self: A #ClutterActor
11808 * @above: (allow-none): A #ClutterActor to lower below
11810 * Puts @self below @above.
11812 * Both actors must have the same parent, and the parent must implement
11813 * the #ClutterContainer interface.
11815 * This function calls clutter_container_lower_child() internally.
11817 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11820 clutter_actor_lower (ClutterActor *self,
11821 ClutterActor *above)
11823 ClutterActor *parent;
11825 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11827 parent = clutter_actor_get_parent (self);
11828 if (parent == NULL)
11830 g_warning ("%s: Actor of type %s is not inside a container",
11832 _clutter_actor_get_debug_name (self));
11838 if (parent != clutter_actor_get_parent (above))
11840 g_warning ("%s: Actor '%s' is not in the same container as "
11843 _clutter_actor_get_debug_name (self),
11844 _clutter_actor_get_debug_name (above));
11849 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11853 * clutter_actor_raise_top:
11854 * @self: A #ClutterActor
11856 * Raises @self to the top.
11858 * This function calls clutter_actor_raise() internally.
11860 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11861 * a %NULL sibling, instead.
11864 clutter_actor_raise_top (ClutterActor *self)
11866 clutter_actor_raise (self, NULL);
11870 * clutter_actor_lower_bottom:
11871 * @self: A #ClutterActor
11873 * Lowers @self to the bottom.
11875 * This function calls clutter_actor_lower() internally.
11877 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11878 * a %NULL sibling, instead.
11881 clutter_actor_lower_bottom (ClutterActor *self)
11883 clutter_actor_lower (self, NULL);
11891 * clutter_actor_event:
11892 * @actor: a #ClutterActor
11893 * @event: a #ClutterEvent
11894 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11896 * This function is used to emit an event on the main stage.
11897 * You should rarely need to use this function, except for
11898 * synthetising events.
11900 * Return value: the return value from the signal emission: %TRUE
11901 * if the actor handled the event, or %FALSE if the event was
11907 clutter_actor_event (ClutterActor *actor,
11908 ClutterEvent *event,
11911 gboolean retval = FALSE;
11912 gint signal_num = -1;
11914 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11915 g_return_val_if_fail (event != NULL, FALSE);
11917 g_object_ref (actor);
11921 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11927 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11931 switch (event->type)
11933 case CLUTTER_NOTHING:
11935 case CLUTTER_BUTTON_PRESS:
11936 signal_num = BUTTON_PRESS_EVENT;
11938 case CLUTTER_BUTTON_RELEASE:
11939 signal_num = BUTTON_RELEASE_EVENT;
11941 case CLUTTER_SCROLL:
11942 signal_num = SCROLL_EVENT;
11944 case CLUTTER_KEY_PRESS:
11945 signal_num = KEY_PRESS_EVENT;
11947 case CLUTTER_KEY_RELEASE:
11948 signal_num = KEY_RELEASE_EVENT;
11950 case CLUTTER_MOTION:
11951 signal_num = MOTION_EVENT;
11953 case CLUTTER_ENTER:
11954 signal_num = ENTER_EVENT;
11956 case CLUTTER_LEAVE:
11957 signal_num = LEAVE_EVENT;
11959 case CLUTTER_DELETE:
11960 case CLUTTER_DESTROY_NOTIFY:
11961 case CLUTTER_CLIENT_MESSAGE:
11967 if (signal_num != -1)
11968 g_signal_emit (actor, actor_signals[signal_num], 0,
11973 g_object_unref (actor);
11979 * clutter_actor_set_reactive:
11980 * @actor: a #ClutterActor
11981 * @reactive: whether the actor should be reactive to events
11983 * Sets @actor as reactive. Reactive actors will receive events.
11988 clutter_actor_set_reactive (ClutterActor *actor,
11991 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11993 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11997 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11999 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12001 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12005 * clutter_actor_get_reactive:
12006 * @actor: a #ClutterActor
12008 * Checks whether @actor is marked as reactive.
12010 * Return value: %TRUE if the actor is reactive
12015 clutter_actor_get_reactive (ClutterActor *actor)
12017 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12019 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12023 * clutter_actor_get_anchor_point:
12024 * @self: a #ClutterActor
12025 * @anchor_x: (out): return location for the X coordinate of the anchor point
12026 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12028 * Gets the current anchor point of the @actor in pixels.
12033 clutter_actor_get_anchor_point (ClutterActor *self,
12037 const ClutterTransformInfo *info;
12039 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12041 info = _clutter_actor_get_transform_info_or_defaults (self);
12042 clutter_anchor_coord_get_units (self, &info->anchor,
12049 * clutter_actor_set_anchor_point:
12050 * @self: a #ClutterActor
12051 * @anchor_x: X coordinate of the anchor point
12052 * @anchor_y: Y coordinate of the anchor point
12054 * Sets an anchor point for @self. The anchor point is a point in the
12055 * coordinate space of an actor to which the actor position within its
12056 * parent is relative; the default is (0, 0), i.e. the top-left corner
12062 clutter_actor_set_anchor_point (ClutterActor *self,
12066 ClutterTransformInfo *info;
12067 ClutterActorPrivate *priv;
12068 gboolean changed = FALSE;
12069 gfloat old_anchor_x, old_anchor_y;
12072 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12074 obj = G_OBJECT (self);
12076 info = _clutter_actor_get_transform_info (self);
12078 g_object_freeze_notify (obj);
12080 clutter_anchor_coord_get_units (self, &info->anchor,
12085 if (info->anchor.is_fractional)
12086 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12088 if (old_anchor_x != anchor_x)
12090 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12094 if (old_anchor_y != anchor_y)
12096 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12100 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12104 priv->transform_valid = FALSE;
12105 clutter_actor_queue_redraw (self);
12108 g_object_thaw_notify (obj);
12112 * clutter_actor_get_anchor_point_gravity:
12113 * @self: a #ClutterActor
12115 * Retrieves the anchor position expressed as a #ClutterGravity. If
12116 * the anchor point was specified using pixels or units this will
12117 * return %CLUTTER_GRAVITY_NONE.
12119 * Return value: the #ClutterGravity used by the anchor point
12124 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12126 const ClutterTransformInfo *info;
12128 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12130 info = _clutter_actor_get_transform_info_or_defaults (self);
12132 return clutter_anchor_coord_get_gravity (&info->anchor);
12136 * clutter_actor_move_anchor_point:
12137 * @self: a #ClutterActor
12138 * @anchor_x: X coordinate of the anchor point
12139 * @anchor_y: Y coordinate of the anchor point
12141 * Sets an anchor point for the actor, and adjusts the actor postion so that
12142 * the relative position of the actor toward its parent remains the same.
12147 clutter_actor_move_anchor_point (ClutterActor *self,
12151 gfloat old_anchor_x, old_anchor_y;
12152 const ClutterTransformInfo *info;
12154 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12156 info = _clutter_actor_get_transform_info (self);
12157 clutter_anchor_coord_get_units (self, &info->anchor,
12162 g_object_freeze_notify (G_OBJECT (self));
12164 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12166 if (self->priv->position_set)
12167 clutter_actor_move_by (self,
12168 anchor_x - old_anchor_x,
12169 anchor_y - old_anchor_y);
12171 g_object_thaw_notify (G_OBJECT (self));
12175 * clutter_actor_move_anchor_point_from_gravity:
12176 * @self: a #ClutterActor
12177 * @gravity: #ClutterGravity.
12179 * Sets an anchor point on the actor based on the given gravity, adjusting the
12180 * actor postion so that its relative position within its parent remains
12183 * Since version 1.0 the anchor point will be stored as a gravity so
12184 * that if the actor changes size then the anchor point will move. For
12185 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12186 * and later double the size of the actor, the anchor point will move
12187 * to the bottom right.
12192 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12193 ClutterGravity gravity)
12195 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12196 const ClutterTransformInfo *info;
12197 ClutterActorPrivate *priv;
12199 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12202 info = _clutter_actor_get_transform_info (self);
12204 g_object_freeze_notify (G_OBJECT (self));
12206 clutter_anchor_coord_get_units (self, &info->anchor,
12210 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12211 clutter_anchor_coord_get_units (self, &info->anchor,
12216 if (priv->position_set)
12217 clutter_actor_move_by (self,
12218 new_anchor_x - old_anchor_x,
12219 new_anchor_y - old_anchor_y);
12221 g_object_thaw_notify (G_OBJECT (self));
12225 * clutter_actor_set_anchor_point_from_gravity:
12226 * @self: a #ClutterActor
12227 * @gravity: #ClutterGravity.
12229 * Sets an anchor point on the actor, based on the given gravity (this is a
12230 * convenience function wrapping clutter_actor_set_anchor_point()).
12232 * Since version 1.0 the anchor point will be stored as a gravity so
12233 * that if the actor changes size then the anchor point will move. For
12234 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12235 * and later double the size of the actor, the anchor point will move
12236 * to the bottom right.
12241 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12242 ClutterGravity gravity)
12244 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12246 if (gravity == CLUTTER_GRAVITY_NONE)
12247 clutter_actor_set_anchor_point (self, 0, 0);
12250 GObject *obj = G_OBJECT (self);
12251 ClutterTransformInfo *info;
12253 g_object_freeze_notify (obj);
12255 info = _clutter_actor_get_transform_info (self);
12256 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12258 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12259 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12260 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12262 self->priv->transform_valid = FALSE;
12264 clutter_actor_queue_redraw (self);
12266 g_object_thaw_notify (obj);
12271 clutter_container_iface_init (ClutterContainerIface *iface)
12273 /* we don't override anything, as ClutterContainer already has a default
12274 * implementation that we can use, and which calls into our own API.
12289 parse_units (ClutterActor *self,
12290 ParseDimension dimension,
12293 GValue value = G_VALUE_INIT;
12296 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12299 json_node_get_value (node, &value);
12301 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12303 retval = (gfloat) g_value_get_int64 (&value);
12305 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12307 retval = g_value_get_double (&value);
12309 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12311 ClutterUnits units;
12314 res = clutter_units_from_string (&units, g_value_get_string (&value));
12316 retval = clutter_units_to_pixels (&units);
12319 g_warning ("Invalid value '%s': integers, strings or floating point "
12320 "values can be used for the x, y, width and height "
12321 "properties. Valid modifiers for strings are 'px', 'mm', "
12323 g_value_get_string (&value));
12329 g_warning ("Invalid value of type '%s': integers, strings of floating "
12330 "point values can be used for the x, y, width, height "
12331 "anchor-x and anchor-y properties.",
12332 g_type_name (G_VALUE_TYPE (&value)));
12335 g_value_unset (&value);
12341 ClutterRotateAxis axis;
12350 static inline gboolean
12351 parse_rotation_array (ClutterActor *actor,
12353 RotationInfo *info)
12357 if (json_array_get_length (array) != 2)
12361 element = json_array_get_element (array, 0);
12362 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12363 info->angle = json_node_get_double (element);
12368 element = json_array_get_element (array, 1);
12369 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12371 JsonArray *center = json_node_get_array (element);
12373 if (json_array_get_length (center) != 2)
12376 switch (info->axis)
12378 case CLUTTER_X_AXIS:
12379 info->center_y = parse_units (actor, PARSE_Y,
12380 json_array_get_element (center, 0));
12381 info->center_z = parse_units (actor, PARSE_Y,
12382 json_array_get_element (center, 1));
12385 case CLUTTER_Y_AXIS:
12386 info->center_x = parse_units (actor, PARSE_X,
12387 json_array_get_element (center, 0));
12388 info->center_z = parse_units (actor, PARSE_X,
12389 json_array_get_element (center, 1));
12392 case CLUTTER_Z_AXIS:
12393 info->center_x = parse_units (actor, PARSE_X,
12394 json_array_get_element (center, 0));
12395 info->center_y = parse_units (actor, PARSE_Y,
12396 json_array_get_element (center, 1));
12405 parse_rotation (ClutterActor *actor,
12407 RotationInfo *info)
12411 gboolean retval = FALSE;
12413 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12415 g_warning ("Invalid node of type '%s' found, expecting an array",
12416 json_node_type_name (node));
12420 array = json_node_get_array (node);
12421 len = json_array_get_length (array);
12423 for (i = 0; i < len; i++)
12425 JsonNode *element = json_array_get_element (array, i);
12426 JsonObject *object;
12429 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12431 g_warning ("Invalid node of type '%s' found, expecting an object",
12432 json_node_type_name (element));
12436 object = json_node_get_object (element);
12438 if (json_object_has_member (object, "x-axis"))
12440 member = json_object_get_member (object, "x-axis");
12442 info->axis = CLUTTER_X_AXIS;
12444 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12446 info->angle = json_node_get_double (member);
12449 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12450 retval = parse_rotation_array (actor,
12451 json_node_get_array (member),
12456 else if (json_object_has_member (object, "y-axis"))
12458 member = json_object_get_member (object, "y-axis");
12460 info->axis = CLUTTER_Y_AXIS;
12462 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12464 info->angle = json_node_get_double (member);
12467 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12468 retval = parse_rotation_array (actor,
12469 json_node_get_array (member),
12474 else if (json_object_has_member (object, "z-axis"))
12476 member = json_object_get_member (object, "z-axis");
12478 info->axis = CLUTTER_Z_AXIS;
12480 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12482 info->angle = json_node_get_double (member);
12485 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12486 retval = parse_rotation_array (actor,
12487 json_node_get_array (member),
12498 parse_actor_metas (ClutterScript *script,
12499 ClutterActor *actor,
12502 GList *elements, *l;
12503 GSList *retval = NULL;
12505 if (!JSON_NODE_HOLDS_ARRAY (node))
12508 elements = json_array_get_elements (json_node_get_array (node));
12510 for (l = elements; l != NULL; l = l->next)
12512 JsonNode *element = l->data;
12513 const gchar *id_ = _clutter_script_get_id_from_node (element);
12516 if (id_ == NULL || *id_ == '\0')
12519 meta = clutter_script_get_object (script, id_);
12523 retval = g_slist_prepend (retval, meta);
12526 g_list_free (elements);
12528 return g_slist_reverse (retval);
12532 parse_behaviours (ClutterScript *script,
12533 ClutterActor *actor,
12536 GList *elements, *l;
12537 GSList *retval = NULL;
12539 if (!JSON_NODE_HOLDS_ARRAY (node))
12542 elements = json_array_get_elements (json_node_get_array (node));
12544 for (l = elements; l != NULL; l = l->next)
12546 JsonNode *element = l->data;
12547 const gchar *id_ = _clutter_script_get_id_from_node (element);
12548 GObject *behaviour;
12550 if (id_ == NULL || *id_ == '\0')
12553 behaviour = clutter_script_get_object (script, id_);
12554 if (behaviour == NULL)
12557 retval = g_slist_prepend (retval, behaviour);
12560 g_list_free (elements);
12562 return g_slist_reverse (retval);
12566 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12567 ClutterScript *script,
12572 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12573 gboolean retval = FALSE;
12575 if ((name[0] == 'x' && name[1] == '\0') ||
12576 (name[0] == 'y' && name[1] == '\0') ||
12577 (strcmp (name, "width") == 0) ||
12578 (strcmp (name, "height") == 0) ||
12579 (strcmp (name, "anchor_x") == 0) ||
12580 (strcmp (name, "anchor_y") == 0))
12582 ParseDimension dimension;
12585 if (name[0] == 'x')
12586 dimension = PARSE_X;
12587 else if (name[0] == 'y')
12588 dimension = PARSE_Y;
12589 else if (name[0] == 'w')
12590 dimension = PARSE_WIDTH;
12591 else if (name[0] == 'h')
12592 dimension = PARSE_HEIGHT;
12593 else if (name[0] == 'a' && name[7] == 'x')
12594 dimension = PARSE_ANCHOR_X;
12595 else if (name[0] == 'a' && name[7] == 'y')
12596 dimension = PARSE_ANCHOR_Y;
12600 units = parse_units (actor, dimension, node);
12602 /* convert back to pixels: all properties are pixel-based */
12603 g_value_init (value, G_TYPE_FLOAT);
12604 g_value_set_float (value, units);
12608 else if (strcmp (name, "rotation") == 0)
12610 RotationInfo *info;
12612 info = g_slice_new0 (RotationInfo);
12613 retval = parse_rotation (actor, node, info);
12617 g_value_init (value, G_TYPE_POINTER);
12618 g_value_set_pointer (value, info);
12621 g_slice_free (RotationInfo, info);
12623 else if (strcmp (name, "behaviours") == 0)
12627 #ifdef CLUTTER_ENABLE_DEBUG
12628 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12629 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12630 "and it should not be used in newly "
12631 "written ClutterScript definitions.");
12634 l = parse_behaviours (script, actor, node);
12636 g_value_init (value, G_TYPE_POINTER);
12637 g_value_set_pointer (value, l);
12641 else if (strcmp (name, "actions") == 0 ||
12642 strcmp (name, "constraints") == 0 ||
12643 strcmp (name, "effects") == 0)
12647 l = parse_actor_metas (script, actor, node);
12649 g_value_init (value, G_TYPE_POINTER);
12650 g_value_set_pointer (value, l);
12659 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12660 ClutterScript *script,
12662 const GValue *value)
12664 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12666 #ifdef CLUTTER_ENABLE_DEBUG
12667 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12669 gchar *tmp = g_strdup_value_contents (value);
12671 CLUTTER_NOTE (SCRIPT,
12672 "in ClutterActor::set_custom_property('%s') = %s",
12678 #endif /* CLUTTER_ENABLE_DEBUG */
12680 if (strcmp (name, "rotation") == 0)
12682 RotationInfo *info;
12684 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12687 info = g_value_get_pointer (value);
12689 clutter_actor_set_rotation (actor,
12690 info->axis, info->angle,
12695 g_slice_free (RotationInfo, info);
12700 if (strcmp (name, "behaviours") == 0)
12702 GSList *behaviours, *l;
12704 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12707 behaviours = g_value_get_pointer (value);
12708 for (l = behaviours; l != NULL; l = l->next)
12710 ClutterBehaviour *behaviour = l->data;
12712 clutter_behaviour_apply (behaviour, actor);
12715 g_slist_free (behaviours);
12720 if (strcmp (name, "actions") == 0 ||
12721 strcmp (name, "constraints") == 0 ||
12722 strcmp (name, "effects") == 0)
12726 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12729 metas = g_value_get_pointer (value);
12730 for (l = metas; l != NULL; l = l->next)
12732 if (name[0] == 'a')
12733 clutter_actor_add_action (actor, l->data);
12735 if (name[0] == 'c')
12736 clutter_actor_add_constraint (actor, l->data);
12738 if (name[0] == 'e')
12739 clutter_actor_add_effect (actor, l->data);
12742 g_slist_free (metas);
12747 g_object_set_property (G_OBJECT (scriptable), name, value);
12751 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12753 iface->parse_custom_node = clutter_actor_parse_custom_node;
12754 iface->set_custom_property = clutter_actor_set_custom_property;
12757 static ClutterActorMeta *
12758 get_meta_from_animation_property (ClutterActor *actor,
12762 ClutterActorPrivate *priv = actor->priv;
12763 ClutterActorMeta *meta = NULL;
12766 /* if this is not a special property, fall through */
12767 if (name[0] != '@')
12770 /* detect the properties named using the following spec:
12772 * @<section>.<meta-name>.<property-name>
12774 * where <section> can be one of the following:
12780 * and <meta-name> is the name set on a specific ActorMeta
12783 tokens = g_strsplit (name + 1, ".", -1);
12784 if (tokens == NULL || g_strv_length (tokens) != 3)
12786 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12788 g_strfreev (tokens);
12792 if (strcmp (tokens[0], "actions") == 0)
12793 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12795 if (strcmp (tokens[0], "constraints") == 0)
12796 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12798 if (strcmp (tokens[0], "effects") == 0)
12799 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12801 if (name_p != NULL)
12802 *name_p = g_strdup (tokens[2]);
12804 CLUTTER_NOTE (ANIMATION,
12805 "Looking for property '%s' of object '%s' in section '%s'",
12810 g_strfreev (tokens);
12815 static GParamSpec *
12816 clutter_actor_find_property (ClutterAnimatable *animatable,
12817 const gchar *property_name)
12819 ClutterActorMeta *meta = NULL;
12820 GObjectClass *klass = NULL;
12821 GParamSpec *pspec = NULL;
12822 gchar *p_name = NULL;
12824 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12830 klass = G_OBJECT_GET_CLASS (meta);
12832 pspec = g_object_class_find_property (klass, p_name);
12836 klass = G_OBJECT_GET_CLASS (animatable);
12838 pspec = g_object_class_find_property (klass, property_name);
12847 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12848 const gchar *property_name,
12851 ClutterActorMeta *meta = NULL;
12852 gchar *p_name = NULL;
12854 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12859 g_object_get_property (G_OBJECT (meta), p_name, initial);
12861 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12867 * clutter_actor_set_animatable_property:
12868 * @actor: a #ClutterActor
12869 * @prop_id: the paramspec id
12870 * @value: the value to set
12871 * @pspec: the paramspec
12873 * Sets values of animatable properties.
12875 * This is a variant of clutter_actor_set_property() that gets called
12876 * by the #ClutterAnimatable implementation of #ClutterActor for the
12877 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12880 * Unlike the implementation of #GObjectClass.set_property(), this
12881 * function will not update the interval if a transition involving an
12882 * animatable property is in progress - this avoids cycles with the
12883 * transition API calling the public API.
12886 clutter_actor_set_animatable_property (ClutterActor *actor,
12888 const GValue *value,
12891 GObject *obj = G_OBJECT (actor);
12893 g_object_freeze_notify (obj);
12898 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12902 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12906 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12910 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12914 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12918 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12921 case PROP_BACKGROUND_COLOR:
12922 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12926 clutter_actor_set_scale_factor_internal (actor,
12927 g_value_get_double (value),
12932 clutter_actor_set_scale_factor_internal (actor,
12933 g_value_get_double (value),
12937 case PROP_ROTATION_ANGLE_X:
12938 clutter_actor_set_rotation_angle_internal (actor,
12940 g_value_get_double (value));
12943 case PROP_ROTATION_ANGLE_Y:
12944 clutter_actor_set_rotation_angle_internal (actor,
12946 g_value_get_double (value));
12949 case PROP_ROTATION_ANGLE_Z:
12950 clutter_actor_set_rotation_angle_internal (actor,
12952 g_value_get_double (value));
12956 g_object_set_property (obj, pspec->name, value);
12960 g_object_thaw_notify (obj);
12964 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12965 const gchar *property_name,
12966 const GValue *final)
12968 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12969 ClutterActorMeta *meta = NULL;
12970 gchar *p_name = NULL;
12972 meta = get_meta_from_animation_property (actor,
12976 g_object_set_property (G_OBJECT (meta), p_name, final);
12979 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12982 pspec = g_object_class_find_property (obj_class, property_name);
12984 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12986 /* XXX - I'm going to the special hell for this */
12987 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12990 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
12997 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12999 iface->find_property = clutter_actor_find_property;
13000 iface->get_initial_state = clutter_actor_get_initial_state;
13001 iface->set_final_state = clutter_actor_set_final_state;
13005 * clutter_actor_transform_stage_point:
13006 * @self: A #ClutterActor
13007 * @x: (in): x screen coordinate of the point to unproject
13008 * @y: (in): y screen coordinate of the point to unproject
13009 * @x_out: (out): return location for the unprojected x coordinance
13010 * @y_out: (out): return location for the unprojected y coordinance
13012 * This function translates screen coordinates (@x, @y) to
13013 * coordinates relative to the actor. For example, it can be used to translate
13014 * screen events from global screen coordinates into actor-local coordinates.
13016 * The conversion can fail, notably if the transform stack results in the
13017 * actor being projected on the screen as a mere line.
13019 * The conversion should not be expected to be pixel-perfect due to the
13020 * nature of the operation. In general the error grows when the skewing
13021 * of the actor rectangle on screen increases.
13023 * <note><para>This function can be computationally intensive.</para></note>
13025 * <note><para>This function only works when the allocation is up-to-date,
13026 * i.e. inside of paint().</para></note>
13028 * Return value: %TRUE if conversion was successful.
13033 clutter_actor_transform_stage_point (ClutterActor *self,
13039 ClutterVertex v[4];
13042 int du, dv, xi, yi;
13044 float xf, yf, wf, det;
13045 ClutterActorPrivate *priv;
13047 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13051 /* This implementation is based on the quad -> quad projection algorithm
13052 * described by Paul Heckbert in:
13054 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13056 * and the sample implementation at:
13058 * http://www.cs.cmu.edu/~ph/src/texfund/
13060 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13061 * quad to rectangle only, which significantly simplifies things; the
13062 * function calls have been unrolled, and most of the math is done in fixed
13066 clutter_actor_get_abs_allocation_vertices (self, v);
13068 /* Keeping these as ints simplifies the multiplication (no significant
13069 * loss of precision here).
13071 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13072 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13077 #define UX2FP(x) (x)
13078 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13080 /* First, find mapping from unit uv square to xy quadrilateral; this
13081 * equivalent to the pmap_square_quad() functions in the sample
13082 * implementation, which we can simplify, since our target is always
13085 px = v[0].x - v[1].x + v[3].x - v[2].x;
13086 py = v[0].y - v[1].y + v[3].y - v[2].y;
13090 /* affine transform */
13091 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13092 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13093 RQ[2][0] = UX2FP (v[0].x);
13094 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13095 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13096 RQ[2][1] = UX2FP (v[0].y);
13103 /* projective transform */
13104 double dx1, dx2, dy1, dy2, del;
13106 dx1 = UX2FP (v[1].x - v[3].x);
13107 dx2 = UX2FP (v[2].x - v[3].x);
13108 dy1 = UX2FP (v[1].y - v[3].y);
13109 dy2 = UX2FP (v[2].y - v[3].y);
13111 del = DET2FP (dx1, dx2, dy1, dy2);
13116 * The division here needs to be done in floating point for
13117 * precisions reasons.
13119 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13120 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13121 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13123 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13124 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13125 RQ[2][0] = UX2FP (v[0].x);
13126 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13127 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13128 RQ[2][1] = UX2FP (v[0].y);
13132 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13133 * square. Since our rectangle is based at 0,0 we only need to scale.
13143 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13146 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13147 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13148 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13149 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13150 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13151 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13152 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13153 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13154 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13157 * Check the resulting matrix is OK.
13159 det = (RQ[0][0] * ST[0][0])
13160 + (RQ[0][1] * ST[0][1])
13161 + (RQ[0][2] * ST[0][2]);
13166 * Now transform our point with the ST matrix; the notional w
13167 * coordinate is 1, hence the last part is simply added.
13172 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13173 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13174 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13192 static ClutterGeometry*
13193 clutter_geometry_copy (const ClutterGeometry *geometry)
13195 return g_slice_dup (ClutterGeometry, geometry);
13199 clutter_geometry_free (ClutterGeometry *geometry)
13201 if (G_LIKELY (geometry != NULL))
13202 g_slice_free (ClutterGeometry, geometry);
13206 * clutter_geometry_union:
13207 * @geometry_a: a #ClutterGeometry
13208 * @geometry_b: another #ClutterGeometry
13209 * @result: (out): location to store the result
13211 * Find the union of two rectangles represented as #ClutterGeometry.
13216 clutter_geometry_union (const ClutterGeometry *geometry_a,
13217 const ClutterGeometry *geometry_b,
13218 ClutterGeometry *result)
13220 /* We don't try to handle rectangles that can't be represented
13221 * as a signed integer box */
13222 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13223 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13224 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13225 geometry_b->x + (gint)geometry_b->width);
13226 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13227 geometry_b->y + (gint)geometry_b->height);
13230 result->width = x_2 - x_1;
13231 result->height = y_2 - y_1;
13235 * clutter_geometry_intersects:
13236 * @geometry0: The first geometry to test
13237 * @geometry1: The second geometry to test
13239 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13240 * they do else %FALSE.
13242 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13248 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13249 const ClutterGeometry *geometry1)
13251 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13252 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13253 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13254 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13261 clutter_geometry_progress (const GValue *a,
13266 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13267 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13268 ClutterGeometry res = { 0, };
13269 gint a_width = a_geom->width;
13270 gint b_width = b_geom->width;
13271 gint a_height = a_geom->height;
13272 gint b_height = b_geom->height;
13274 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13275 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13277 res.width = a_width + (b_width - a_width) * progress;
13278 res.height = a_height + (b_height - a_height) * progress;
13280 g_value_set_boxed (retval, &res);
13285 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13286 clutter_geometry_copy,
13287 clutter_geometry_free,
13288 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13295 * clutter_vertex_new:
13300 * Creates a new #ClutterVertex for the point in 3D space
13301 * identified by the 3 coordinates @x, @y, @z
13303 * Return value: the newly allocate #ClutterVertex. Use
13304 * clutter_vertex_free() to free the resources
13309 clutter_vertex_new (gfloat x,
13313 ClutterVertex *vertex;
13315 vertex = g_slice_new (ClutterVertex);
13316 clutter_vertex_init (vertex, x, y, z);
13322 * clutter_vertex_init:
13323 * @vertex: a #ClutterVertex
13328 * Initializes @vertex with the given coordinates.
13333 clutter_vertex_init (ClutterVertex *vertex,
13338 g_return_if_fail (vertex != NULL);
13346 * clutter_vertex_copy:
13347 * @vertex: a #ClutterVertex
13351 * Return value: a newly allocated copy of #ClutterVertex. Use
13352 * clutter_vertex_free() to free the allocated resources
13357 clutter_vertex_copy (const ClutterVertex *vertex)
13359 if (G_LIKELY (vertex != NULL))
13360 return g_slice_dup (ClutterVertex, vertex);
13366 * clutter_vertex_free:
13367 * @vertex: a #ClutterVertex
13369 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13374 clutter_vertex_free (ClutterVertex *vertex)
13376 if (G_UNLIKELY (vertex != NULL))
13377 g_slice_free (ClutterVertex, vertex);
13381 * clutter_vertex_equal:
13382 * @vertex_a: a #ClutterVertex
13383 * @vertex_b: a #ClutterVertex
13385 * Compares @vertex_a and @vertex_b for equality
13387 * Return value: %TRUE if the passed #ClutterVertex are equal
13392 clutter_vertex_equal (const ClutterVertex *vertex_a,
13393 const ClutterVertex *vertex_b)
13395 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13397 if (vertex_a == vertex_b)
13400 return vertex_a->x == vertex_b->x &&
13401 vertex_a->y == vertex_b->y &&
13402 vertex_a->z == vertex_b->z;
13406 clutter_vertex_progress (const GValue *a,
13411 const ClutterVertex *av = g_value_get_boxed (a);
13412 const ClutterVertex *bv = g_value_get_boxed (b);
13413 ClutterVertex res = { 0, };
13415 res.x = av->x + (bv->x - av->x) * progress;
13416 res.y = av->y + (bv->y - av->y) * progress;
13417 res.z = av->z + (bv->z - av->z) * progress;
13419 g_value_set_boxed (retval, &res);
13424 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13425 clutter_vertex_copy,
13426 clutter_vertex_free,
13427 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13430 * clutter_actor_is_rotated:
13431 * @self: a #ClutterActor
13433 * Checks whether any rotation is applied to the actor.
13435 * Return value: %TRUE if the actor is rotated.
13440 clutter_actor_is_rotated (ClutterActor *self)
13442 const ClutterTransformInfo *info;
13444 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13446 info = _clutter_actor_get_transform_info_or_defaults (self);
13448 if (info->rx_angle || info->ry_angle || info->rz_angle)
13455 * clutter_actor_is_scaled:
13456 * @self: a #ClutterActor
13458 * Checks whether the actor is scaled in either dimension.
13460 * Return value: %TRUE if the actor is scaled.
13465 clutter_actor_is_scaled (ClutterActor *self)
13467 const ClutterTransformInfo *info;
13469 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13471 info = _clutter_actor_get_transform_info_or_defaults (self);
13473 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13480 _clutter_actor_get_stage_internal (ClutterActor *actor)
13482 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13483 actor = actor->priv->parent;
13489 * clutter_actor_get_stage:
13490 * @actor: a #ClutterActor
13492 * Retrieves the #ClutterStage where @actor is contained.
13494 * Return value: (transfer none) (type Clutter.Stage): the stage
13495 * containing the actor, or %NULL
13500 clutter_actor_get_stage (ClutterActor *actor)
13502 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13504 return _clutter_actor_get_stage_internal (actor);
13508 * clutter_actor_allocate_available_size:
13509 * @self: a #ClutterActor
13510 * @x: the actor's X coordinate
13511 * @y: the actor's Y coordinate
13512 * @available_width: the maximum available width, or -1 to use the
13513 * actor's natural width
13514 * @available_height: the maximum available height, or -1 to use the
13515 * actor's natural height
13516 * @flags: flags controlling the allocation
13518 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13519 * preferred size, but limiting it to the maximum available width
13520 * and height provided.
13522 * This function will do the right thing when dealing with the
13523 * actor's request mode.
13525 * The implementation of this function is equivalent to:
13528 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13530 * clutter_actor_get_preferred_width (self, available_height,
13532 * &natural_width);
13533 * width = CLAMP (natural_width, min_width, available_width);
13535 * clutter_actor_get_preferred_height (self, width,
13537 * &natural_height);
13538 * height = CLAMP (natural_height, min_height, available_height);
13542 * clutter_actor_get_preferred_height (self, available_width,
13544 * &natural_height);
13545 * height = CLAMP (natural_height, min_height, available_height);
13547 * clutter_actor_get_preferred_width (self, height,
13549 * &natural_width);
13550 * width = CLAMP (natural_width, min_width, available_width);
13553 * box.x1 = x; box.y1 = y;
13554 * box.x2 = box.x1 + available_width;
13555 * box.y2 = box.y1 + available_height;
13556 * clutter_actor_allocate (self, &box, flags);
13559 * This function can be used by fluid layout managers to allocate
13560 * an actor's preferred size without making it bigger than the area
13561 * available for the container.
13566 clutter_actor_allocate_available_size (ClutterActor *self,
13569 gfloat available_width,
13570 gfloat available_height,
13571 ClutterAllocationFlags flags)
13573 ClutterActorPrivate *priv;
13574 gfloat width, height;
13575 gfloat min_width, min_height;
13576 gfloat natural_width, natural_height;
13577 ClutterActorBox box;
13579 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13583 width = height = 0.0;
13585 switch (priv->request_mode)
13587 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13588 clutter_actor_get_preferred_width (self, available_height,
13591 width = CLAMP (natural_width, min_width, available_width);
13593 clutter_actor_get_preferred_height (self, width,
13596 height = CLAMP (natural_height, min_height, available_height);
13599 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13600 clutter_actor_get_preferred_height (self, available_width,
13603 height = CLAMP (natural_height, min_height, available_height);
13605 clutter_actor_get_preferred_width (self, height,
13608 width = CLAMP (natural_width, min_width, available_width);
13615 box.x2 = box.x1 + width;
13616 box.y2 = box.y1 + height;
13617 clutter_actor_allocate (self, &box, flags);
13621 * clutter_actor_allocate_preferred_size:
13622 * @self: a #ClutterActor
13623 * @flags: flags controlling the allocation
13625 * Allocates the natural size of @self.
13627 * This function is a utility call for #ClutterActor implementations
13628 * that allocates the actor's preferred natural size. It can be used
13629 * by fixed layout managers (like #ClutterGroup or so called
13630 * 'composite actors') inside the ClutterActor::allocate
13631 * implementation to give each child exactly how much space it
13634 * This function is not meant to be used by applications. It is also
13635 * not meant to be used outside the implementation of the
13636 * ClutterActor::allocate virtual function.
13641 clutter_actor_allocate_preferred_size (ClutterActor *self,
13642 ClutterAllocationFlags flags)
13644 gfloat actor_x, actor_y;
13645 gfloat natural_width, natural_height;
13646 ClutterActorBox actor_box;
13648 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13650 actor_x = clutter_actor_get_x (self);
13651 actor_y = clutter_actor_get_y (self);
13653 clutter_actor_get_preferred_size (self,
13658 actor_box.x1 = actor_x;
13659 actor_box.y1 = actor_y;
13660 actor_box.x2 = actor_box.x1 + natural_width;
13661 actor_box.y2 = actor_box.y1 + natural_height;
13663 clutter_actor_allocate (self, &actor_box, flags);
13667 * clutter_actor_allocate_align_fill:
13668 * @self: a #ClutterActor
13669 * @box: a #ClutterActorBox, containing the available width and height
13670 * @x_align: the horizontal alignment, between 0 and 1
13671 * @y_align: the vertical alignment, between 0 and 1
13672 * @x_fill: whether the actor should fill horizontally
13673 * @y_fill: whether the actor should fill vertically
13674 * @flags: allocation flags to be passed to clutter_actor_allocate()
13676 * Allocates @self by taking into consideration the available allocation
13677 * area; an alignment factor on either axis; and whether the actor should
13678 * fill the allocation on either axis.
13680 * The @box should contain the available allocation width and height;
13681 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13682 * allocation will be offset by their value.
13684 * This function takes into consideration the geometry request specified by
13685 * the #ClutterActor:request-mode property, and the text direction.
13687 * This function is useful for fluid layout managers, like #ClutterBinLayout
13688 * or #ClutterTableLayout
13693 clutter_actor_allocate_align_fill (ClutterActor *self,
13694 const ClutterActorBox *box,
13699 ClutterAllocationFlags flags)
13701 ClutterActorPrivate *priv;
13702 ClutterActorBox allocation = { 0, };
13703 gfloat x_offset, y_offset;
13704 gfloat available_width, available_height;
13705 gfloat child_width, child_height;
13707 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13708 g_return_if_fail (box != NULL);
13709 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13710 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13714 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13715 clutter_actor_box_get_size (box, &available_width, &available_height);
13717 if (available_width < 0)
13718 available_width = 0;
13720 if (available_height < 0)
13721 available_height = 0;
13725 allocation.x1 = x_offset;
13726 allocation.x2 = allocation.x1 + available_width;
13731 allocation.y1 = y_offset;
13732 allocation.y2 = allocation.y1 + available_height;
13735 /* if we are filling horizontally and vertically then we're done */
13736 if (x_fill && y_fill)
13739 child_width = child_height = 0.0f;
13741 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13743 gfloat min_width, natural_width;
13744 gfloat min_height, natural_height;
13746 clutter_actor_get_preferred_width (self, available_height,
13750 child_width = CLAMP (natural_width, min_width, available_width);
13754 clutter_actor_get_preferred_height (self, child_width,
13758 child_height = CLAMP (natural_height, min_height, available_height);
13763 gfloat min_width, natural_width;
13764 gfloat min_height, natural_height;
13766 clutter_actor_get_preferred_height (self, available_width,
13770 child_height = CLAMP (natural_height, min_height, available_height);
13774 clutter_actor_get_preferred_width (self, child_height,
13778 child_width = CLAMP (natural_width, min_width, available_width);
13782 /* invert the horizontal alignment for RTL languages */
13783 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13784 x_align = 1.0 - x_align;
13788 allocation.x1 = x_offset
13789 + ((available_width - child_width) * x_align);
13790 allocation.x2 = allocation.x1 + child_width;
13795 allocation.y1 = y_offset
13796 + ((available_height - child_height) * y_align);
13797 allocation.y2 = allocation.y1 + child_height;
13801 clutter_actor_box_clamp_to_pixel (&allocation);
13802 clutter_actor_allocate (self, &allocation, flags);
13806 * clutter_actor_grab_key_focus:
13807 * @self: a #ClutterActor
13809 * Sets the key focus of the #ClutterStage including @self
13810 * to this #ClutterActor.
13815 clutter_actor_grab_key_focus (ClutterActor *self)
13817 ClutterActor *stage;
13819 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13821 stage = _clutter_actor_get_stage_internal (self);
13823 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13827 * clutter_actor_get_pango_context:
13828 * @self: a #ClutterActor
13830 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13831 * is already configured using the appropriate font map, resolution
13832 * and font options.
13834 * Unlike clutter_actor_create_pango_context(), this context is owend
13835 * by the #ClutterActor and it will be updated each time the options
13836 * stored by the #ClutterBackend change.
13838 * You can use the returned #PangoContext to create a #PangoLayout
13839 * and render text using cogl_pango_render_layout() to reuse the
13840 * glyphs cache also used by Clutter.
13842 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13843 * The returned #PangoContext is owned by the actor and should not be
13844 * unreferenced by the application code
13849 clutter_actor_get_pango_context (ClutterActor *self)
13851 ClutterActorPrivate *priv;
13853 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13857 if (priv->pango_context != NULL)
13858 return priv->pango_context;
13860 priv->pango_context = _clutter_context_get_pango_context ();
13861 g_object_ref (priv->pango_context);
13863 return priv->pango_context;
13867 * clutter_actor_create_pango_context:
13868 * @self: a #ClutterActor
13870 * Creates a #PangoContext for the given actor. The #PangoContext
13871 * is already configured using the appropriate font map, resolution
13872 * and font options.
13874 * See also clutter_actor_get_pango_context().
13876 * Return value: (transfer full): the newly created #PangoContext.
13877 * Use g_object_unref() on the returned value to deallocate its
13883 clutter_actor_create_pango_context (ClutterActor *self)
13885 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13887 return _clutter_context_create_pango_context ();
13891 * clutter_actor_create_pango_layout:
13892 * @self: a #ClutterActor
13893 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13895 * Creates a new #PangoLayout from the same #PangoContext used
13896 * by the #ClutterActor. The #PangoLayout is already configured
13897 * with the font map, resolution and font options, and the
13900 * If you want to keep around a #PangoLayout created by this
13901 * function you will have to connect to the #ClutterBackend::font-changed
13902 * and #ClutterBackend::resolution-changed signals, and call
13903 * pango_layout_context_changed() in response to them.
13905 * Return value: (transfer full): the newly created #PangoLayout.
13906 * Use g_object_unref() when done
13911 clutter_actor_create_pango_layout (ClutterActor *self,
13914 PangoContext *context;
13915 PangoLayout *layout;
13917 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13919 context = clutter_actor_get_pango_context (self);
13920 layout = pango_layout_new (context);
13923 pango_layout_set_text (layout, text, -1);
13928 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13929 * ClutterOffscreenEffect.
13932 _clutter_actor_set_opacity_override (ClutterActor *self,
13935 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13937 self->priv->opacity_override = opacity;
13941 _clutter_actor_get_opacity_override (ClutterActor *self)
13943 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13945 return self->priv->opacity_override;
13948 /* Allows you to disable applying the actors model view transform during
13949 * a paint. Used by ClutterClone. */
13951 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13954 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13956 self->priv->enable_model_view_transform = enable;
13960 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13963 ClutterActorPrivate *priv;
13965 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13969 priv->enable_paint_unmapped = enable;
13971 if (priv->enable_paint_unmapped)
13973 /* Make sure that the parents of the widget are realized first;
13974 * otherwise checks in clutter_actor_update_map_state() will
13977 clutter_actor_realize (self);
13979 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13983 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13988 clutter_anchor_coord_get_units (ClutterActor *self,
13989 const AnchorCoord *coord,
13994 if (coord->is_fractional)
13996 gfloat actor_width, actor_height;
13998 clutter_actor_get_size (self, &actor_width, &actor_height);
14001 *x = actor_width * coord->v.fraction.x;
14004 *y = actor_height * coord->v.fraction.y;
14012 *x = coord->v.units.x;
14015 *y = coord->v.units.y;
14018 *z = coord->v.units.z;
14023 clutter_anchor_coord_set_units (AnchorCoord *coord,
14028 coord->is_fractional = FALSE;
14029 coord->v.units.x = x;
14030 coord->v.units.y = y;
14031 coord->v.units.z = z;
14034 static ClutterGravity
14035 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14037 if (coord->is_fractional)
14039 if (coord->v.fraction.x == 0.0)
14041 if (coord->v.fraction.y == 0.0)
14042 return CLUTTER_GRAVITY_NORTH_WEST;
14043 else if (coord->v.fraction.y == 0.5)
14044 return CLUTTER_GRAVITY_WEST;
14045 else if (coord->v.fraction.y == 1.0)
14046 return CLUTTER_GRAVITY_SOUTH_WEST;
14048 return CLUTTER_GRAVITY_NONE;
14050 else if (coord->v.fraction.x == 0.5)
14052 if (coord->v.fraction.y == 0.0)
14053 return CLUTTER_GRAVITY_NORTH;
14054 else if (coord->v.fraction.y == 0.5)
14055 return CLUTTER_GRAVITY_CENTER;
14056 else if (coord->v.fraction.y == 1.0)
14057 return CLUTTER_GRAVITY_SOUTH;
14059 return CLUTTER_GRAVITY_NONE;
14061 else if (coord->v.fraction.x == 1.0)
14063 if (coord->v.fraction.y == 0.0)
14064 return CLUTTER_GRAVITY_NORTH_EAST;
14065 else if (coord->v.fraction.y == 0.5)
14066 return CLUTTER_GRAVITY_EAST;
14067 else if (coord->v.fraction.y == 1.0)
14068 return CLUTTER_GRAVITY_SOUTH_EAST;
14070 return CLUTTER_GRAVITY_NONE;
14073 return CLUTTER_GRAVITY_NONE;
14076 return CLUTTER_GRAVITY_NONE;
14080 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14081 ClutterGravity gravity)
14085 case CLUTTER_GRAVITY_NORTH:
14086 coord->v.fraction.x = 0.5;
14087 coord->v.fraction.y = 0.0;
14090 case CLUTTER_GRAVITY_NORTH_EAST:
14091 coord->v.fraction.x = 1.0;
14092 coord->v.fraction.y = 0.0;
14095 case CLUTTER_GRAVITY_EAST:
14096 coord->v.fraction.x = 1.0;
14097 coord->v.fraction.y = 0.5;
14100 case CLUTTER_GRAVITY_SOUTH_EAST:
14101 coord->v.fraction.x = 1.0;
14102 coord->v.fraction.y = 1.0;
14105 case CLUTTER_GRAVITY_SOUTH:
14106 coord->v.fraction.x = 0.5;
14107 coord->v.fraction.y = 1.0;
14110 case CLUTTER_GRAVITY_SOUTH_WEST:
14111 coord->v.fraction.x = 0.0;
14112 coord->v.fraction.y = 1.0;
14115 case CLUTTER_GRAVITY_WEST:
14116 coord->v.fraction.x = 0.0;
14117 coord->v.fraction.y = 0.5;
14120 case CLUTTER_GRAVITY_NORTH_WEST:
14121 coord->v.fraction.x = 0.0;
14122 coord->v.fraction.y = 0.0;
14125 case CLUTTER_GRAVITY_CENTER:
14126 coord->v.fraction.x = 0.5;
14127 coord->v.fraction.y = 0.5;
14131 coord->v.fraction.x = 0.0;
14132 coord->v.fraction.y = 0.0;
14136 coord->is_fractional = TRUE;
14140 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14142 if (coord->is_fractional)
14143 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14145 return (coord->v.units.x == 0.0
14146 && coord->v.units.y == 0.0
14147 && coord->v.units.z == 0.0);
14151 * clutter_actor_get_flags:
14152 * @self: a #ClutterActor
14154 * Retrieves the flags set on @self
14156 * Return value: a bitwise or of #ClutterActorFlags or 0
14161 clutter_actor_get_flags (ClutterActor *self)
14163 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14165 return self->flags;
14169 * clutter_actor_set_flags:
14170 * @self: a #ClutterActor
14171 * @flags: the flags to set
14173 * Sets @flags on @self
14175 * This function will emit notifications for the changed properties
14180 clutter_actor_set_flags (ClutterActor *self,
14181 ClutterActorFlags flags)
14183 ClutterActorFlags old_flags;
14185 gboolean was_reactive_set, reactive_set;
14186 gboolean was_realized_set, realized_set;
14187 gboolean was_mapped_set, mapped_set;
14188 gboolean was_visible_set, visible_set;
14190 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14192 if (self->flags == flags)
14195 obj = G_OBJECT (self);
14196 g_object_ref (obj);
14197 g_object_freeze_notify (obj);
14199 old_flags = self->flags;
14201 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14202 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14203 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14204 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14206 self->flags |= flags;
14208 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14209 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14210 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14211 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14213 if (reactive_set != was_reactive_set)
14214 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14216 if (realized_set != was_realized_set)
14217 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14219 if (mapped_set != was_mapped_set)
14220 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14222 if (visible_set != was_visible_set)
14223 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14225 g_object_thaw_notify (obj);
14226 g_object_unref (obj);
14230 * clutter_actor_unset_flags:
14231 * @self: a #ClutterActor
14232 * @flags: the flags to unset
14234 * Unsets @flags on @self
14236 * This function will emit notifications for the changed properties
14241 clutter_actor_unset_flags (ClutterActor *self,
14242 ClutterActorFlags flags)
14244 ClutterActorFlags old_flags;
14246 gboolean was_reactive_set, reactive_set;
14247 gboolean was_realized_set, realized_set;
14248 gboolean was_mapped_set, mapped_set;
14249 gboolean was_visible_set, visible_set;
14251 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14253 obj = G_OBJECT (self);
14254 g_object_freeze_notify (obj);
14256 old_flags = self->flags;
14258 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14259 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14260 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14261 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14263 self->flags &= ~flags;
14265 if (self->flags == old_flags)
14268 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14269 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14270 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14271 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14273 if (reactive_set != was_reactive_set)
14274 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14276 if (realized_set != was_realized_set)
14277 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14279 if (mapped_set != was_mapped_set)
14280 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14282 if (visible_set != was_visible_set)
14283 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14285 g_object_thaw_notify (obj);
14289 * clutter_actor_get_transformation_matrix:
14290 * @self: a #ClutterActor
14291 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14293 * Retrieves the transformations applied to @self relative to its
14299 clutter_actor_get_transformation_matrix (ClutterActor *self,
14300 CoglMatrix *matrix)
14302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14304 cogl_matrix_init_identity (matrix);
14306 _clutter_actor_apply_modelview_transform (self, matrix);
14310 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14311 gboolean is_in_clone_paint)
14313 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14314 self->priv->in_clone_paint = is_in_clone_paint;
14318 * clutter_actor_is_in_clone_paint:
14319 * @self: a #ClutterActor
14321 * Checks whether @self is being currently painted by a #ClutterClone
14323 * This function is useful only inside the ::paint virtual function
14324 * implementations or within handlers for the #ClutterActor::paint
14327 * This function should not be used by applications
14329 * Return value: %TRUE if the #ClutterActor is currently being painted
14330 * by a #ClutterClone, and %FALSE otherwise
14335 clutter_actor_is_in_clone_paint (ClutterActor *self)
14337 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14339 return self->priv->in_clone_paint;
14343 set_direction_recursive (ClutterActor *actor,
14344 gpointer user_data)
14346 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14348 clutter_actor_set_text_direction (actor, text_dir);
14354 * clutter_actor_set_text_direction:
14355 * @self: a #ClutterActor
14356 * @text_dir: the text direction for @self
14358 * Sets the #ClutterTextDirection for an actor
14360 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14362 * If @self implements #ClutterContainer then this function will recurse
14363 * inside all the children of @self (including the internal ones).
14365 * Composite actors not implementing #ClutterContainer, or actors requiring
14366 * special handling when the text direction changes, should connect to
14367 * the #GObject::notify signal for the #ClutterActor:text-direction property
14372 clutter_actor_set_text_direction (ClutterActor *self,
14373 ClutterTextDirection text_dir)
14375 ClutterActorPrivate *priv;
14377 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14378 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14382 if (priv->text_direction != text_dir)
14384 priv->text_direction = text_dir;
14386 /* we need to emit the notify::text-direction first, so that
14387 * the sub-classes can catch that and do specific handling of
14388 * the text direction; see clutter_text_direction_changed_cb()
14389 * inside clutter-text.c
14391 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14393 _clutter_actor_foreach_child (self, set_direction_recursive,
14394 GINT_TO_POINTER (text_dir));
14396 clutter_actor_queue_relayout (self);
14401 _clutter_actor_set_has_pointer (ClutterActor *self,
14402 gboolean has_pointer)
14404 ClutterActorPrivate *priv = self->priv;
14406 if (priv->has_pointer != has_pointer)
14408 priv->has_pointer = has_pointer;
14410 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14415 * clutter_actor_get_text_direction:
14416 * @self: a #ClutterActor
14418 * Retrieves the value set using clutter_actor_set_text_direction()
14420 * If no text direction has been previously set, the default text
14421 * direction, as returned by clutter_get_default_text_direction(), will
14422 * be returned instead
14424 * Return value: the #ClutterTextDirection for the actor
14428 ClutterTextDirection
14429 clutter_actor_get_text_direction (ClutterActor *self)
14431 ClutterActorPrivate *priv;
14433 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14434 CLUTTER_TEXT_DIRECTION_LTR);
14438 /* if no direction has been set yet use the default */
14439 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14440 priv->text_direction = clutter_get_default_text_direction ();
14442 return priv->text_direction;
14446 * clutter_actor_push_internal:
14447 * @self: a #ClutterActor
14449 * Should be used by actors implementing the #ClutterContainer and with
14450 * internal children added through clutter_actor_set_parent(), for instance:
14454 * my_actor_init (MyActor *self)
14456 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14458 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14460 * /* calling clutter_actor_set_parent() now will result in
14461 * * the internal flag being set on a child of MyActor
14464 * /* internal child - a background texture */
14465 * self->priv->background_tex = clutter_texture_new ();
14466 * clutter_actor_set_parent (self->priv->background_tex,
14467 * CLUTTER_ACTOR (self));
14469 * /* internal child - a label */
14470 * self->priv->label = clutter_text_new ();
14471 * clutter_actor_set_parent (self->priv->label,
14472 * CLUTTER_ACTOR (self));
14474 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14476 * /* calling clutter_actor_set_parent() now will not result in
14477 * * the internal flag being set on a child of MyActor
14482 * This function will be used by Clutter to toggle an "internal child"
14483 * flag whenever clutter_actor_set_parent() is called; internal children
14484 * are handled differently by Clutter, specifically when destroying their
14487 * Call clutter_actor_pop_internal() when you finished adding internal
14490 * Nested calls to clutter_actor_push_internal() are allowed, but each
14491 * one must by followed by a clutter_actor_pop_internal() call.
14495 * Deprecated: 1.10: All children of an actor are accessible through
14496 * the #ClutterActor API, and #ClutterActor implements the
14497 * #ClutterContainer interface, so this function is only useful
14498 * for legacy containers overriding the default implementation.
14501 clutter_actor_push_internal (ClutterActor *self)
14503 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14505 self->priv->internal_child += 1;
14509 * clutter_actor_pop_internal:
14510 * @self: a #ClutterActor
14512 * Disables the effects of clutter_actor_push_internal().
14516 * Deprecated: 1.10: All children of an actor are accessible through
14517 * the #ClutterActor API. This function is only useful for legacy
14518 * containers overriding the default implementation of the
14519 * #ClutterContainer interface.
14522 clutter_actor_pop_internal (ClutterActor *self)
14524 ClutterActorPrivate *priv;
14526 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14530 if (priv->internal_child == 0)
14532 g_warning ("Mismatched %s: you need to call "
14533 "clutter_actor_push_composite() at least once before "
14534 "calling this function", G_STRFUNC);
14538 priv->internal_child -= 1;
14542 * clutter_actor_has_pointer:
14543 * @self: a #ClutterActor
14545 * Checks whether an actor contains the pointer of a
14546 * #ClutterInputDevice
14548 * Return value: %TRUE if the actor contains the pointer, and
14554 clutter_actor_has_pointer (ClutterActor *self)
14556 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14558 return self->priv->has_pointer;
14561 /* XXX: This is a workaround for not being able to break the ABI of
14562 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14563 * clutter_actor_queue_clipped_redraw() for details.
14565 ClutterPaintVolume *
14566 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14568 return g_object_get_data (G_OBJECT (self),
14569 "-clutter-actor-queue-redraw-clip");
14573 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14574 ClutterPaintVolume *clip)
14576 g_object_set_data (G_OBJECT (self),
14577 "-clutter-actor-queue-redraw-clip",
14582 * clutter_actor_has_allocation:
14583 * @self: a #ClutterActor
14585 * Checks if the actor has an up-to-date allocation assigned to
14586 * it. This means that the actor should have an allocation: it's
14587 * visible and has a parent. It also means that there is no
14588 * outstanding relayout request in progress for the actor or its
14589 * children (There might be other outstanding layout requests in
14590 * progress that will cause the actor to get a new allocation
14591 * when the stage is laid out, however).
14593 * If this function returns %FALSE, then the actor will normally
14594 * be allocated before it is next drawn on the screen.
14596 * Return value: %TRUE if the actor has an up-to-date allocation
14601 clutter_actor_has_allocation (ClutterActor *self)
14603 ClutterActorPrivate *priv;
14605 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14609 return priv->parent != NULL &&
14610 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14611 !priv->needs_allocation;
14615 * clutter_actor_add_action:
14616 * @self: a #ClutterActor
14617 * @action: a #ClutterAction
14619 * Adds @action to the list of actions applied to @self
14621 * A #ClutterAction can only belong to one actor at a time
14623 * The #ClutterActor will hold a reference on @action until either
14624 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14630 clutter_actor_add_action (ClutterActor *self,
14631 ClutterAction *action)
14633 ClutterActorPrivate *priv;
14635 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14636 g_return_if_fail (CLUTTER_IS_ACTION (action));
14640 if (priv->actions == NULL)
14642 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14643 priv->actions->actor = self;
14646 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14648 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14652 * clutter_actor_add_action_with_name:
14653 * @self: a #ClutterActor
14654 * @name: the name to set on the action
14655 * @action: a #ClutterAction
14657 * A convenience function for setting the name of a #ClutterAction
14658 * while adding it to the list of actions applied to @self
14660 * This function is the logical equivalent of:
14663 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14664 * clutter_actor_add_action (self, action);
14670 clutter_actor_add_action_with_name (ClutterActor *self,
14672 ClutterAction *action)
14674 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14675 g_return_if_fail (name != NULL);
14676 g_return_if_fail (CLUTTER_IS_ACTION (action));
14678 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14679 clutter_actor_add_action (self, action);
14683 * clutter_actor_remove_action:
14684 * @self: a #ClutterActor
14685 * @action: a #ClutterAction
14687 * Removes @action from the list of actions applied to @self
14689 * The reference held by @self on the #ClutterAction will be released
14694 clutter_actor_remove_action (ClutterActor *self,
14695 ClutterAction *action)
14697 ClutterActorPrivate *priv;
14699 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14700 g_return_if_fail (CLUTTER_IS_ACTION (action));
14704 if (priv->actions == NULL)
14707 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14709 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14713 * clutter_actor_remove_action_by_name:
14714 * @self: a #ClutterActor
14715 * @name: the name of the action to remove
14717 * Removes the #ClutterAction with the given name from the list
14718 * of actions applied to @self
14723 clutter_actor_remove_action_by_name (ClutterActor *self,
14726 ClutterActorPrivate *priv;
14727 ClutterActorMeta *meta;
14729 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14730 g_return_if_fail (name != NULL);
14734 if (priv->actions == NULL)
14737 meta = _clutter_meta_group_get_meta (priv->actions, name);
14741 _clutter_meta_group_remove_meta (priv->actions, meta);
14743 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14747 * clutter_actor_get_actions:
14748 * @self: a #ClutterActor
14750 * Retrieves the list of actions applied to @self
14752 * Return value: (transfer container) (element-type Clutter.Action): a copy
14753 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14754 * owned by the #ClutterActor. Use g_list_free() to free the resources
14755 * allocated by the returned #GList
14760 clutter_actor_get_actions (ClutterActor *self)
14762 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14764 if (self->priv->actions == NULL)
14767 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14771 * clutter_actor_get_action:
14772 * @self: a #ClutterActor
14773 * @name: the name of the action to retrieve
14775 * Retrieves the #ClutterAction with the given name in the list
14776 * of actions applied to @self
14778 * Return value: (transfer none): a #ClutterAction for the given
14779 * name, or %NULL. The returned #ClutterAction is owned by the
14780 * actor and it should not be unreferenced directly
14785 clutter_actor_get_action (ClutterActor *self,
14788 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14789 g_return_val_if_fail (name != NULL, NULL);
14791 if (self->priv->actions == NULL)
14794 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14798 * clutter_actor_clear_actions:
14799 * @self: a #ClutterActor
14801 * Clears the list of actions applied to @self
14806 clutter_actor_clear_actions (ClutterActor *self)
14808 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14810 if (self->priv->actions == NULL)
14813 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14817 * clutter_actor_add_constraint:
14818 * @self: a #ClutterActor
14819 * @constraint: a #ClutterConstraint
14821 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14824 * The #ClutterActor will hold a reference on the @constraint until
14825 * either clutter_actor_remove_constraint() or
14826 * clutter_actor_clear_constraints() is called.
14831 clutter_actor_add_constraint (ClutterActor *self,
14832 ClutterConstraint *constraint)
14834 ClutterActorPrivate *priv;
14836 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14837 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14841 if (priv->constraints == NULL)
14843 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14844 priv->constraints->actor = self;
14847 _clutter_meta_group_add_meta (priv->constraints,
14848 CLUTTER_ACTOR_META (constraint));
14849 clutter_actor_queue_relayout (self);
14851 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14855 * clutter_actor_add_constraint_with_name:
14856 * @self: a #ClutterActor
14857 * @name: the name to set on the constraint
14858 * @constraint: a #ClutterConstraint
14860 * A convenience function for setting the name of a #ClutterConstraint
14861 * while adding it to the list of constraints applied to @self
14863 * This function is the logical equivalent of:
14866 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14867 * clutter_actor_add_constraint (self, constraint);
14873 clutter_actor_add_constraint_with_name (ClutterActor *self,
14875 ClutterConstraint *constraint)
14877 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14878 g_return_if_fail (name != NULL);
14879 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14881 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14882 clutter_actor_add_constraint (self, constraint);
14886 * clutter_actor_remove_constraint:
14887 * @self: a #ClutterActor
14888 * @constraint: a #ClutterConstraint
14890 * Removes @constraint from the list of constraints applied to @self
14892 * The reference held by @self on the #ClutterConstraint will be released
14897 clutter_actor_remove_constraint (ClutterActor *self,
14898 ClutterConstraint *constraint)
14900 ClutterActorPrivate *priv;
14902 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14903 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14907 if (priv->constraints == NULL)
14910 _clutter_meta_group_remove_meta (priv->constraints,
14911 CLUTTER_ACTOR_META (constraint));
14912 clutter_actor_queue_relayout (self);
14914 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14918 * clutter_actor_remove_constraint_by_name:
14919 * @self: a #ClutterActor
14920 * @name: the name of the constraint to remove
14922 * Removes the #ClutterConstraint with the given name from the list
14923 * of constraints applied to @self
14928 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14931 ClutterActorPrivate *priv;
14932 ClutterActorMeta *meta;
14934 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14935 g_return_if_fail (name != NULL);
14939 if (priv->constraints == NULL)
14942 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14946 _clutter_meta_group_remove_meta (priv->constraints, meta);
14947 clutter_actor_queue_relayout (self);
14951 * clutter_actor_get_constraints:
14952 * @self: a #ClutterActor
14954 * Retrieves the list of constraints applied to @self
14956 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14957 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14958 * owned by the #ClutterActor. Use g_list_free() to free the resources
14959 * allocated by the returned #GList
14964 clutter_actor_get_constraints (ClutterActor *self)
14966 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14968 if (self->priv->constraints == NULL)
14971 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14975 * clutter_actor_get_constraint:
14976 * @self: a #ClutterActor
14977 * @name: the name of the constraint to retrieve
14979 * Retrieves the #ClutterConstraint with the given name in the list
14980 * of constraints applied to @self
14982 * Return value: (transfer none): a #ClutterConstraint for the given
14983 * name, or %NULL. The returned #ClutterConstraint is owned by the
14984 * actor and it should not be unreferenced directly
14988 ClutterConstraint *
14989 clutter_actor_get_constraint (ClutterActor *self,
14992 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14993 g_return_val_if_fail (name != NULL, NULL);
14995 if (self->priv->constraints == NULL)
14998 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15002 * clutter_actor_clear_constraints:
15003 * @self: a #ClutterActor
15005 * Clears the list of constraints applied to @self
15010 clutter_actor_clear_constraints (ClutterActor *self)
15012 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15014 if (self->priv->constraints == NULL)
15017 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15019 clutter_actor_queue_relayout (self);
15023 * clutter_actor_set_clip_to_allocation:
15024 * @self: a #ClutterActor
15025 * @clip_set: %TRUE to apply a clip tracking the allocation
15027 * Sets whether @self should be clipped to the same size as its
15033 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15036 ClutterActorPrivate *priv;
15038 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15040 clip_set = !!clip_set;
15044 if (priv->clip_to_allocation != clip_set)
15046 priv->clip_to_allocation = clip_set;
15048 clutter_actor_queue_redraw (self);
15050 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15055 * clutter_actor_get_clip_to_allocation:
15056 * @self: a #ClutterActor
15058 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15060 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15065 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15067 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15069 return self->priv->clip_to_allocation;
15073 * clutter_actor_add_effect:
15074 * @self: a #ClutterActor
15075 * @effect: a #ClutterEffect
15077 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15079 * The #ClutterActor will hold a reference on the @effect until either
15080 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15086 clutter_actor_add_effect (ClutterActor *self,
15087 ClutterEffect *effect)
15089 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15090 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15092 _clutter_actor_add_effect_internal (self, effect);
15094 clutter_actor_queue_redraw (self);
15096 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15100 * clutter_actor_add_effect_with_name:
15101 * @self: a #ClutterActor
15102 * @name: the name to set on the effect
15103 * @effect: a #ClutterEffect
15105 * A convenience function for setting the name of a #ClutterEffect
15106 * while adding it to the list of effectss applied to @self
15108 * This function is the logical equivalent of:
15111 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15112 * clutter_actor_add_effect (self, effect);
15118 clutter_actor_add_effect_with_name (ClutterActor *self,
15120 ClutterEffect *effect)
15122 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15123 g_return_if_fail (name != NULL);
15124 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15126 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15127 clutter_actor_add_effect (self, effect);
15131 * clutter_actor_remove_effect:
15132 * @self: a #ClutterActor
15133 * @effect: a #ClutterEffect
15135 * Removes @effect from the list of effects applied to @self
15137 * The reference held by @self on the #ClutterEffect will be released
15142 clutter_actor_remove_effect (ClutterActor *self,
15143 ClutterEffect *effect)
15145 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15146 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15148 _clutter_actor_remove_effect_internal (self, effect);
15150 clutter_actor_queue_redraw (self);
15152 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15156 * clutter_actor_remove_effect_by_name:
15157 * @self: a #ClutterActor
15158 * @name: the name of the effect to remove
15160 * Removes the #ClutterEffect with the given name from the list
15161 * of effects applied to @self
15166 clutter_actor_remove_effect_by_name (ClutterActor *self,
15169 ClutterActorPrivate *priv;
15170 ClutterActorMeta *meta;
15172 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15173 g_return_if_fail (name != NULL);
15177 if (priv->effects == NULL)
15180 meta = _clutter_meta_group_get_meta (priv->effects, name);
15184 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15188 * clutter_actor_get_effects:
15189 * @self: a #ClutterActor
15191 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15193 * Return value: (transfer container) (element-type Clutter.Effect): a list
15194 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15195 * list are owned by Clutter and they should not be freed. You should
15196 * free the returned list using g_list_free() when done
15201 clutter_actor_get_effects (ClutterActor *self)
15203 ClutterActorPrivate *priv;
15205 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15209 if (priv->effects == NULL)
15212 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15216 * clutter_actor_get_effect:
15217 * @self: a #ClutterActor
15218 * @name: the name of the effect to retrieve
15220 * Retrieves the #ClutterEffect with the given name in the list
15221 * of effects applied to @self
15223 * Return value: (transfer none): a #ClutterEffect for the given
15224 * name, or %NULL. The returned #ClutterEffect is owned by the
15225 * actor and it should not be unreferenced directly
15230 clutter_actor_get_effect (ClutterActor *self,
15233 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15234 g_return_val_if_fail (name != NULL, NULL);
15236 if (self->priv->effects == NULL)
15239 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15243 * clutter_actor_clear_effects:
15244 * @self: a #ClutterActor
15246 * Clears the list of effects applied to @self
15251 clutter_actor_clear_effects (ClutterActor *self)
15253 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15255 if (self->priv->effects == NULL)
15258 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15260 clutter_actor_queue_redraw (self);
15264 * clutter_actor_has_key_focus:
15265 * @self: a #ClutterActor
15267 * Checks whether @self is the #ClutterActor that has key focus
15269 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15274 clutter_actor_has_key_focus (ClutterActor *self)
15276 ClutterActor *stage;
15278 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15280 stage = _clutter_actor_get_stage_internal (self);
15284 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15288 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15289 ClutterPaintVolume *pv)
15291 ClutterActorPrivate *priv = self->priv;
15293 /* Actors are only expected to report a valid paint volume
15294 * while they have a valid allocation. */
15295 if (G_UNLIKELY (priv->needs_allocation))
15297 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15298 "Actor needs allocation",
15299 _clutter_actor_get_debug_name (self));
15303 /* Check if there are any handlers connected to the paint
15304 * signal. If there are then all bets are off for what the paint
15305 * volume for this actor might possibly be!
15307 * XXX: It's expected that this is going to end up being quite a
15308 * costly check to have to do here, but we haven't come up with
15309 * another solution that can reliably catch paint signal handlers at
15310 * the right time to either avoid artefacts due to invalid stage
15311 * clipping or due to incorrect culling.
15313 * Previously we checked in clutter_actor_paint(), but at that time
15314 * we may already be using a stage clip that could be derived from
15315 * an invalid paint-volume. We used to try and handle that by
15316 * queuing a follow up, unclipped, redraw but still the previous
15317 * checking wasn't enough to catch invalid volumes involved in
15318 * culling (considering that containers may derive their volume from
15319 * children that haven't yet been painted)
15321 * Longer term, improved solutions could be:
15322 * - Disallow painting in the paint signal, only allow using it
15323 * for tracking when paints happen. We can add another API that
15324 * allows monkey patching the paint of arbitrary actors but in a
15325 * more controlled way and that also supports modifying the
15327 * - If we could be notified somehow when signal handlers are
15328 * connected we wouldn't have to poll for handlers like this.
15330 if (g_signal_has_handler_pending (self,
15331 actor_signals[PAINT],
15335 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15336 "Actor has \"paint\" signal handlers",
15337 _clutter_actor_get_debug_name (self));
15341 _clutter_paint_volume_init_static (pv, self);
15343 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15345 clutter_paint_volume_free (pv);
15346 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15347 "Actor failed to report a volume",
15348 _clutter_actor_get_debug_name (self));
15352 /* since effects can modify the paint volume, we allow them to actually
15353 * do this by making get_paint_volume() "context sensitive"
15355 if (priv->effects != NULL)
15357 if (priv->current_effect != NULL)
15359 const GList *effects, *l;
15361 /* if we are being called from within the paint sequence of
15362 * an actor, get the paint volume up to the current effect
15364 effects = _clutter_meta_group_peek_metas (priv->effects);
15366 l != NULL || (l != NULL && l->data != priv->current_effect);
15369 if (!_clutter_effect_get_paint_volume (l->data, pv))
15371 clutter_paint_volume_free (pv);
15372 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15373 "Effect (%s) failed to report a volume",
15374 _clutter_actor_get_debug_name (self),
15375 _clutter_actor_meta_get_debug_name (l->data));
15382 const GList *effects, *l;
15384 /* otherwise, get the cumulative volume */
15385 effects = _clutter_meta_group_peek_metas (priv->effects);
15386 for (l = effects; l != NULL; l = l->next)
15387 if (!_clutter_effect_get_paint_volume (l->data, pv))
15389 clutter_paint_volume_free (pv);
15390 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15391 "Effect (%s) failed to report a volume",
15392 _clutter_actor_get_debug_name (self),
15393 _clutter_actor_meta_get_debug_name (l->data));
15402 /* The public clutter_actor_get_paint_volume API returns a const
15403 * pointer since we return a pointer directly to the cached
15404 * PaintVolume associated with the actor and don't want the user to
15405 * inadvertently modify it, but for internal uses we sometimes need
15406 * access to the same PaintVolume but need to apply some book-keeping
15407 * modifications to it so we don't want a const pointer.
15409 static ClutterPaintVolume *
15410 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15412 ClutterActorPrivate *priv;
15416 if (priv->paint_volume_valid)
15417 clutter_paint_volume_free (&priv->paint_volume);
15419 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15421 priv->paint_volume_valid = TRUE;
15422 return &priv->paint_volume;
15426 priv->paint_volume_valid = FALSE;
15432 * clutter_actor_get_paint_volume:
15433 * @self: a #ClutterActor
15435 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15436 * when a paint volume can't be determined.
15438 * The paint volume is defined as the 3D space occupied by an actor
15439 * when being painted.
15441 * This function will call the <function>get_paint_volume()</function>
15442 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15443 * should not usually care about overriding the default implementation,
15444 * unless they are, for instance: painting outside their allocation, or
15445 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15448 * <note>2D actors overriding <function>get_paint_volume()</function>
15449 * ensure their volume has a depth of 0. (This will be true so long as
15450 * you don't call clutter_paint_volume_set_depth().)</note>
15452 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15453 * or %NULL if no volume could be determined. The returned pointer
15454 * is not guaranteed to be valid across multiple frames; if you want
15455 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15459 const ClutterPaintVolume *
15460 clutter_actor_get_paint_volume (ClutterActor *self)
15462 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15464 return _clutter_actor_get_paint_volume_mutable (self);
15468 * clutter_actor_get_transformed_paint_volume:
15469 * @self: a #ClutterActor
15470 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15471 * (or %NULL for the stage)
15473 * Retrieves the 3D paint volume of an actor like
15474 * clutter_actor_get_paint_volume() does (Please refer to the
15475 * documentation of clutter_actor_get_paint_volume() for more
15476 * details.) and it additionally transforms the paint volume into the
15477 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15478 * is passed for @relative_to_ancestor)
15480 * This can be used by containers that base their paint volume on
15481 * the volume of their children. Such containers can query the
15482 * transformed paint volume of all of its children and union them
15483 * together using clutter_paint_volume_union().
15485 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15486 * or %NULL if no volume could be determined. The returned pointer is
15487 * not guaranteed to be valid across multiple frames; if you wish to
15488 * keep it, you will have to copy it using clutter_paint_volume_copy().
15492 const ClutterPaintVolume *
15493 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15494 ClutterActor *relative_to_ancestor)
15496 const ClutterPaintVolume *volume;
15497 ClutterActor *stage;
15498 ClutterPaintVolume *transformed_volume;
15500 stage = _clutter_actor_get_stage_internal (self);
15501 if (G_UNLIKELY (stage == NULL))
15504 if (relative_to_ancestor == NULL)
15505 relative_to_ancestor = stage;
15507 volume = clutter_actor_get_paint_volume (self);
15508 if (volume == NULL)
15511 transformed_volume =
15512 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15514 _clutter_paint_volume_copy_static (volume, transformed_volume);
15516 _clutter_paint_volume_transform_relative (transformed_volume,
15517 relative_to_ancestor);
15519 return transformed_volume;
15523 * clutter_actor_get_paint_box:
15524 * @self: a #ClutterActor
15525 * @box: (out): return location for a #ClutterActorBox
15527 * Retrieves the paint volume of the passed #ClutterActor, and
15528 * transforms it into a 2D bounding box in stage coordinates.
15530 * This function is useful to determine the on screen area occupied by
15531 * the actor. The box is only an approximation and may often be
15532 * considerably larger due to the optimizations used to calculate the
15533 * box. The box is never smaller though, so it can reliably be used
15536 * There are times when a 2D paint box can't be determined, e.g.
15537 * because the actor isn't yet parented under a stage or because
15538 * the actor is unable to determine a paint volume.
15540 * Return value: %TRUE if a 2D paint box could be determined, else
15546 clutter_actor_get_paint_box (ClutterActor *self,
15547 ClutterActorBox *box)
15549 ClutterActor *stage;
15550 ClutterPaintVolume *pv;
15552 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15553 g_return_val_if_fail (box != NULL, FALSE);
15555 stage = _clutter_actor_get_stage_internal (self);
15556 if (G_UNLIKELY (!stage))
15559 pv = _clutter_actor_get_paint_volume_mutable (self);
15560 if (G_UNLIKELY (!pv))
15563 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15569 * clutter_actor_has_overlaps:
15570 * @self: A #ClutterActor
15572 * Asks the actor's implementation whether it may contain overlapping
15575 * For example; Clutter may use this to determine whether the painting
15576 * should be redirected to an offscreen buffer to correctly implement
15577 * the opacity property.
15579 * Custom actors can override the default response by implementing the
15580 * #ClutterActor <function>has_overlaps</function> virtual function. See
15581 * clutter_actor_set_offscreen_redirect() for more information.
15583 * Return value: %TRUE if the actor may have overlapping primitives, and
15589 clutter_actor_has_overlaps (ClutterActor *self)
15591 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15593 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15597 * clutter_actor_has_effects:
15598 * @self: A #ClutterActor
15600 * Returns whether the actor has any effects applied.
15602 * Return value: %TRUE if the actor has any effects,
15608 clutter_actor_has_effects (ClutterActor *self)
15610 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15612 if (self->priv->effects == NULL)
15615 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15619 * clutter_actor_has_constraints:
15620 * @self: A #ClutterActor
15622 * Returns whether the actor has any constraints applied.
15624 * Return value: %TRUE if the actor has any constraints,
15630 clutter_actor_has_constraints (ClutterActor *self)
15632 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15634 return self->priv->constraints != NULL;
15638 * clutter_actor_has_actions:
15639 * @self: A #ClutterActor
15641 * Returns whether the actor has any actions applied.
15643 * Return value: %TRUE if the actor has any actions,
15649 clutter_actor_has_actions (ClutterActor *self)
15651 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15653 return self->priv->actions != NULL;
15657 * clutter_actor_get_n_children:
15658 * @self: a #ClutterActor
15660 * Retrieves the number of children of @self.
15662 * Return value: the number of children of an actor
15667 clutter_actor_get_n_children (ClutterActor *self)
15669 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15671 return self->priv->n_children;
15675 * clutter_actor_get_child_at_index:
15676 * @self: a #ClutterActor
15677 * @index_: the position in the list of children
15679 * Retrieves the actor at the given @index_ inside the list of
15680 * children of @self.
15682 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15687 clutter_actor_get_child_at_index (ClutterActor *self,
15690 ClutterActor *iter;
15693 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15694 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15696 for (iter = self->priv->first_child, i = 0;
15697 iter != NULL && i < index_;
15698 iter = iter->priv->next_sibling, i += 1)
15705 * _clutter_actor_foreach_child:
15706 * @actor: The actor whos children you want to iterate
15707 * @callback: The function to call for each child
15708 * @user_data: Private data to pass to @callback
15710 * Calls a given @callback once for each child of the specified @actor and
15711 * passing the @user_data pointer each time.
15713 * Return value: returns %TRUE if all children were iterated, else
15714 * %FALSE if a callback broke out of iteration early.
15717 _clutter_actor_foreach_child (ClutterActor *self,
15718 ClutterForeachCallback callback,
15719 gpointer user_data)
15721 ClutterActorPrivate *priv = self->priv;
15722 ClutterActor *iter;
15725 for (cont = TRUE, iter = priv->first_child;
15726 cont && iter != NULL;
15727 iter = iter->priv->next_sibling)
15729 cont = callback (iter, user_data);
15736 /* For debugging purposes this gives us a simple way to print out
15737 * the scenegraph e.g in gdb using:
15739 * _clutter_actor_traverse (stage,
15741 * clutter_debug_print_actor_cb,
15746 static ClutterActorTraverseVisitFlags
15747 clutter_debug_print_actor_cb (ClutterActor *actor,
15751 g_print ("%*s%s:%p\n",
15753 _clutter_actor_get_debug_name (actor),
15756 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15761 _clutter_actor_traverse_breadth (ClutterActor *actor,
15762 ClutterTraverseCallback callback,
15763 gpointer user_data)
15765 GQueue *queue = g_queue_new ();
15766 ClutterActor dummy;
15767 int current_depth = 0;
15769 g_queue_push_tail (queue, actor);
15770 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15772 while ((actor = g_queue_pop_head (queue)))
15774 ClutterActorTraverseVisitFlags flags;
15776 if (actor == &dummy)
15779 g_queue_push_tail (queue, &dummy);
15783 flags = callback (actor, current_depth, user_data);
15784 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15786 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15788 ClutterActor *iter;
15790 for (iter = actor->priv->first_child;
15792 iter = iter->priv->next_sibling)
15794 g_queue_push_tail (queue, iter);
15799 g_queue_free (queue);
15802 static ClutterActorTraverseVisitFlags
15803 _clutter_actor_traverse_depth (ClutterActor *actor,
15804 ClutterTraverseCallback before_children_callback,
15805 ClutterTraverseCallback after_children_callback,
15807 gpointer user_data)
15809 ClutterActorTraverseVisitFlags flags;
15811 flags = before_children_callback (actor, current_depth, user_data);
15812 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15813 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15815 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15817 ClutterActor *iter;
15819 for (iter = actor->priv->first_child;
15821 iter = iter->priv->next_sibling)
15823 flags = _clutter_actor_traverse_depth (iter,
15824 before_children_callback,
15825 after_children_callback,
15829 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15830 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15834 if (after_children_callback)
15835 return after_children_callback (actor, current_depth, user_data);
15837 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15840 /* _clutter_actor_traverse:
15841 * @actor: The actor to start traversing the graph from
15842 * @flags: These flags may affect how the traversal is done
15843 * @before_children_callback: A function to call before visiting the
15844 * children of the current actor.
15845 * @after_children_callback: A function to call after visiting the
15846 * children of the current actor. (Ignored if
15847 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15848 * @user_data: The private data to pass to the callbacks
15850 * Traverses the scenegraph starting at the specified @actor and
15851 * descending through all its children and its children's children.
15852 * For each actor traversed @before_children_callback and
15853 * @after_children_callback are called with the specified
15854 * @user_data, before and after visiting that actor's children.
15856 * The callbacks can return flags that affect the ongoing traversal
15857 * such as by skipping over an actors children or bailing out of
15858 * any further traversing.
15861 _clutter_actor_traverse (ClutterActor *actor,
15862 ClutterActorTraverseFlags flags,
15863 ClutterTraverseCallback before_children_callback,
15864 ClutterTraverseCallback after_children_callback,
15865 gpointer user_data)
15867 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15868 _clutter_actor_traverse_breadth (actor,
15869 before_children_callback,
15871 else /* DEPTH_FIRST */
15872 _clutter_actor_traverse_depth (actor,
15873 before_children_callback,
15874 after_children_callback,
15875 0, /* start depth */
15880 on_layout_manager_changed (ClutterLayoutManager *manager,
15881 ClutterActor *self)
15883 clutter_actor_queue_relayout (self);
15887 * clutter_actor_set_layout_manager:
15888 * @self: a #ClutterActor
15889 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15891 * Sets the #ClutterLayoutManager delegate object that will be used to
15892 * lay out the children of @self.
15894 * The #ClutterActor will take a reference on the passed @manager which
15895 * will be released either when the layout manager is removed, or when
15896 * the actor is destroyed.
15901 clutter_actor_set_layout_manager (ClutterActor *self,
15902 ClutterLayoutManager *manager)
15904 ClutterActorPrivate *priv;
15906 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15907 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15911 if (priv->layout_manager != NULL)
15913 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15914 G_CALLBACK (on_layout_manager_changed),
15916 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15917 g_clear_object (&priv->layout_manager);
15920 priv->layout_manager = manager;
15922 if (priv->layout_manager != NULL)
15924 g_object_ref_sink (priv->layout_manager);
15925 clutter_layout_manager_set_container (priv->layout_manager,
15926 CLUTTER_CONTAINER (self));
15927 g_signal_connect (priv->layout_manager, "layout-changed",
15928 G_CALLBACK (on_layout_manager_changed),
15932 clutter_actor_queue_relayout (self);
15934 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15938 * clutter_actor_get_layout_manager:
15939 * @self: a #ClutterActor
15941 * Retrieves the #ClutterLayoutManager used by @self.
15943 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15948 ClutterLayoutManager *
15949 clutter_actor_get_layout_manager (ClutterActor *self)
15951 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15953 return self->priv->layout_manager;
15956 static const ClutterLayoutInfo default_layout_info = {
15959 { 0, 0, 0, 0 }, /* margin */
15960 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15961 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15962 0.f, 0.f, /* min_width, natural_width */
15963 0.f, 0.f, /* natual_width, natural_height */
15967 layout_info_free (gpointer data)
15969 if (G_LIKELY (data != NULL))
15970 g_slice_free (ClutterLayoutInfo, data);
15974 * _clutter_actor_get_layout_info:
15975 * @self: a #ClutterActor
15977 * Retrieves a pointer to the ClutterLayoutInfo structure.
15979 * If the actor does not have a ClutterLayoutInfo associated to it, one
15980 * will be created and initialized to the default values.
15982 * This function should be used for setters.
15984 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15987 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15989 ClutterLayoutInfo *
15990 _clutter_actor_get_layout_info (ClutterActor *self)
15992 ClutterLayoutInfo *retval;
15994 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15995 if (retval == NULL)
15997 retval = g_slice_new (ClutterLayoutInfo);
15999 *retval = default_layout_info;
16001 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16010 * _clutter_actor_get_layout_info_or_defaults:
16011 * @self: a #ClutterActor
16013 * Retrieves the ClutterLayoutInfo structure associated to an actor.
16015 * If the actor does not have a ClutterLayoutInfo structure associated to it,
16016 * then the default structure will be returned.
16018 * This function should only be used for getters.
16020 * Return value: a const pointer to the ClutterLayoutInfo structure
16022 const ClutterLayoutInfo *
16023 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16025 const ClutterLayoutInfo *info;
16027 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16029 return &default_layout_info;
16035 * clutter_actor_set_x_align:
16036 * @self: a #ClutterActor
16037 * @x_align: the horizontal alignment policy
16039 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16040 * actor received extra horizontal space.
16042 * See also the #ClutterActor:x-align property.
16047 clutter_actor_set_x_align (ClutterActor *self,
16048 ClutterActorAlign x_align)
16050 ClutterLayoutInfo *info;
16052 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16054 info = _clutter_actor_get_layout_info (self);
16056 if (info->x_align != x_align)
16058 info->x_align = x_align;
16060 clutter_actor_queue_relayout (self);
16062 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16067 * clutter_actor_get_x_align:
16068 * @self: a #ClutterActor
16070 * Retrieves the horizontal alignment policy set using
16071 * clutter_actor_set_x_align().
16073 * Return value: the horizontal alignment policy.
16078 clutter_actor_get_x_align (ClutterActor *self)
16080 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16082 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16086 * clutter_actor_set_y_align:
16087 * @self: a #ClutterActor
16088 * @y_align: the vertical alignment policy
16090 * Sets the vertical alignment policy of a #ClutterActor, in case the
16091 * actor received extra vertical space.
16093 * See also the #ClutterActor:y-align property.
16098 clutter_actor_set_y_align (ClutterActor *self,
16099 ClutterActorAlign y_align)
16101 ClutterLayoutInfo *info;
16103 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16105 info = _clutter_actor_get_layout_info (self);
16107 if (info->y_align != y_align)
16109 info->y_align = y_align;
16111 clutter_actor_queue_relayout (self);
16113 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16118 * clutter_actor_get_y_align:
16119 * @self: a #ClutterActor
16121 * Retrieves the vertical alignment policy set using
16122 * clutter_actor_set_y_align().
16124 * Return value: the vertical alignment policy.
16129 clutter_actor_get_y_align (ClutterActor *self)
16131 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16133 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16138 * clutter_margin_new:
16140 * Creates a new #ClutterMargin.
16142 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16143 * clutter_margin_free() to free the resources associated with it when
16149 clutter_margin_new (void)
16151 return g_slice_new0 (ClutterMargin);
16155 * clutter_margin_copy:
16156 * @margin_: a #ClutterMargin
16158 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16159 * the newly created structure.
16161 * Return value: (transfer full): a copy of the #ClutterMargin.
16166 clutter_margin_copy (const ClutterMargin *margin_)
16168 if (G_LIKELY (margin_ != NULL))
16169 return g_slice_dup (ClutterMargin, margin_);
16175 * clutter_margin_free:
16176 * @margin_: a #ClutterMargin
16178 * Frees the resources allocated by clutter_margin_new() and
16179 * clutter_margin_copy().
16184 clutter_margin_free (ClutterMargin *margin_)
16186 if (G_LIKELY (margin_ != NULL))
16187 g_slice_free (ClutterMargin, margin_);
16190 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16191 clutter_margin_copy,
16192 clutter_margin_free)
16195 * clutter_actor_set_margin:
16196 * @self: a #ClutterActor
16197 * @margin: a #ClutterMargin
16199 * Sets all the components of the margin of a #ClutterActor.
16204 clutter_actor_set_margin (ClutterActor *self,
16205 const ClutterMargin *margin)
16207 ClutterLayoutInfo *info;
16211 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16212 g_return_if_fail (margin != NULL);
16214 obj = G_OBJECT (self);
16217 g_object_freeze_notify (obj);
16219 info = _clutter_actor_get_layout_info (self);
16221 if (info->margin.top != margin->top)
16223 info->margin.top = margin->top;
16224 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16228 if (info->margin.right != margin->right)
16230 info->margin.right = margin->right;
16231 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16235 if (info->margin.bottom != margin->bottom)
16237 info->margin.bottom = margin->bottom;
16238 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16242 if (info->margin.left != margin->left)
16244 info->margin.left = margin->left;
16245 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16250 clutter_actor_queue_relayout (self);
16252 g_object_thaw_notify (obj);
16256 * clutter_actor_get_margin:
16257 * @self: a #ClutterActor
16258 * @margin: (out caller-allocates): return location for a #ClutterMargin
16260 * Retrieves all the components of the margin of a #ClutterActor.
16265 clutter_actor_get_margin (ClutterActor *self,
16266 ClutterMargin *margin)
16268 const ClutterLayoutInfo *info;
16270 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16271 g_return_if_fail (margin != NULL);
16273 info = _clutter_actor_get_layout_info_or_defaults (self);
16275 *margin = info->margin;
16279 * clutter_actor_set_margin_top:
16280 * @self: a #ClutterActor
16281 * @margin: the top margin
16283 * Sets the margin from the top of a #ClutterActor.
16288 clutter_actor_set_margin_top (ClutterActor *self,
16291 ClutterLayoutInfo *info;
16293 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16294 g_return_if_fail (margin >= 0.f);
16296 info = _clutter_actor_get_layout_info (self);
16298 if (info->margin.top == margin)
16301 info->margin.top = margin;
16303 clutter_actor_queue_relayout (self);
16305 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16309 * clutter_actor_get_margin_top:
16310 * @self: a #ClutterActor
16312 * Retrieves the top margin of a #ClutterActor.
16314 * Return value: the top margin
16319 clutter_actor_get_margin_top (ClutterActor *self)
16321 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16323 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16327 * clutter_actor_set_margin_bottom:
16328 * @self: a #ClutterActor
16329 * @margin: the bottom margin
16331 * Sets the margin from the bottom of a #ClutterActor.
16336 clutter_actor_set_margin_bottom (ClutterActor *self,
16339 ClutterLayoutInfo *info;
16341 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16342 g_return_if_fail (margin >= 0.f);
16344 info = _clutter_actor_get_layout_info (self);
16346 if (info->margin.bottom == margin)
16349 info->margin.bottom = margin;
16351 clutter_actor_queue_relayout (self);
16353 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16357 * clutter_actor_get_margin_bottom:
16358 * @self: a #ClutterActor
16360 * Retrieves the bottom margin of a #ClutterActor.
16362 * Return value: the bottom margin
16367 clutter_actor_get_margin_bottom (ClutterActor *self)
16369 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16371 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16375 * clutter_actor_set_margin_left:
16376 * @self: a #ClutterActor
16377 * @margin: the left margin
16379 * Sets the margin from the left of a #ClutterActor.
16384 clutter_actor_set_margin_left (ClutterActor *self,
16387 ClutterLayoutInfo *info;
16389 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16390 g_return_if_fail (margin >= 0.f);
16392 info = _clutter_actor_get_layout_info (self);
16394 if (info->margin.left == margin)
16397 info->margin.left = margin;
16399 clutter_actor_queue_relayout (self);
16401 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16405 * clutter_actor_get_margin_left:
16406 * @self: a #ClutterActor
16408 * Retrieves the left margin of a #ClutterActor.
16410 * Return value: the left margin
16415 clutter_actor_get_margin_left (ClutterActor *self)
16417 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16419 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16423 * clutter_actor_set_margin_right:
16424 * @self: a #ClutterActor
16425 * @margin: the right margin
16427 * Sets the margin from the right of a #ClutterActor.
16432 clutter_actor_set_margin_right (ClutterActor *self,
16435 ClutterLayoutInfo *info;
16437 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16438 g_return_if_fail (margin >= 0.f);
16440 info = _clutter_actor_get_layout_info (self);
16442 if (info->margin.right == margin)
16445 info->margin.right = margin;
16447 clutter_actor_queue_relayout (self);
16449 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16453 * clutter_actor_get_margin_right:
16454 * @self: a #ClutterActor
16456 * Retrieves the right margin of a #ClutterActor.
16458 * Return value: the right margin
16463 clutter_actor_get_margin_right (ClutterActor *self)
16465 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16467 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16471 clutter_actor_set_background_color_internal (ClutterActor *self,
16472 const ClutterColor *color)
16474 ClutterActorPrivate *priv = self->priv;
16477 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16480 obj = G_OBJECT (self);
16482 priv->bg_color = *color;
16483 priv->bg_color_set = TRUE;
16485 clutter_actor_queue_redraw (self);
16487 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16488 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16492 * clutter_actor_set_background_color:
16493 * @self: a #ClutterActor
16494 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16497 * Sets the background color of a #ClutterActor.
16499 * The background color will be used to cover the whole allocation of the
16500 * actor. The default background color of an actor is transparent.
16502 * To check whether an actor has a background color, you can use the
16503 * #ClutterActor:background-color-set actor property.
16505 * The #ClutterActor:background-color property is animatable.
16510 clutter_actor_set_background_color (ClutterActor *self,
16511 const ClutterColor *color)
16513 ClutterActorPrivate *priv;
16515 GParamSpec *bg_color_pspec;
16517 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16519 obj = G_OBJECT (self);
16525 priv->bg_color_set = FALSE;
16526 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16527 clutter_actor_queue_redraw (self);
16531 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16532 if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16534 _clutter_actor_create_transition (self, bg_color_pspec,
16539 _clutter_actor_update_transition (self, bg_color_pspec, color);
16541 clutter_actor_queue_redraw (self);
16545 * clutter_actor_get_background_color:
16546 * @self: a #ClutterActor
16547 * @color: (out caller-allocates): return location for a #ClutterColor
16549 * Retrieves the color set using clutter_actor_set_background_color().
16554 clutter_actor_get_background_color (ClutterActor *self,
16555 ClutterColor *color)
16557 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16558 g_return_if_fail (color != NULL);
16560 *color = self->priv->bg_color;
16564 * clutter_actor_get_previous_sibling:
16565 * @self: a #ClutterActor
16567 * Retrieves the sibling of @self that comes before it in the list
16568 * of children of @self's parent.
16570 * The returned pointer is only valid until the scene graph changes; it
16571 * is not safe to modify the list of children of @self while iterating
16574 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16579 clutter_actor_get_previous_sibling (ClutterActor *self)
16581 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16583 return self->priv->prev_sibling;
16587 * clutter_actor_get_next_sibling:
16588 * @self: a #ClutterActor
16590 * Retrieves the sibling of @self that comes after it in the list
16591 * of children of @self's parent.
16593 * The returned pointer is only valid until the scene graph changes; it
16594 * is not safe to modify the list of children of @self while iterating
16597 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16602 clutter_actor_get_next_sibling (ClutterActor *self)
16604 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16606 return self->priv->next_sibling;
16610 * clutter_actor_get_first_child:
16611 * @self: a #ClutterActor
16613 * Retrieves the first child of @self.
16615 * The returned pointer is only valid until the scene graph changes; it
16616 * is not safe to modify the list of children of @self while iterating
16619 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16624 clutter_actor_get_first_child (ClutterActor *self)
16626 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16628 return self->priv->first_child;
16632 * clutter_actor_get_last_child:
16633 * @self: a #ClutterActor
16635 * Retrieves the last child of @self.
16637 * The returned pointer is only valid until the scene graph changes; it
16638 * is not safe to modify the list of children of @self while iterating
16641 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16646 clutter_actor_get_last_child (ClutterActor *self)
16648 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16650 return self->priv->last_child;
16653 /* easy way to have properly named fields instead of the dummy ones
16654 * we use in the public structure
16656 typedef struct _RealActorIter
16658 ClutterActor *root; /* dummy1 */
16659 ClutterActor *current; /* dummy2 */
16660 gpointer padding_1; /* dummy3 */
16661 gint age; /* dummy4 */
16662 gpointer padding_2; /* dummy5 */
16666 * clutter_actor_iter_init:
16667 * @iter: a #ClutterActorIter
16668 * @root: a #ClutterActor
16670 * Initializes a #ClutterActorIter, which can then be used to iterate
16671 * efficiently over a section of the scene graph, and associates it
16674 * Modifying the scene graph section that contains @root will invalidate
16678 * ClutterActorIter iter;
16679 * ClutterActor *child;
16681 * clutter_actor_iter_init (&iter, container);
16682 * while (clutter_actor_iter_next (&iter, &child))
16684 * /* do something with child */
16691 clutter_actor_iter_init (ClutterActorIter *iter,
16692 ClutterActor *root)
16694 RealActorIter *ri = (RealActorIter *) iter;
16696 g_return_if_fail (iter != NULL);
16697 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16700 ri->current = NULL;
16701 ri->age = root->priv->age;
16705 * clutter_actor_iter_next:
16706 * @iter: a #ClutterActorIter
16707 * @child: (out): return location for a #ClutterActor
16709 * Advances the @iter and retrieves the next child of the root #ClutterActor
16710 * that was used to initialize the #ClutterActorIterator.
16712 * If the iterator can advance, this function returns %TRUE and sets the
16715 * If the iterator cannot advance, this function returns %FALSE, and
16716 * the contents of @child are undefined.
16718 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16723 clutter_actor_iter_next (ClutterActorIter *iter,
16724 ClutterActor **child)
16726 RealActorIter *ri = (RealActorIter *) iter;
16728 g_return_val_if_fail (iter != NULL, FALSE);
16729 g_return_val_if_fail (ri->root != NULL, FALSE);
16730 #ifndef G_DISABLE_ASSERT
16731 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16734 if (ri->current == NULL)
16735 ri->current = ri->root->priv->first_child;
16737 ri->current = ri->current->priv->next_sibling;
16740 *child = ri->current;
16742 return ri->current != NULL;
16746 * clutter_actor_iter_prev:
16747 * @iter: a #ClutterActorIter
16748 * @child: (out): return location for a #ClutterActor
16750 * Advances the @iter and retrieves the previous child of the root
16751 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16753 * If the iterator can advance, this function returns %TRUE and sets the
16756 * If the iterator cannot advance, this function returns %FALSE, and
16757 * the contents of @child are undefined.
16759 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16764 clutter_actor_iter_prev (ClutterActorIter *iter,
16765 ClutterActor **child)
16767 RealActorIter *ri = (RealActorIter *) iter;
16769 g_return_val_if_fail (iter != NULL, FALSE);
16770 g_return_val_if_fail (ri->root != NULL, FALSE);
16771 #ifndef G_DISABLE_ASSERT
16772 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16775 if (ri->current == NULL)
16776 ri->current = ri->root->priv->last_child;
16778 ri->current = ri->current->priv->prev_sibling;
16781 *child = ri->current;
16783 return ri->current != NULL;
16787 * clutter_actor_iter_remove:
16788 * @iter: a #ClutterActorIter
16790 * Safely removes the #ClutterActor currently pointer to by the iterator
16793 * This function can only be called after clutter_actor_iter_next() or
16794 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16795 * than once for the same actor.
16797 * This function will call clutter_actor_remove_child() internally.
16802 clutter_actor_iter_remove (ClutterActorIter *iter)
16804 RealActorIter *ri = (RealActorIter *) iter;
16807 g_return_if_fail (iter != NULL);
16808 g_return_if_fail (ri->root != NULL);
16809 #ifndef G_DISABLE_ASSERT
16810 g_return_if_fail (ri->age == ri->root->priv->age);
16812 g_return_if_fail (ri->current != NULL);
16818 ri->current = cur->priv->prev_sibling;
16820 clutter_actor_remove_child_internal (ri->root, cur,
16821 REMOVE_CHILD_DEFAULT_FLAGS);
16828 * clutter_actor_iter_destroy:
16829 * @iter: a #ClutterActorIter
16831 * Safely destroys the #ClutterActor currently pointer to by the iterator
16834 * This function can only be called after clutter_actor_iter_next() or
16835 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16836 * than once for the same actor.
16838 * This function will call clutter_actor_destroy() internally.
16843 clutter_actor_iter_destroy (ClutterActorIter *iter)
16845 RealActorIter *ri = (RealActorIter *) iter;
16848 g_return_if_fail (iter != NULL);
16849 g_return_if_fail (ri->root != NULL);
16850 #ifndef G_DISABLE_ASSERT
16851 g_return_if_fail (ri->age == ri->root->priv->age);
16853 g_return_if_fail (ri->current != NULL);
16859 ri->current = cur->priv->prev_sibling;
16861 clutter_actor_destroy (cur);
16867 static const ClutterAnimationInfo default_animation_info = {
16868 NULL, /* transitions */
16870 NULL, /* cur_state */
16874 clutter_animation_info_free (gpointer data)
16878 ClutterAnimationInfo *info = data;
16880 if (info->transitions != NULL)
16881 g_hash_table_unref (info->transitions);
16883 if (info->states != NULL)
16884 g_array_unref (info->states);
16886 g_slice_free (ClutterAnimationInfo, info);
16890 const ClutterAnimationInfo *
16891 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16893 const ClutterAnimationInfo *res;
16894 GObject *obj = G_OBJECT (self);
16896 res = g_object_get_qdata (obj, quark_actor_animation_info);
16900 return &default_animation_info;
16903 ClutterAnimationInfo *
16904 _clutter_actor_get_animation_info (ClutterActor *self)
16906 GObject *obj = G_OBJECT (self);
16907 ClutterAnimationInfo *res;
16909 res = g_object_get_qdata (obj, quark_actor_animation_info);
16912 res = g_slice_new (ClutterAnimationInfo);
16914 *res = default_animation_info;
16916 g_object_set_qdata_full (obj, quark_actor_animation_info,
16918 clutter_animation_info_free);
16924 ClutterTransition *
16925 _clutter_actor_get_transition (ClutterActor *actor,
16928 const ClutterAnimationInfo *info;
16930 info = _clutter_actor_get_animation_info_or_defaults (actor);
16932 if (info->transitions == NULL)
16935 return g_hash_table_lookup (info->transitions, pspec->name);
16938 typedef struct _TransitionClosure
16940 ClutterActor *actor;
16941 ClutterTransition *transition;
16943 gulong completed_id;
16944 } TransitionClosure;
16947 transition_closure_free (gpointer data)
16949 if (G_LIKELY (data != NULL))
16951 TransitionClosure *clos = data;
16953 if (clutter_timeline_is_playing (CLUTTER_TIMELINE (clos->transition)))
16954 clutter_timeline_stop (CLUTTER_TIMELINE (clos->transition));
16956 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16958 g_object_unref (clos->transition);
16959 g_free (clos->name);
16961 g_slice_free (TransitionClosure, clos);
16966 on_transition_completed (ClutterTransition *transition,
16967 TransitionClosure *clos)
16969 ClutterActor *actor = clos->actor;
16970 ClutterAnimationInfo *info;
16972 info = _clutter_actor_get_animation_info (actor);
16974 /* this will take care of cleaning clos for us */
16975 if (clutter_transition_get_remove_on_complete (transition))
16977 /* we take a reference here because removing the closure
16978 * will release the reference on the transition, and we
16979 * want the transition to survive the signal emission;
16980 * the master clock will release the laste reference at
16981 * the end of the frame processing.
16983 g_object_ref (transition);
16984 g_hash_table_remove (info->transitions, clos->name);
16987 /* if it's the last transition then we clean up */
16988 if (g_hash_table_size (info->transitions) == 0)
16990 g_hash_table_unref (info->transitions);
16991 info->transitions = NULL;
16993 CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
16994 _clutter_actor_get_debug_name (actor));
16996 g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17001 _clutter_actor_update_transition (ClutterActor *actor,
17005 TransitionClosure *clos;
17006 ClutterInterval *interval;
17007 const ClutterAnimationInfo *info;
17010 GValue initial = G_VALUE_INIT;
17011 GValue final = G_VALUE_INIT;
17012 char *error = NULL;
17014 info = _clutter_actor_get_animation_info_or_defaults (actor);
17016 if (info->transitions == NULL)
17019 clos = g_hash_table_lookup (info->transitions, pspec->name);
17023 va_start (var_args, pspec);
17025 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17027 g_value_init (&initial, ptype);
17028 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17032 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17035 g_critical ("%s: %s", G_STRLOC, error);
17040 interval = clutter_transition_get_interval (clos->transition);
17041 clutter_interval_set_initial_value (interval, &initial);
17042 clutter_interval_set_final_value (interval, &final);
17044 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
17047 g_value_unset (&initial);
17048 g_value_unset (&final);
17054 * _clutter_actor_create_transition:
17055 * @actor: a #ClutterActor
17056 * @pspec: the property used for the transition
17057 * @...: initial and final state
17059 * Creates a #ClutterTransition for the property represented by @pspec.
17061 * Return value: a #ClutterTransition
17063 ClutterTransition *
17064 _clutter_actor_create_transition (ClutterActor *actor,
17068 ClutterAnimationInfo *info;
17069 ClutterTransition *res = NULL;
17070 gboolean call_restore = FALSE;
17071 TransitionClosure *clos;
17074 info = _clutter_actor_get_animation_info (actor);
17076 /* XXX - this will go away in 2.0
17078 * if no state has been pushed, we assume that the easing state is
17079 * in "compatibility mode": all transitions have a duration of 0
17080 * msecs, which means that they happen immediately. in Clutter 2.0
17081 * this will turn into a g_assert(info->states != NULL), as every
17082 * actor will start with a predefined easing state
17084 if (info->states == NULL)
17086 clutter_actor_save_easing_state (actor);
17087 clutter_actor_set_easing_duration (actor, 0);
17088 call_restore = TRUE;
17091 if (info->transitions == NULL)
17092 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17094 transition_closure_free);
17096 va_start (var_args, pspec);
17098 clos = g_hash_table_lookup (info->transitions, pspec->name);
17101 ClutterInterval *interval;
17102 GValue initial = G_VALUE_INIT;
17103 GValue final = G_VALUE_INIT;
17107 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17109 G_VALUE_COLLECT_INIT (&initial, ptype,
17114 g_critical ("%s: %s", G_STRLOC, error);
17119 G_VALUE_COLLECT_INIT (&final, ptype,
17125 g_critical ("%s: %s", G_STRLOC, error);
17126 g_value_unset (&initial);
17131 /* if the current easing state has a duration of 0, then we don't
17132 * bother to create the transition, and we just set the final value
17133 * directly on the actor; we don't go through the Animatable
17134 * interface because we know we got here through an animatable
17137 if (info->cur_state->easing_duration == 0)
17139 clutter_actor_set_animatable_property (actor,
17143 g_value_unset (&initial);
17144 g_value_unset (&final);
17149 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17151 g_value_unset (&initial);
17152 g_value_unset (&final);
17154 res = clutter_property_transition_new (pspec->name);
17156 clutter_transition_set_interval (res, interval);
17157 clutter_transition_set_remove_on_complete (res, TRUE);
17159 /* this will start the transition as well */
17160 clutter_actor_add_transition (actor, pspec->name, res);
17162 /* the actor now owns the transition */
17163 g_object_unref (res);
17166 res = clos->transition;
17170 clutter_actor_restore_easing_state (actor);
17178 * clutter_actor_add_transition:
17179 * @self: a #ClutterActor
17180 * @name: the name of the transition to add
17181 * @transition: the #ClutterTransition to add
17183 * Adds a @transition to the #ClutterActor's list of animations.
17185 * The @name string is a per-actor unique identifier of the @transition: only
17186 * one #ClutterTransition can be associated to the specified @name.
17188 * The @transition will be given the easing duration, mode, and delay
17189 * associated to the actor's current easing state; it is possible to modify
17190 * these values after calling clutter_actor_add_transition().
17192 * The @transition will be started once added.
17194 * This function will take a reference on the @transition.
17196 * This function is usually called implicitly when modifying an animatable
17202 clutter_actor_add_transition (ClutterActor *self,
17204 ClutterTransition *transition)
17206 ClutterTimeline *timeline;
17207 TransitionClosure *clos;
17208 ClutterAnimationInfo *info;
17210 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17211 g_return_if_fail (name != NULL);
17212 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17214 info = _clutter_actor_get_animation_info (self);
17216 if (info->cur_state == NULL)
17218 g_warning ("No easing state is defined for the actor '%s'; you "
17219 "must call clutter_actor_save_easing_state() before "
17220 "calling clutter_actor_add_transition().",
17221 _clutter_actor_get_debug_name (self));
17225 if (info->transitions == NULL)
17226 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17228 transition_closure_free);
17230 if (g_hash_table_lookup (info->transitions, name) != NULL)
17232 g_warning ("A transition with name '%s' already exists for "
17235 _clutter_actor_get_debug_name (self));
17239 clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17241 timeline = CLUTTER_TIMELINE (transition);
17243 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17244 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17245 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17247 clos = g_slice_new (TransitionClosure);
17248 clos->actor = self;
17249 clos->transition = g_object_ref (transition);
17250 clos->name = g_strdup (name);
17251 clos->completed_id = g_signal_connect (timeline, "completed",
17252 G_CALLBACK (on_transition_completed),
17255 CLUTTER_NOTE (ANIMATION,
17256 "Adding transition '%s' [%p] to actor '%s'",
17259 _clutter_actor_get_debug_name (self));
17261 g_hash_table_insert (info->transitions, clos->name, clos);
17262 clutter_timeline_start (timeline);
17266 * clutter_actor_remove_transition:
17267 * @self: a #ClutterActor
17268 * @name: the name of the transition to remove
17270 * Removes the transition stored inside a #ClutterActor using @name
17273 * If the transition is currently in progress, it will be stopped.
17275 * This function releases the reference acquired when the transition
17276 * was added to the #ClutterActor.
17281 clutter_actor_remove_transition (ClutterActor *self,
17284 const ClutterAnimationInfo *info;
17286 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17287 g_return_if_fail (name != NULL);
17289 info = _clutter_actor_get_animation_info_or_defaults (self);
17291 if (info->transitions == NULL)
17294 g_hash_table_remove (info->transitions, name);
17298 * clutter_actor_remove_all_transitions:
17299 * @self: a #ClutterActor
17301 * Removes all transitions associated to @self.
17306 clutter_actor_remove_all_transitions (ClutterActor *self)
17308 const ClutterAnimationInfo *info;
17310 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17312 info = _clutter_actor_get_animation_info_or_defaults (self);
17313 if (info->transitions == NULL)
17316 g_hash_table_remove_all (info->transitions);
17320 * clutter_actor_set_easing_duration:
17321 * @self: a #ClutterActor
17322 * @msecs: the duration of the easing, or %NULL
17324 * Sets the duration of the tweening for animatable properties
17325 * of @self for the current easing state.
17330 clutter_actor_set_easing_duration (ClutterActor *self,
17333 ClutterAnimationInfo *info;
17335 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17337 info = _clutter_actor_get_animation_info (self);
17339 if (info->cur_state == NULL)
17341 g_warning ("You must call clutter_actor_save_easing_state() prior "
17342 "to calling clutter_actor_set_easing_duration().");
17346 if (info->cur_state->easing_duration != msecs)
17347 info->cur_state->easing_duration = msecs;
17351 * clutter_actor_get_easing_duration:
17352 * @self: a #ClutterActor
17354 * Retrieves the duration of the tweening for animatable
17355 * properties of @self for the current easing state.
17357 * Return value: the duration of the tweening, in milliseconds
17362 clutter_actor_get_easing_duration (ClutterActor *self)
17364 const ClutterAnimationInfo *info;
17366 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17368 info = _clutter_actor_get_animation_info_or_defaults (self);
17370 if (info->cur_state != NULL)
17371 return info->cur_state->easing_duration;
17377 * clutter_actor_set_easing_mode:
17378 * @self: a #ClutterActor
17379 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17381 * Sets the easing mode for the tweening of animatable properties
17387 clutter_actor_set_easing_mode (ClutterActor *self,
17388 ClutterAnimationMode mode)
17390 ClutterAnimationInfo *info;
17392 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17393 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17394 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17396 info = _clutter_actor_get_animation_info (self);
17398 if (info->cur_state == NULL)
17400 g_warning ("You must call clutter_actor_save_easing_state() prior "
17401 "to calling clutter_actor_set_easing_mode().");
17405 if (info->cur_state->easing_mode != mode)
17406 info->cur_state->easing_mode = mode;
17410 * clutter_actor_get_easing_mode:
17411 * @self: a #ClutterActor
17413 * Retrieves the easing mode for the tweening of animatable properties
17414 * of @self for the current easing state.
17416 * Return value: an easing mode
17420 ClutterAnimationMode
17421 clutter_actor_get_easing_mode (ClutterActor *self)
17423 const ClutterAnimationInfo *info;
17425 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17427 info = _clutter_actor_get_animation_info_or_defaults (self);
17429 if (info->cur_state != NULL)
17430 return info->cur_state->easing_mode;
17432 return CLUTTER_EASE_OUT_CUBIC;
17436 * clutter_actor_set_easing_delay:
17437 * @self: a #ClutterActor
17438 * @msecs: the delay before the start of the tweening, in milliseconds
17440 * Sets the delay that should be applied before tweening animatable
17446 clutter_actor_set_easing_delay (ClutterActor *self,
17449 ClutterAnimationInfo *info;
17451 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17453 info = _clutter_actor_get_animation_info (self);
17455 if (info->cur_state == NULL)
17457 g_warning ("You must call clutter_actor_save_easing_state() prior "
17458 "to calling clutter_actor_set_easing_delay().");
17462 if (info->cur_state->easing_delay != msecs)
17463 info->cur_state->easing_delay = msecs;
17467 * clutter_actor_get_easing_delay:
17468 * @self: a #ClutterActor
17470 * Retrieves the delay that should be applied when tweening animatable
17473 * Return value: a delay, in milliseconds
17478 clutter_actor_get_easing_delay (ClutterActor *self)
17480 const ClutterAnimationInfo *info;
17482 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17484 info = _clutter_actor_get_animation_info_or_defaults (self);
17486 if (info->cur_state != NULL)
17487 return info->cur_state->easing_delay;
17493 * clutter_actor_get_transition:
17494 * @self: a #ClutterActor
17495 * @name: the name of the transition
17497 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17498 * transition @name.
17500 * Transitions created for animatable properties use the name of the
17501 * property itself, for instance the code below:
17504 * clutter_actor_set_easing_duration (actor, 1000);
17505 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17507 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17508 * g_signal_connect (transition, "completed",
17509 * G_CALLBACK (on_transition_complete),
17513 * will call the <function>on_transition_complete</function> callback when
17514 * the transition is complete.
17516 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17517 * was found to match the passed name; the returned instance is owned
17518 * by Clutter and it should not be freed
17522 ClutterTransition *
17523 clutter_actor_get_transition (ClutterActor *self,
17526 TransitionClosure *clos;
17527 const ClutterAnimationInfo *info;
17529 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17530 g_return_val_if_fail (name != NULL, NULL);
17532 info = _clutter_actor_get_animation_info_or_defaults (self);
17533 if (info->transitions == NULL)
17536 clos = g_hash_table_lookup (info->transitions, name);
17540 return clos->transition;
17544 * clutter_actor_save_easing_state:
17545 * @self: a #ClutterActor
17547 * Saves the current easing state for animatable properties, and creates
17548 * a new state with the default values for easing mode and duration.
17553 clutter_actor_save_easing_state (ClutterActor *self)
17555 ClutterAnimationInfo *info;
17558 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17560 info = _clutter_actor_get_animation_info (self);
17562 if (info->states == NULL)
17563 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17565 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17566 new_state.easing_duration = 250;
17567 new_state.easing_delay = 0;
17569 g_array_append_val (info->states, new_state);
17571 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17575 * clutter_actor_restore_easing_state:
17576 * @self: a #ClutterActor
17578 * Restores the easing state as it was prior to a call to
17579 * clutter_actor_save_easing_state().
17584 clutter_actor_restore_easing_state (ClutterActor *self)
17586 ClutterAnimationInfo *info;
17588 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17590 info = _clutter_actor_get_animation_info (self);
17592 if (info->states == NULL)
17594 g_critical ("The function clutter_actor_restore_easing_state() has "
17595 "called without a previous call to "
17596 "clutter_actor_save_easing_state().");
17600 g_array_remove_index (info->states, info->states->len - 1);
17602 if (info->states->len > 0)
17603 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17606 g_array_unref (info->states);
17607 info->states = NULL;
17608 info->cur_state = NULL;
17613 * clutter_actor_set_content:
17614 * @self: a #ClutterActor
17615 * @content: (allow-none): a #ClutterContent, or %NULL
17617 * Sets the contents of a #ClutterActor.
17622 clutter_actor_set_content (ClutterActor *self,
17623 ClutterContent *content)
17625 ClutterActorPrivate *priv;
17627 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17628 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17632 if (priv->content != NULL)
17634 _clutter_content_detached (priv->content, self);
17635 g_clear_object (&priv->content);
17638 priv->content = content;
17640 if (priv->content != NULL)
17642 g_object_ref (priv->content);
17643 _clutter_content_attached (priv->content, self);
17646 /* given that the content is always painted within the allocation,
17647 * we only need to queue a redraw here
17649 clutter_actor_queue_redraw (self);
17651 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17653 /* if the content gravity is not resize-fill, and the new content has a
17654 * different preferred size than the previous one, then the content box
17655 * may have been changed. since we compute that lazily, we just notify
17656 * here, and let whomever watches :content-box do whatever they need to
17659 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17660 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17664 * clutter_actor_get_content:
17665 * @self: a #ClutterActor
17667 * Retrieves the contents of @self.
17669 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17670 * or %NULL if none was set
17675 clutter_actor_get_content (ClutterActor *self)
17677 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17679 return self->priv->content;
17683 * clutter_actor_set_content_gravity:
17684 * @self: a #ClutterActor
17685 * @gravity: the #ClutterContentGravity
17687 * Sets the gravity of the #ClutterContent used by @self.
17689 * See the description of the #ClutterActor:content-gravity property for
17690 * more information.
17695 clutter_actor_set_content_gravity (ClutterActor *self,
17696 ClutterContentGravity gravity)
17698 ClutterActorPrivate *priv;
17700 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17704 if (priv->content_gravity == gravity)
17707 priv->content_gravity = gravity;
17709 clutter_actor_queue_redraw (self);
17711 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17712 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17716 * clutter_actor_get_content_gravity:
17717 * @self: a #ClutterActor
17719 * Retrieves the content gravity as set using
17720 * clutter_actor_get_content_gravity().
17722 * Return value: the content gravity
17726 ClutterContentGravity
17727 clutter_actor_get_content_gravity (ClutterActor *self)
17729 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17730 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17732 return self->priv->content_gravity;
17736 * clutter_actor_get_content_box:
17737 * @self: a #ClutterActor
17738 * @box: (out caller-allocates): the return location for the bounding
17739 * box for the #ClutterContent
17741 * Retrieves the bounding box for the #ClutterContent of @self.
17743 * The bounding box is relative to the actor's allocation.
17745 * If no #ClutterContent is set for @self, or if @self has not been
17746 * allocated yet, then the result is undefined.
17748 * The content box is guaranteed to be, at most, as big as the allocation
17749 * of the #ClutterActor.
17751 * If the #ClutterContent used by the actor has a preferred size, then
17752 * it is possible to modify the content box by using the
17753 * #ClutterActor:content-gravity property.
17758 clutter_actor_get_content_box (ClutterActor *self,
17759 ClutterActorBox *box)
17761 ClutterActorPrivate *priv;
17762 gfloat content_w, content_h;
17763 gfloat alloc_w, alloc_h;
17765 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17766 g_return_if_fail (box != NULL);
17772 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17773 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17775 if (priv->content == NULL)
17778 /* no need to do any more work */
17779 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17782 /* if the content does not have a preferred size then there is
17783 * no point in computing the content box
17785 if (!clutter_content_get_preferred_size (priv->content,
17793 switch (priv->content_gravity)
17795 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17796 box->x2 = box->x1 + MIN (content_w, alloc_w);
17797 box->y2 = box->y1 + MIN (content_h, alloc_h);
17800 case CLUTTER_CONTENT_GRAVITY_TOP:
17801 if (alloc_w > content_w)
17803 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17804 box->x2 = box->x1 + content_w;
17806 box->y2 = box->y1 + MIN (content_h, alloc_h);
17809 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17810 if (alloc_w > content_w)
17812 box->x1 += (alloc_w - content_w);
17813 box->x2 = box->x1 + content_w;
17815 box->y2 = box->y1 + MIN (content_h, alloc_h);
17818 case CLUTTER_CONTENT_GRAVITY_LEFT:
17819 box->x2 = box->x1 + MIN (content_w, alloc_w);
17820 if (alloc_h > content_h)
17822 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17823 box->y2 = box->y1 + content_h;
17827 case CLUTTER_CONTENT_GRAVITY_CENTER:
17828 if (alloc_w > content_w)
17830 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17831 box->x2 = box->x1 + content_w;
17833 if (alloc_h > content_h)
17835 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17836 box->y2 = box->y1 + content_h;
17840 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17841 if (alloc_w > content_w)
17843 box->x1 += (alloc_w - content_w);
17844 box->x2 = box->x1 + content_w;
17846 if (alloc_h > content_h)
17848 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17849 box->y2 = box->y1 + content_h;
17853 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17854 box->x2 = box->x1 + MIN (content_w, alloc_w);
17855 if (alloc_h > content_h)
17857 box->y1 += (alloc_h - content_h);
17858 box->y2 = box->y1 + content_h;
17862 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17863 if (alloc_w > content_w)
17865 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17866 box->x2 = box->x1 + content_w;
17868 if (alloc_h > content_h)
17870 box->y1 += (alloc_h - content_h);
17871 box->y2 = box->y1 + content_h;
17875 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17876 if (alloc_w > content_w)
17878 box->x1 += (alloc_w - content_w);
17879 box->x2 = box->x1 + content_w;
17881 if (alloc_h > content_h)
17883 box->y1 += (alloc_h - content_h);
17884 box->y2 = box->y1 + content_h;
17888 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17889 g_assert_not_reached ();
17892 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17894 double r_c = content_w / content_h;
17895 double r_a = alloc_w / alloc_h;
17904 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17905 box->y2 = box->y1 + (alloc_w * r_c);
17912 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17913 box->x2 = box->x1 + (alloc_h * r_c);
17923 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17924 box->x2 = box->x1 + (alloc_h * r_c);
17931 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17932 box->y2 = box->y1 + (alloc_w * r_c);
17941 * clutter_actor_set_content_scaling_filters:
17942 * @self: a #ClutterActor
17943 * @min_filter: the minification filter for the content
17944 * @mag_filter: the magnification filter for the content
17946 * Sets the minification and magnification filter to be applied when
17947 * scaling the #ClutterActor:content of a #ClutterActor.
17949 * The #ClutterActor:minification-filter will be used when reducing
17950 * the size of the content; the #ClutterActor:magnification-filter
17951 * will be used when increasing the size of the content.
17956 clutter_actor_set_content_scaling_filters (ClutterActor *self,
17957 ClutterScalingFilter min_filter,
17958 ClutterScalingFilter mag_filter)
17960 ClutterActorPrivate *priv;
17964 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17967 obj = G_OBJECT (self);
17969 g_object_freeze_notify (obj);
17973 if (priv->min_filter != min_filter)
17975 priv->min_filter = min_filter;
17978 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17981 if (priv->mag_filter != mag_filter)
17983 priv->mag_filter = mag_filter;
17986 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17990 clutter_actor_queue_redraw (self);
17992 g_object_thaw_notify (obj);
17996 * clutter_actor_get_content_scaling_filters:
17997 * @self: a #ClutterActor
17998 * @min_filter: (out) (allow-none): return location for the minification
18000 * @mag_filter: (out) (allow-none): return location for the magnification
18003 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18008 clutter_actor_get_content_scaling_filters (ClutterActor *self,
18009 ClutterScalingFilter *min_filter,
18010 ClutterScalingFilter *mag_filter)
18012 g_return_if_fail (CLUTTER_IS_ACTOR (self));
18014 if (min_filter != NULL)
18015 *min_filter = self->priv->min_filter;
18017 if (mag_filter != NULL)
18018 *mag_filter = self->priv->mag_filter;