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: Base abstract class for all visual stage actors.
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);
171 * /* paint the content of the node using the allocation */
172 * clutter_paint_node_add_rectangle (node, &box);
174 * /* add the node, and transfer ownership */
175 * clutter_paint_node_add_child (root, node);
176 * clutter_paint_node_unref (node);
178 * </programlisting></informalexample>
181 * <title>Overriding the paint virtual function</title>
182 * <para>The #ClutterActorClass.paint() virtual function is invoked
183 * when the #ClutterActor::paint signal is emitted, and after the other
184 * signal handlers have been invoked. Overriding the paint virtual
185 * function gives total control to the paint sequence of the actor
186 * itself, including the children of the actor, if any.</para>
187 * <warning><para>It is strongly discouraged to override the
188 * #ClutterActorClass.paint() virtual function, as well as connecting
189 * to the #ClutterActor::paint signal. These hooks into the paint
190 * sequence are considered legacy, and will be removed when the Clutter
191 * API changes.</para></warning>
195 * <refsect2 id="ClutterActor-events">
196 * <title>Handling events on an actor</title>
197 * <para>A #ClutterActor can receive and handle input device events, for
198 * instance pointer events and key events, as long as its
199 * #ClutterActor:reactive property is set to %TRUE.</para>
200 * <para>Once an actor has been determined to be the source of an event,
201 * Clutter will traverse the scene graph from the top-level actor towards the
202 * event source, emitting the #ClutterActor::captured-event signal on each
203 * ancestor until it reaches the source; this phase is also called
204 * <emphasis>the capture phase</emphasis>. If the event propagation was not
205 * stopped, the graph is walked backwards, from the source actor to the
206 * top-level, and the #ClutterActor::event signal, along with other event
207 * signals if needed, is emitted; this phase is also called <emphasis>the
208 * bubble phase</emphasis>. At any point of the signal emission, signal
209 * handlers can stop the propagation through the scene graph by returning
210 * %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
211 * returning %CLUTTER_EVENT_PROPAGATE.</para>
214 * <refsect2 id="ClutterActor-subclassing">
215 * <title>Implementing an actor</title>
216 * <para>Careful consideration should be given when deciding to implement
217 * a #ClutterActor sub-class. It is generally recommended to implement a
218 * sub-class of #ClutterActor only for actors that should be used as leaf
219 * nodes of a scene graph.</para>
220 * <para>If your actor should be painted in a custom way, you should
221 * override the #ClutterActor::paint signal class handler. You can either
222 * opt to chain up to the parent class implementation or decide to fully
223 * override the default paint implementation; Clutter will set up the
224 * transformations and clip regions prior to emitting the #ClutterActor::paint
226 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
227 * #ClutterActorClass.get_preferred_height() virtual functions it is
228 * possible to change or provide the preferred size of an actor; similarly,
229 * by overriding the #ClutterActorClass.allocate() virtual function it is
230 * possible to control the layout of the children of an actor. Make sure to
231 * always chain up to the parent implementation of the
232 * #ClutterActorClass.allocate() virtual function.</para>
233 * <para>In general, it is strongly encouraged to use delegation and
234 * composition instead of direct subclassing.</para>
237 * <refsect2 id="ClutterActor-script">
238 * <title>ClutterActor custom properties for #ClutterScript</title>
239 * <para>#ClutterActor defines a custom "rotation" property which
240 * allows a short-hand description of the rotations to be applied
241 * to an actor.</para>
242 * <para>The syntax of the "rotation" property is the following:</para>
246 * { "<axis>" : [ <angle>, [ <center> ] ] }
250 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
251 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
252 * floating point value representing the rotation angle on the given axis,
254 * <para>The <emphasis>center</emphasis> array is optional, and if present
255 * it must contain the center of rotation as described by two coordinates:
256 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
258 * <para>#ClutterActor will also parse every positional and dimensional
259 * property defined as a string through clutter_units_from_string(); you
260 * should read the documentation for the #ClutterUnits parser format for
261 * the valid units and syntax.</para>
264 * <refsect2 id="ClutterActor-animating">
265 * <title>Custom animatable properties</title>
266 * <para>#ClutterActor allows accessing properties of #ClutterAction
267 * and #ClutterConstraint instances associated to an actor instance
268 * for animation purposes.</para>
269 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
270 * property it is necessary to set the #ClutterActorMeta:name property on the
271 * given action or constraint.</para>
272 * <para>The property can be accessed using the following syntax:</para>
275 * @<section>.<meta-name>.<property-name>
278 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
279 * <para>The <emphasis>section</emphasis> fragment can be one between
280 * "actions", "constraints" and "effects".</para>
281 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
282 * action or constraint, as specified by the #ClutterActorMeta:name
284 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
285 * action or constraint property to be animated.</para>
286 * <para>The example below animates a #ClutterBindConstraint applied to an
287 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
288 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
289 * its initial state is fully transparent and overlapping the actor to
290 * which is bound to. </para>
291 * <informalexample><programlisting>
292 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
293 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
294 * clutter_actor_add_constraint (rect, constraint);
296 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
297 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
298 * clutter_actor_add_constraint (rect, constraint);
300 * clutter_actor_set_reactive (rect, TRUE);
301 * clutter_actor_set_opacity (rect, 0);
303 * g_signal_connect (rect, "button-press-event",
304 * G_CALLBACK (on_button_press),
306 * </programlisting></informalexample>
307 * <para>On button press, the rectangle "slides" from behind the actor to
308 * which is bound to, using the #ClutterBindConstraint:offset property and
309 * the #ClutterActor:opacity property.</para>
310 * <informalexample><programlisting>
311 * float new_offset = clutter_actor_get_width (origin) + h_padding;
313 * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
315 * "@constraints.bind-x.offset", new_offset,
317 * </programlisting></informalexample>
320 * <refsect2 id="ClutterActor-animatable-properties">
321 * <title>Animatable properties</title>
322 * <para>Certain properties on #ClutterActor are marked as "animatable";
323 * these properties will be automatically tweened between the current
324 * value and the new value when one is set.</para>
325 * <para>For backward compatibility, animatable properties will only be
326 * tweened if the easing duration is greater than 0, or if a new easing
327 * state is set, for instance the following example:</para>
328 * <informalexample><programlisting>
329 * clutter_actor_save_easing_state (actor);
330 * clutter_actor_set_position (actor, 200, 200);
331 * clutter_actor_restore_easing_state (actor);
332 * </programlisting></informalexample>
333 * <para>will tween the actor to the (200, 200) coordinates using the default
334 * easing mode and duration of a new easing state. The example above is
335 * equivalent to the following code:</para>
336 * <informalexample><programlisting>
337 * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
338 * clutter_actor_set_easing_duration (actor, 250);
339 * clutter_actor_set_position (actor, 200, 200);
340 * clutter_actor_restore_easing_state (actor);
341 * </programlisting></informalexample>
342 * <para>It is possible to nest easing states to tween animatable
343 * properties using different modes and durations, for instance:</para>
344 * <informalexample><programlisting>
345 * clutter_actor_save_easing_state (actor); /* outer state */
347 * /* set the duration of the animation to 2 seconds and change position */
348 * clutter_actor_set_easing_duration (actor, 2000);
349 * clutter_actor_set_position (actor, 0, 0);
351 * clutter_actor_save_easing_state (actor); /* inner state */
353 * /* set the duration of the animation to 5 seconds and change depth and opacity */
354 * clutter_actor_set_easing_duration (actor, 5000);
355 * clutter_actor_set_depth (actor, 200);
356 * clutter_actor_set_opacity (actor, 0);
358 * clutter_actor_restore_easing_state (actor);
360 * clutter_actor_restore_easing_state (actor);
361 * </programlisting></informalexample>
366 * CLUTTER_ACTOR_IS_MAPPED:
367 * @a: a #ClutterActor
369 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
371 * The mapped state is set when the actor is visible and all its parents up
372 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
374 * This check can be used to see if an actor is going to be painted, as only
375 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
377 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
378 * not be checked directly; instead, the recommended usage is to connect a
379 * handler on the #GObject::notify signal for the #ClutterActor:mapped
380 * property of #ClutterActor, and check the presence of
381 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
383 * It is also important to note that Clutter may delay the changes of
384 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
385 * limitations, or during the reparenting of an actor, to optimize
386 * unnecessary (and potentially expensive) state changes.
392 * CLUTTER_ACTOR_IS_REALIZED:
393 * @a: a #ClutterActor
395 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
397 * The realized state has an actor-dependant interpretation. If an
398 * actor wants to delay allocating resources until it is attached to a
399 * stage, it may use the realize state to do so. However it is
400 * perfectly acceptable for an actor to allocate Cogl resources before
401 * being realized because there is only one drawing context used by Clutter
402 * so any resources will work on any stage. If an actor is mapped it
403 * must also be realized, but an actor can be realized and unmapped
404 * (this is so hiding an actor temporarily doesn't do an expensive
405 * unrealize/realize).
407 * To be realized an actor must be inside a stage, and all its parents
414 * CLUTTER_ACTOR_IS_VISIBLE:
415 * @a: a #ClutterActor
417 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
418 * Equivalent to the ClutterActor::visible object property.
420 * Note that an actor is only painted onscreen if it's mapped, which
421 * means it's visible, and all its parents are visible, and one of the
422 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
428 * CLUTTER_ACTOR_IS_REACTIVE:
429 * @a: a #ClutterActor
431 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
433 * Only reactive actors will receive event-related signals.
444 #include <gobject/gvaluecollector.h>
446 #include <cogl/cogl.h>
448 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
449 #define CLUTTER_ENABLE_EXPERIMENTAL_API
451 #include "clutter-actor-private.h"
453 #include "clutter-action.h"
454 #include "clutter-actor-meta-private.h"
455 #include "clutter-animatable.h"
456 #include "clutter-color-static.h"
457 #include "clutter-color.h"
458 #include "clutter-constraint.h"
459 #include "clutter-container.h"
460 #include "clutter-content-private.h"
461 #include "clutter-debug.h"
462 #include "clutter-effect-private.h"
463 #include "clutter-enum-types.h"
464 #include "clutter-fixed-layout.h"
465 #include "clutter-flatten-effect.h"
466 #include "clutter-interval.h"
467 #include "clutter-main.h"
468 #include "clutter-marshal.h"
469 #include "clutter-paint-nodes.h"
470 #include "clutter-paint-node-private.h"
471 #include "clutter-paint-volume-private.h"
472 #include "clutter-private.h"
473 #include "clutter-profile.h"
474 #include "clutter-property-transition.h"
475 #include "clutter-scriptable.h"
476 #include "clutter-script-private.h"
477 #include "clutter-stage-private.h"
478 #include "clutter-timeline.h"
479 #include "clutter-transition.h"
480 #include "clutter-units.h"
482 #include "deprecated/clutter-actor.h"
483 #include "deprecated/clutter-behaviour.h"
484 #include "deprecated/clutter-container.h"
486 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
487 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
489 /* Internal enum used to control mapped state update. This is a hint
490 * which indicates when to do something other than just enforce
494 MAP_STATE_CHECK, /* just enforce invariants. */
495 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
496 * used when about to unparent.
498 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
499 * used to set mapped on toplevels.
501 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
502 * used just before unmapping parent.
506 /* 3 entries should be a good compromise, few layout managers
507 * will ask for 3 different preferred size in each allocation cycle */
508 #define N_CACHED_SIZE_REQUESTS 3
510 struct _ClutterActorPrivate
513 ClutterRequestMode request_mode;
515 /* our cached size requests for different width / height */
516 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
517 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
519 /* An age of 0 means the entry is not set */
520 guint cached_height_age;
521 guint cached_width_age;
523 /* the bounding box of the actor, relative to the parent's
526 ClutterActorBox allocation;
527 ClutterAllocationFlags allocation_flags;
529 /* clip, in actor coordinates */
530 cairo_rectangle_t clip;
532 /* the cached transformation matrix; see apply_transform() */
533 CoglMatrix transform;
536 gint opacity_override;
538 ClutterOffscreenRedirect offscreen_redirect;
540 /* This is an internal effect used to implement the
541 offscreen-redirect property */
542 ClutterEffect *flatten_effect;
545 ClutterActor *parent;
546 ClutterActor *prev_sibling;
547 ClutterActor *next_sibling;
548 ClutterActor *first_child;
549 ClutterActor *last_child;
553 /* tracks whenever the children of an actor are changed; the
554 * age is incremented by 1 whenever an actor is added or
555 * removed. the age is not incremented when the first or the
556 * last child pointers are changed, or when grandchildren of
557 * an actor are changed.
561 gchar *name; /* a non-unique name, used for debugging */
562 guint32 id; /* unique id, used for backward compatibility */
564 gint32 pick_id; /* per-stage unique id, used for picking */
566 /* a back-pointer to the Pango context that we can use
567 * to create pre-configured PangoLayout
569 PangoContext *pango_context;
571 /* the text direction configured for this child - either by
572 * application code, or by the actor's parent
574 ClutterTextDirection text_direction;
576 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
580 ClutterMetaGroup *actions;
581 ClutterMetaGroup *constraints;
582 ClutterMetaGroup *effects;
584 /* delegate object used to allocate the children of this actor */
585 ClutterLayoutManager *layout_manager;
587 /* delegate object used to paint the contents of this actor */
588 ClutterContent *content;
590 ClutterContentGravity content_gravity;
592 /* used when painting, to update the paint volume */
593 ClutterEffect *current_effect;
595 /* This is used to store an effect which needs to be redrawn. A
596 redraw can be queued to start from a particular effect. This is
597 used by parametrised effects that can cache an image of the
598 actor. If a parameter of the effect changes then it only needs to
599 redraw the cached image, not the actual actor. The pointer is
600 only valid if is_dirty == TRUE. If the pointer is NULL then the
601 whole actor is dirty. */
602 ClutterEffect *effect_to_redraw;
604 /* This is used when painting effects to implement the
605 clutter_actor_continue_paint() function. It points to the node in
606 the list of effects that is next in the chain */
607 const GList *next_effect_to_paint;
609 ClutterPaintVolume paint_volume;
611 /* NB: This volume isn't relative to this actor, it is in eye
612 * coordinates so that it can remain valid after the actor changes.
614 ClutterPaintVolume last_paint_volume;
616 ClutterStageQueueRedrawEntry *queue_redraw_entry;
618 ClutterColor bg_color;
622 /* fixed position and sizes */
623 guint position_set : 1;
624 guint min_width_set : 1;
625 guint min_height_set : 1;
626 guint natural_width_set : 1;
627 guint natural_height_set : 1;
628 /* cached request is invalid (implies allocation is too) */
629 guint needs_width_request : 1;
630 /* cached request is invalid (implies allocation is too) */
631 guint needs_height_request : 1;
632 /* cached allocation is invalid (request has changed, probably) */
633 guint needs_allocation : 1;
634 guint show_on_set_parent : 1;
636 guint clip_to_allocation : 1;
637 guint enable_model_view_transform : 1;
638 guint enable_paint_unmapped : 1;
639 guint has_pointer : 1;
640 guint propagated_one_redraw : 1;
641 guint paint_volume_valid : 1;
642 guint last_paint_volume_valid : 1;
643 guint in_clone_paint : 1;
644 guint transform_valid : 1;
645 /* This is TRUE if anything has queued a redraw since we were last
646 painted. In this case effect_to_redraw will point to an effect
647 the redraw was queued from or it will be NULL if the redraw was
648 queued without an effect. */
650 guint bg_color_set : 1;
659 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
660 * when set they force a size request, when gotten they
661 * get the allocation if the allocation is valid, and the
669 /* Then the rest of these size-related properties are the "actual"
670 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
675 PROP_FIXED_POSITION_SET,
684 PROP_NATURAL_WIDTH_SET,
687 PROP_NATURAL_HEIGHT_SET,
691 /* Allocation properties are read-only */
698 PROP_CLIP_TO_ALLOCATION,
702 PROP_OFFSCREEN_REDIRECT,
715 PROP_ROTATION_ANGLE_X,
716 PROP_ROTATION_ANGLE_Y,
717 PROP_ROTATION_ANGLE_Z,
718 PROP_ROTATION_CENTER_X,
719 PROP_ROTATION_CENTER_Y,
720 PROP_ROTATION_CENTER_Z,
721 /* This property only makes sense for the z rotation because the
722 others would depend on the actor having a size along the
724 PROP_ROTATION_CENTER_Z_GRAVITY,
730 PROP_SHOW_ON_SET_PARENT,
748 PROP_BACKGROUND_COLOR,
749 PROP_BACKGROUND_COLOR_SET,
755 PROP_CONTENT_GRAVITY,
761 static GParamSpec *obj_props[PROP_LAST];
780 BUTTON_RELEASE_EVENT,
792 static guint actor_signals[LAST_SIGNAL] = { 0, };
794 static void clutter_container_iface_init (ClutterContainerIface *iface);
795 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
796 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
797 static void atk_implementor_iface_init (AtkImplementorIface *iface);
799 /* These setters are all static for now, maybe they should be in the
800 * public API, but they are perhaps obscure enough to leave only as
803 static void clutter_actor_set_min_width (ClutterActor *self,
805 static void clutter_actor_set_min_height (ClutterActor *self,
807 static void clutter_actor_set_natural_width (ClutterActor *self,
808 gfloat natural_width);
809 static void clutter_actor_set_natural_height (ClutterActor *self,
810 gfloat natural_height);
811 static void clutter_actor_set_min_width_set (ClutterActor *self,
812 gboolean use_min_width);
813 static void clutter_actor_set_min_height_set (ClutterActor *self,
814 gboolean use_min_height);
815 static void clutter_actor_set_natural_width_set (ClutterActor *self,
816 gboolean use_natural_width);
817 static void clutter_actor_set_natural_height_set (ClutterActor *self,
818 gboolean use_natural_height);
819 static void clutter_actor_update_map_state (ClutterActor *self,
820 MapStateChange change);
821 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
823 /* Helper routines for managing anchor coords */
824 static void clutter_anchor_coord_get_units (ClutterActor *self,
825 const AnchorCoord *coord,
829 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
834 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
835 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
836 ClutterGravity gravity);
838 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
840 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
842 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
843 ClutterActor *ancestor,
846 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
848 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
850 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
851 const ClutterColor *color);
853 static void on_layout_manager_changed (ClutterLayoutManager *manager,
856 /* Helper macro which translates by the anchor coord, applies the
857 given transformation and then translates back */
858 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
859 gfloat _tx, _ty, _tz; \
860 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
861 cogl_matrix_translate ((m), _tx, _ty, _tz); \
863 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
865 static GQuark quark_shader_data = 0;
866 static GQuark quark_actor_layout_info = 0;
867 static GQuark quark_actor_transform_info = 0;
868 static GQuark quark_actor_animation_info = 0;
870 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
872 G_TYPE_INITIALLY_UNOWNED,
873 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
874 clutter_container_iface_init)
875 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
876 clutter_scriptable_iface_init)
877 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
878 clutter_animatable_iface_init)
879 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
880 atk_implementor_iface_init));
883 * clutter_actor_get_debug_name:
884 * @actor: a #ClutterActor
886 * Retrieves a printable name of @actor for debugging messages
888 * Return value: a string with a printable name
891 _clutter_actor_get_debug_name (ClutterActor *actor)
893 return actor->priv->name != NULL ? actor->priv->name
894 : G_OBJECT_TYPE_NAME (actor);
897 #ifdef CLUTTER_ENABLE_DEBUG
898 /* XXX - this is for debugging only, remove once working (or leave
899 * in only in some debug mode). Should leave it for a little while
900 * until we're confident in the new map/realize/visible handling.
903 clutter_actor_verify_map_state (ClutterActor *self)
905 ClutterActorPrivate *priv = self->priv;
907 if (CLUTTER_ACTOR_IS_REALIZED (self))
909 /* all bets are off during reparent when we're potentially realized,
910 * but should not be according to invariants
912 if (!CLUTTER_ACTOR_IN_REPARENT (self))
914 if (priv->parent == NULL)
916 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
920 g_warning ("Realized non-toplevel actor '%s' should "
922 _clutter_actor_get_debug_name (self));
924 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
926 g_warning ("Realized actor %s has an unrealized parent %s",
927 _clutter_actor_get_debug_name (self),
928 _clutter_actor_get_debug_name (priv->parent));
933 if (CLUTTER_ACTOR_IS_MAPPED (self))
935 if (!CLUTTER_ACTOR_IS_REALIZED (self))
936 g_warning ("Actor '%s' is mapped but not realized",
937 _clutter_actor_get_debug_name (self));
939 /* remaining bets are off during reparent when we're potentially
940 * mapped, but should not be according to invariants
942 if (!CLUTTER_ACTOR_IN_REPARENT (self))
944 if (priv->parent == NULL)
946 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
948 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
949 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
951 g_warning ("Toplevel actor '%s' is mapped "
953 _clutter_actor_get_debug_name (self));
958 g_warning ("Mapped actor '%s' should have a parent",
959 _clutter_actor_get_debug_name (self));
964 ClutterActor *iter = self;
966 /* check for the enable_paint_unmapped flag on the actor
967 * and parents; if the flag is enabled at any point of this
968 * branch of the scene graph then all the later checks
973 if (iter->priv->enable_paint_unmapped)
976 iter = iter->priv->parent;
979 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
981 g_warning ("Actor '%s' should not be mapped if parent '%s'"
983 _clutter_actor_get_debug_name (self),
984 _clutter_actor_get_debug_name (priv->parent));
987 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
989 g_warning ("Actor '%s' should not be mapped if parent '%s'"
991 _clutter_actor_get_debug_name (self),
992 _clutter_actor_get_debug_name (priv->parent));
995 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
997 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
998 g_warning ("Actor '%s' is mapped but its non-toplevel "
999 "parent '%s' is not mapped",
1000 _clutter_actor_get_debug_name (self),
1001 _clutter_actor_get_debug_name (priv->parent));
1008 #endif /* CLUTTER_ENABLE_DEBUG */
1011 clutter_actor_set_mapped (ClutterActor *self,
1014 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1019 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1020 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1024 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1025 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1029 /* this function updates the mapped and realized states according to
1030 * invariants, in the appropriate order.
1033 clutter_actor_update_map_state (ClutterActor *self,
1034 MapStateChange change)
1036 gboolean was_mapped;
1038 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1040 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1042 /* the mapped flag on top-level actors must be set by the
1043 * per-backend implementation because it might be asynchronous.
1045 * That is, the MAPPED flag on toplevels currently tracks the X
1046 * server mapped-ness of the window, while the expected behavior
1047 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1048 * This creates some weird complexity by breaking the invariant
1049 * that if we're visible and all ancestors shown then we are
1050 * also mapped - instead, we are mapped if all ancestors
1051 * _possibly excepting_ the stage are mapped. The stage
1052 * will map/unmap for example when it is minimized or
1053 * moved to another workspace.
1055 * So, the only invariant on the stage is that if visible it
1056 * should be realized, and that it has to be visible to be
1059 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1060 clutter_actor_realize (self);
1064 case MAP_STATE_CHECK:
1067 case MAP_STATE_MAKE_MAPPED:
1068 g_assert (!was_mapped);
1069 clutter_actor_set_mapped (self, TRUE);
1072 case MAP_STATE_MAKE_UNMAPPED:
1073 g_assert (was_mapped);
1074 clutter_actor_set_mapped (self, FALSE);
1077 case MAP_STATE_MAKE_UNREALIZED:
1078 /* we only use MAKE_UNREALIZED in unparent,
1079 * and unparenting a stage isn't possible.
1080 * If someone wants to just unrealize a stage
1081 * then clutter_actor_unrealize() doesn't
1082 * go through this codepath.
1084 g_warning ("Trying to force unrealize stage is not allowed");
1088 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1089 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1090 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1092 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1093 "it is somehow still mapped",
1094 _clutter_actor_get_debug_name (self));
1099 ClutterActorPrivate *priv = self->priv;
1100 ClutterActor *parent = priv->parent;
1101 gboolean should_be_mapped;
1102 gboolean may_be_realized;
1103 gboolean must_be_realized;
1105 should_be_mapped = FALSE;
1106 may_be_realized = TRUE;
1107 must_be_realized = FALSE;
1109 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1111 may_be_realized = FALSE;
1115 /* Maintain invariant that if parent is mapped, and we are
1116 * visible, then we are mapped ... unless parent is a
1117 * stage, in which case we map regardless of parent's map
1118 * state but do require stage to be visible and realized.
1120 * If parent is realized, that does not force us to be
1121 * realized; but if parent is unrealized, that does force
1122 * us to be unrealized.
1124 * The reason we don't force children to realize with
1125 * parents is _clutter_actor_rerealize(); if we require that
1126 * a realized parent means children are realized, then to
1127 * unrealize an actor we would have to unrealize its
1128 * parents, which would end up meaning unrealizing and
1129 * hiding the entire stage. So we allow unrealizing a
1130 * child (as long as that child is not mapped) while that
1131 * child still has a realized parent.
1133 * Also, if we unrealize from leaf nodes to root, and
1134 * realize from root to leaf, the invariants are never
1135 * violated if we allow children to be unrealized
1136 * while parents are realized.
1138 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1139 * to force us to unmap, even though parent is still
1140 * mapped. This is because we're unmapping from leaf nodes
1143 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1144 change != MAP_STATE_MAKE_UNMAPPED)
1146 gboolean parent_is_visible_realized_toplevel;
1148 parent_is_visible_realized_toplevel =
1149 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1150 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1151 CLUTTER_ACTOR_IS_REALIZED (parent));
1153 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1154 parent_is_visible_realized_toplevel)
1156 must_be_realized = TRUE;
1157 should_be_mapped = TRUE;
1161 /* if the actor has been set to be painted even if unmapped
1162 * then we should map it and check for realization as well;
1163 * this is an override for the branch of the scene graph
1164 * which begins with this node
1166 if (priv->enable_paint_unmapped)
1168 if (priv->parent == NULL)
1169 g_warning ("Attempting to map an unparented actor '%s'",
1170 _clutter_actor_get_debug_name (self));
1172 should_be_mapped = TRUE;
1173 must_be_realized = TRUE;
1176 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1177 may_be_realized = FALSE;
1180 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1183 g_warning ("Attempting to map a child that does not "
1184 "meet the necessary invariants: the actor '%s' "
1186 _clutter_actor_get_debug_name (self));
1188 g_warning ("Attempting to map a child that does not "
1189 "meet the necessary invariants: the actor '%s' "
1190 "is parented to an unmapped actor '%s'",
1191 _clutter_actor_get_debug_name (self),
1192 _clutter_actor_get_debug_name (priv->parent));
1195 /* If in reparent, we temporarily suspend unmap and unrealize.
1197 * We want to go in the order "realize, map" and "unmap, unrealize"
1201 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1202 clutter_actor_set_mapped (self, FALSE);
1205 if (must_be_realized)
1206 clutter_actor_realize (self);
1208 /* if we must be realized then we may be, presumably */
1209 g_assert (!(must_be_realized && !may_be_realized));
1212 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1213 clutter_actor_unrealize_not_hiding (self);
1216 if (should_be_mapped)
1218 if (!must_be_realized)
1219 g_warning ("Somehow we think actor '%s' should be mapped but "
1220 "not realized, which isn't allowed",
1221 _clutter_actor_get_debug_name (self));
1223 /* realization is allowed to fail (though I don't know what
1224 * an app is supposed to do about that - shouldn't it just
1225 * be a g_error? anyway, we have to avoid mapping if this
1228 if (CLUTTER_ACTOR_IS_REALIZED (self))
1229 clutter_actor_set_mapped (self, TRUE);
1233 #ifdef CLUTTER_ENABLE_DEBUG
1234 /* check all invariants were kept */
1235 clutter_actor_verify_map_state (self);
1240 clutter_actor_real_map (ClutterActor *self)
1242 ClutterActorPrivate *priv = self->priv;
1243 ClutterActor *stage, *iter;
1245 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1247 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1248 _clutter_actor_get_debug_name (self));
1250 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1252 stage = _clutter_actor_get_stage_internal (self);
1253 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1255 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1257 _clutter_actor_get_debug_name (self));
1259 /* notify on parent mapped before potentially mapping
1260 * children, so apps see a top-down notification.
1262 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1264 for (iter = self->priv->first_child;
1266 iter = iter->priv->next_sibling)
1268 clutter_actor_map (iter);
1273 * clutter_actor_map:
1274 * @self: A #ClutterActor
1276 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1277 * and realizes its children if they are visible. Does nothing if the
1278 * actor is not visible.
1280 * Calling this function is strongly disencouraged: the default
1281 * implementation of #ClutterActorClass.map() will map all the children
1282 * of an actor when mapping its parent.
1284 * When overriding map, it is mandatory to chain up to the parent
1290 clutter_actor_map (ClutterActor *self)
1292 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1294 if (CLUTTER_ACTOR_IS_MAPPED (self))
1297 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1300 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1304 clutter_actor_real_unmap (ClutterActor *self)
1306 ClutterActorPrivate *priv = self->priv;
1309 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1311 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1312 _clutter_actor_get_debug_name (self));
1314 for (iter = self->priv->first_child;
1316 iter = iter->priv->next_sibling)
1318 clutter_actor_unmap (iter);
1321 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1323 /* clear the contents of the last paint volume, so that hiding + moving +
1324 * showing will not result in the wrong area being repainted
1326 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1327 priv->last_paint_volume_valid = TRUE;
1329 /* notify on parent mapped after potentially unmapping
1330 * children, so apps see a bottom-up notification.
1332 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1334 /* relinquish keyboard focus if we were unmapped while owning it */
1335 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1337 ClutterStage *stage;
1339 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1342 _clutter_stage_release_pick_id (stage, priv->pick_id);
1346 if (stage != NULL &&
1347 clutter_stage_get_key_focus (stage) == self)
1349 clutter_stage_set_key_focus (stage, NULL);
1355 * clutter_actor_unmap:
1356 * @self: A #ClutterActor
1358 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1359 * unmaps its children if they were mapped.
1361 * Calling this function is not encouraged: the default #ClutterActor
1362 * implementation of #ClutterActorClass.unmap() will also unmap any
1363 * eventual children by default when their parent is unmapped.
1365 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1366 * chain up to the parent implementation.
1368 * <note>It is important to note that the implementation of the
1369 * #ClutterActorClass.unmap() virtual function may be called after
1370 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1371 * implementation, but it is guaranteed to be called before the
1372 * #GObjectClass.finalize() implementation.</note>
1377 clutter_actor_unmap (ClutterActor *self)
1379 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1381 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1384 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1388 clutter_actor_real_show (ClutterActor *self)
1390 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1392 ClutterActorPrivate *priv = self->priv;
1394 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1396 /* we notify on the "visible" flag in the clutter_actor_show()
1397 * wrapper so the entire show signal emission completes first
1400 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1402 /* we queue a relayout unless the actor is inside a
1403 * container that explicitly told us not to
1405 if (priv->parent != NULL &&
1406 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1408 /* While an actor is hidden the parent may not have
1409 * allocated/requested so we need to start from scratch
1410 * and avoid the short-circuiting in
1411 * clutter_actor_queue_relayout().
1413 priv->needs_width_request = FALSE;
1414 priv->needs_height_request = FALSE;
1415 priv->needs_allocation = FALSE;
1416 clutter_actor_queue_relayout (self);
1422 set_show_on_set_parent (ClutterActor *self,
1425 ClutterActorPrivate *priv = self->priv;
1427 set_show = !!set_show;
1429 if (priv->show_on_set_parent == set_show)
1432 if (priv->parent == NULL)
1434 priv->show_on_set_parent = set_show;
1435 g_object_notify_by_pspec (G_OBJECT (self),
1436 obj_props[PROP_SHOW_ON_SET_PARENT]);
1441 * clutter_actor_show:
1442 * @self: A #ClutterActor
1444 * Flags an actor to be displayed. An actor that isn't shown will not
1445 * be rendered on the stage.
1447 * Actors are visible by default.
1449 * If this function is called on an actor without a parent, the
1450 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1454 clutter_actor_show (ClutterActor *self)
1456 ClutterActorPrivate *priv;
1458 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1460 /* simple optimization */
1461 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1463 /* we still need to set the :show-on-set-parent property, in
1464 * case show() is called on an unparented actor
1466 set_show_on_set_parent (self, TRUE);
1470 #ifdef CLUTTER_ENABLE_DEBUG
1471 clutter_actor_verify_map_state (self);
1476 g_object_freeze_notify (G_OBJECT (self));
1478 set_show_on_set_parent (self, TRUE);
1480 g_signal_emit (self, actor_signals[SHOW], 0);
1481 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1483 if (priv->parent != NULL)
1484 clutter_actor_queue_redraw (priv->parent);
1486 g_object_thaw_notify (G_OBJECT (self));
1490 * clutter_actor_show_all:
1491 * @self: a #ClutterActor
1493 * Calls clutter_actor_show() on all children of an actor (if any).
1497 * Deprecated: 1.10: Actors are visible by default
1500 clutter_actor_show_all (ClutterActor *self)
1502 ClutterActorClass *klass;
1504 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1506 klass = CLUTTER_ACTOR_GET_CLASS (self);
1507 if (klass->show_all)
1508 klass->show_all (self);
1512 clutter_actor_real_hide (ClutterActor *self)
1514 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1516 ClutterActorPrivate *priv = self->priv;
1518 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1520 /* we notify on the "visible" flag in the clutter_actor_hide()
1521 * wrapper so the entire hide signal emission completes first
1524 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1526 /* we queue a relayout unless the actor is inside a
1527 * container that explicitly told us not to
1529 if (priv->parent != NULL &&
1530 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1531 clutter_actor_queue_relayout (priv->parent);
1536 * clutter_actor_hide:
1537 * @self: A #ClutterActor
1539 * Flags an actor to be hidden. A hidden actor will not be
1540 * rendered on the stage.
1542 * Actors are visible by default.
1544 * If this function is called on an actor without a parent, the
1545 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1549 clutter_actor_hide (ClutterActor *self)
1551 ClutterActorPrivate *priv;
1553 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1555 /* simple optimization */
1556 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1558 /* we still need to set the :show-on-set-parent property, in
1559 * case hide() is called on an unparented actor
1561 set_show_on_set_parent (self, FALSE);
1565 #ifdef CLUTTER_ENABLE_DEBUG
1566 clutter_actor_verify_map_state (self);
1571 g_object_freeze_notify (G_OBJECT (self));
1573 set_show_on_set_parent (self, FALSE);
1575 g_signal_emit (self, actor_signals[HIDE], 0);
1576 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1578 if (priv->parent != NULL)
1579 clutter_actor_queue_redraw (priv->parent);
1581 g_object_thaw_notify (G_OBJECT (self));
1585 * clutter_actor_hide_all:
1586 * @self: a #ClutterActor
1588 * Calls clutter_actor_hide() on all child actors (if any).
1592 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1593 * prevent its children from being painted as well.
1596 clutter_actor_hide_all (ClutterActor *self)
1598 ClutterActorClass *klass;
1600 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1602 klass = CLUTTER_ACTOR_GET_CLASS (self);
1603 if (klass->hide_all)
1604 klass->hide_all (self);
1608 * clutter_actor_realize:
1609 * @self: A #ClutterActor
1611 * Realization informs the actor that it is attached to a stage. It
1612 * can use this to allocate resources if it wanted to delay allocation
1613 * until it would be rendered. However it is perfectly acceptable for
1614 * an actor to create resources before being realized because Clutter
1615 * only ever has a single rendering context so that actor is free to
1616 * be moved from one stage to another.
1618 * This function does nothing if the actor is already realized.
1620 * Because a realized actor must have realized parent actors, calling
1621 * clutter_actor_realize() will also realize all parents of the actor.
1623 * This function does not realize child actors, except in the special
1624 * case that realizing the stage, when the stage is visible, will
1625 * suddenly map (and thus realize) the children of the stage.
1628 clutter_actor_realize (ClutterActor *self)
1630 ClutterActorPrivate *priv;
1632 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1636 #ifdef CLUTTER_ENABLE_DEBUG
1637 clutter_actor_verify_map_state (self);
1640 if (CLUTTER_ACTOR_IS_REALIZED (self))
1643 /* To be realized, our parent actors must be realized first.
1644 * This will only succeed if we're inside a toplevel.
1646 if (priv->parent != NULL)
1647 clutter_actor_realize (priv->parent);
1649 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1651 /* toplevels can be realized at any time */
1655 /* "Fail" the realization if parent is missing or unrealized;
1656 * this should really be a g_warning() not some kind of runtime
1657 * failure; how can an app possibly recover? Instead it's a bug
1658 * in the app and the app should get an explanatory warning so
1659 * someone can fix it. But for now it's too hard to fix this
1660 * because e.g. ClutterTexture needs reworking.
1662 if (priv->parent == NULL ||
1663 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1667 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1669 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1670 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1672 g_signal_emit (self, actor_signals[REALIZE], 0);
1674 /* Stage actor is allowed to unset the realized flag again in its
1675 * default signal handler, though that is a pathological situation.
1678 /* If realization "failed" we'll have to update child state. */
1679 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1683 clutter_actor_real_unrealize (ClutterActor *self)
1685 /* we must be unmapped (implying our children are also unmapped) */
1686 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1690 * clutter_actor_unrealize:
1691 * @self: A #ClutterActor
1693 * Unrealization informs the actor that it may be being destroyed or
1694 * moved to another stage. The actor may want to destroy any
1695 * underlying graphics resources at this point. However it is
1696 * perfectly acceptable for it to retain the resources until the actor
1697 * is destroyed because Clutter only ever uses a single rendering
1698 * context and all of the graphics resources are valid on any stage.
1700 * Because mapped actors must be realized, actors may not be
1701 * unrealized if they are mapped. This function hides the actor to be
1702 * sure it isn't mapped, an application-visible side effect that you
1703 * may not be expecting.
1705 * This function should not be called by application code.
1708 clutter_actor_unrealize (ClutterActor *self)
1710 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1711 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1713 /* This function should not really be in the public API, because
1714 * there isn't a good reason to call it. ClutterActor will already
1715 * unrealize things for you when it's important to do so.
1717 * If you were using clutter_actor_unrealize() in a dispose
1718 * implementation, then don't, just chain up to ClutterActor's
1721 * If you were using clutter_actor_unrealize() to implement
1722 * unrealizing children of your container, then don't, ClutterActor
1723 * will already take care of that.
1725 * If you were using clutter_actor_unrealize() to re-realize to
1726 * create your resources in a different way, then use
1727 * _clutter_actor_rerealize() (inside Clutter) or just call your
1728 * code that recreates your resources directly (outside Clutter).
1731 #ifdef CLUTTER_ENABLE_DEBUG
1732 clutter_actor_verify_map_state (self);
1735 clutter_actor_hide (self);
1737 clutter_actor_unrealize_not_hiding (self);
1740 static ClutterActorTraverseVisitFlags
1741 unrealize_actor_before_children_cb (ClutterActor *self,
1745 /* If an actor is already unrealized we know its children have also
1746 * already been unrealized... */
1747 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1748 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1750 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1752 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1755 static ClutterActorTraverseVisitFlags
1756 unrealize_actor_after_children_cb (ClutterActor *self,
1760 /* We want to unset the realized flag only _after_
1761 * child actors are unrealized, to maintain invariants.
1763 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1764 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1765 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1769 * clutter_actor_unrealize_not_hiding:
1770 * @self: A #ClutterActor
1772 * Unrealization informs the actor that it may be being destroyed or
1773 * moved to another stage. The actor may want to destroy any
1774 * underlying graphics resources at this point. However it is
1775 * perfectly acceptable for it to retain the resources until the actor
1776 * is destroyed because Clutter only ever uses a single rendering
1777 * context and all of the graphics resources are valid on any stage.
1779 * Because mapped actors must be realized, actors may not be
1780 * unrealized if they are mapped. You must hide the actor or one of
1781 * its parents before attempting to unrealize.
1783 * This function is separate from clutter_actor_unrealize() because it
1784 * does not automatically hide the actor.
1785 * Actors need not be hidden to be unrealized, they just need to
1786 * be unmapped. In fact we don't want to mess up the application's
1787 * setting of the "visible" flag, so hiding is very undesirable.
1789 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1790 * backward compatibility.
1793 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1795 _clutter_actor_traverse (self,
1796 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1797 unrealize_actor_before_children_cb,
1798 unrealize_actor_after_children_cb,
1803 * _clutter_actor_rerealize:
1804 * @self: A #ClutterActor
1805 * @callback: Function to call while unrealized
1806 * @data: data for callback
1808 * If an actor is already unrealized, this just calls the callback.
1810 * If it is realized, it unrealizes temporarily, calls the callback,
1811 * and then re-realizes the actor.
1813 * As a side effect, leaves all children of the actor unrealized if
1814 * the actor was realized but not showing. This is because when we
1815 * unrealize the actor temporarily we must unrealize its children
1816 * (e.g. children of a stage can't be realized if stage window is
1817 * gone). And we aren't clever enough to save the realization state of
1818 * all children. In most cases this should not matter, because
1819 * the children will automatically realize when they next become mapped.
1822 _clutter_actor_rerealize (ClutterActor *self,
1823 ClutterCallback callback,
1826 gboolean was_mapped;
1827 gboolean was_showing;
1828 gboolean was_realized;
1830 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1832 #ifdef CLUTTER_ENABLE_DEBUG
1833 clutter_actor_verify_map_state (self);
1836 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1837 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1838 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1840 /* Must be unmapped to unrealize. Note we only have to hide this
1841 * actor if it was mapped (if all parents were showing). If actor
1842 * is merely visible (but not mapped), then that's fine, we can
1846 clutter_actor_hide (self);
1848 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1850 /* unrealize self and all children */
1851 clutter_actor_unrealize_not_hiding (self);
1853 if (callback != NULL)
1855 (* callback) (self, data);
1859 clutter_actor_show (self); /* will realize only if mapping implies it */
1860 else if (was_realized)
1861 clutter_actor_realize (self); /* realize self and all parents */
1865 clutter_actor_real_pick (ClutterActor *self,
1866 const ClutterColor *color)
1868 /* the default implementation is just to paint a rectangle
1869 * with the same size of the actor using the passed color
1871 if (clutter_actor_should_pick_paint (self))
1873 ClutterActorBox box = { 0, };
1874 float width, height;
1876 clutter_actor_get_allocation_box (self, &box);
1878 width = box.x2 - box.x1;
1879 height = box.y2 - box.y1;
1881 cogl_set_source_color4ub (color->red,
1886 cogl_rectangle (0, 0, width, height);
1889 /* XXX - this thoroughly sucks, but we need to maintain compatibility
1890 * with existing container classes that override the pick() virtual
1891 * and chain up to the default implementation - otherwise we'll end up
1892 * painting our children twice.
1894 * this has to go away for 2.0; hopefully along the pick() itself.
1896 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1900 for (iter = self->priv->first_child;
1902 iter = iter->priv->next_sibling)
1903 clutter_actor_paint (iter);
1908 * clutter_actor_should_pick_paint:
1909 * @self: A #ClutterActor
1911 * Should be called inside the implementation of the
1912 * #ClutterActor::pick virtual function in order to check whether
1913 * the actor should paint itself in pick mode or not.
1915 * This function should never be called directly by applications.
1917 * Return value: %TRUE if the actor should paint its silhouette,
1921 clutter_actor_should_pick_paint (ClutterActor *self)
1923 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1925 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1926 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1927 CLUTTER_ACTOR_IS_REACTIVE (self)))
1934 clutter_actor_real_get_preferred_width (ClutterActor *self,
1936 gfloat *min_width_p,
1937 gfloat *natural_width_p)
1939 ClutterActorPrivate *priv = self->priv;
1941 if (priv->n_children != 0 &&
1942 priv->layout_manager != NULL)
1944 ClutterContainer *container = CLUTTER_CONTAINER (self);
1946 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1947 "for the preferred width",
1948 G_OBJECT_TYPE_NAME (priv->layout_manager),
1949 priv->layout_manager);
1951 clutter_layout_manager_get_preferred_width (priv->layout_manager,
1960 /* Default implementation is always 0x0, usually an actor
1961 * using this default is relying on someone to set the
1964 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1969 if (natural_width_p)
1970 *natural_width_p = 0;
1974 clutter_actor_real_get_preferred_height (ClutterActor *self,
1976 gfloat *min_height_p,
1977 gfloat *natural_height_p)
1979 ClutterActorPrivate *priv = self->priv;
1981 if (priv->n_children != 0 &&
1982 priv->layout_manager != NULL)
1984 ClutterContainer *container = CLUTTER_CONTAINER (self);
1986 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1987 "for the preferred height",
1988 G_OBJECT_TYPE_NAME (priv->layout_manager),
1989 priv->layout_manager);
1991 clutter_layout_manager_get_preferred_height (priv->layout_manager,
1999 /* Default implementation is always 0x0, usually an actor
2000 * using this default is relying on someone to set the
2003 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2008 if (natural_height_p)
2009 *natural_height_p = 0;
2013 clutter_actor_store_old_geometry (ClutterActor *self,
2014 ClutterActorBox *box)
2016 *box = self->priv->allocation;
2020 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2021 const ClutterActorBox *old)
2023 ClutterActorPrivate *priv = self->priv;
2024 GObject *obj = G_OBJECT (self);
2026 g_object_freeze_notify (obj);
2028 /* to avoid excessive requisition or allocation cycles we
2029 * use the cached values.
2031 * - if we don't have an allocation we assume that we need
2033 * - if we don't have a width or a height request we notify
2035 * - if we have a valid allocation then we check the old
2036 * bounding box with the current allocation and we notify
2039 if (priv->needs_allocation)
2041 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2042 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2043 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2044 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2046 else if (priv->needs_width_request || priv->needs_height_request)
2048 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2049 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2054 gfloat widthu, heightu;
2056 xu = priv->allocation.x1;
2057 yu = priv->allocation.y1;
2058 widthu = priv->allocation.x2 - priv->allocation.x1;
2059 heightu = priv->allocation.y2 - priv->allocation.y1;
2062 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2065 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2067 if (widthu != (old->x2 - old->x1))
2068 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2070 if (heightu != (old->y2 - old->y1))
2071 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2074 g_object_thaw_notify (obj);
2078 * clutter_actor_set_allocation_internal:
2079 * @self: a #ClutterActor
2080 * @box: a #ClutterActorBox
2081 * @flags: allocation flags
2083 * Stores the allocation of @self.
2085 * This function only performs basic storage and property notification.
2087 * This function should be called by clutter_actor_set_allocation()
2088 * and by the default implementation of #ClutterActorClass.allocate().
2090 * Return value: %TRUE if the allocation of the #ClutterActor has been
2091 * changed, and %FALSE otherwise
2093 static inline gboolean
2094 clutter_actor_set_allocation_internal (ClutterActor *self,
2095 const ClutterActorBox *box,
2096 ClutterAllocationFlags flags)
2098 ClutterActorPrivate *priv = self->priv;
2100 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2101 gboolean flags_changed;
2103 ClutterActorBox old_alloc = { 0, };
2105 obj = G_OBJECT (self);
2107 g_object_freeze_notify (obj);
2109 clutter_actor_store_old_geometry (self, &old_alloc);
2111 x1_changed = priv->allocation.x1 != box->x1;
2112 y1_changed = priv->allocation.y1 != box->y1;
2113 x2_changed = priv->allocation.x2 != box->x2;
2114 y2_changed = priv->allocation.y2 != box->y2;
2116 flags_changed = priv->allocation_flags != flags;
2118 priv->allocation = *box;
2119 priv->allocation_flags = flags;
2121 /* allocation is authoritative */
2122 priv->needs_width_request = FALSE;
2123 priv->needs_height_request = FALSE;
2124 priv->needs_allocation = FALSE;
2126 if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2128 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2129 _clutter_actor_get_debug_name (self));
2131 priv->transform_valid = FALSE;
2133 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2135 /* if the allocation changes, so does the content box */
2136 if (priv->content != NULL)
2137 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2144 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2146 g_object_thaw_notify (obj);
2151 static void clutter_actor_real_allocate (ClutterActor *self,
2152 const ClutterActorBox *box,
2153 ClutterAllocationFlags flags);
2156 clutter_actor_maybe_layout_children (ClutterActor *self,
2157 const ClutterActorBox *allocation,
2158 ClutterAllocationFlags flags)
2160 ClutterActorPrivate *priv = self->priv;
2162 /* this is going to be a bit hard to follow, so let's put an explanation
2165 * we want ClutterActor to have a default layout manager if the actor was
2166 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2168 * we also want any subclass of ClutterActor that does not override the
2169 * ::allocate() virtual function to delegate to a layout manager.
2171 * finally, we want to allow people subclassing ClutterActor and overriding
2172 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2174 * on the other hand, we want existing actor subclasses overriding the
2175 * ::allocate() virtual function and chaining up to the parent's
2176 * implementation to continue working without allocating their children
2177 * twice, or without entering an allocation loop.
2179 * for the first two points, we check if the class of the actor is
2180 * overridding the ::allocate() virtual function; if it isn't, then we
2181 * follow through with checking whether we have children and a layout
2182 * manager, and eventually calling clutter_layout_manager_allocate().
2184 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2185 * allocation flags that we got passed, and if it is present, we continue
2186 * with the check above.
2188 * if neither of these two checks yields a positive result, we just
2189 * assume that the ::allocate() virtual function that resulted in this
2190 * function being called will also allocate the children of the actor.
2193 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2196 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2202 if (priv->n_children != 0 &&
2203 priv->layout_manager != NULL)
2205 ClutterContainer *container = CLUTTER_CONTAINER (self);
2206 ClutterAllocationFlags children_flags;
2207 ClutterActorBox children_box;
2209 /* normalize the box passed to the layout manager */
2210 children_box.x1 = children_box.y1 = 0.f;
2211 children_box.x2 = (allocation->x2 - allocation->x1);
2212 children_box.y2 = (allocation->y2 - allocation->y1);
2214 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2215 * the actor's children, since it refers only to the current
2216 * actor's allocation.
2218 children_flags = flags;
2219 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2221 CLUTTER_NOTE (LAYOUT,
2222 "Allocating %d children of %s "
2223 "at { %.2f, %.2f - %.2f x %.2f } "
2226 _clutter_actor_get_debug_name (self),
2229 (allocation->x2 - allocation->x1),
2230 (allocation->y2 - allocation->y1),
2231 G_OBJECT_TYPE_NAME (priv->layout_manager));
2233 clutter_layout_manager_allocate (priv->layout_manager,
2241 clutter_actor_real_allocate (ClutterActor *self,
2242 const ClutterActorBox *box,
2243 ClutterAllocationFlags flags)
2245 ClutterActorPrivate *priv = self->priv;
2248 g_object_freeze_notify (G_OBJECT (self));
2250 changed = clutter_actor_set_allocation_internal (self, box, flags);
2252 /* we allocate our children before we notify changes in our geometry,
2253 * so that people connecting to properties will be able to get valid
2254 * data out of the sub-tree of the scene graph that has this actor at
2257 clutter_actor_maybe_layout_children (self, box, flags);
2261 ClutterActorBox signal_box = priv->allocation;
2262 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2264 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2269 g_object_thaw_notify (G_OBJECT (self));
2273 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2274 ClutterActor *origin)
2276 /* no point in queuing a redraw on a destroyed actor */
2277 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2280 /* NB: We can't bail out early here if the actor is hidden in case
2281 * the actor bas been cloned. In this case the clone will need to
2282 * receive the signal so it can queue its own redraw.
2285 /* calls klass->queue_redraw in default handler */
2286 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2290 clutter_actor_real_queue_redraw (ClutterActor *self,
2291 ClutterActor *origin)
2293 ClutterActor *parent;
2295 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2296 _clutter_actor_get_debug_name (self),
2297 origin != NULL ? _clutter_actor_get_debug_name (origin)
2300 /* no point in queuing a redraw on a destroyed actor */
2301 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2304 /* If the queue redraw is coming from a child then the actor has
2305 become dirty and any queued effect is no longer valid */
2308 self->priv->is_dirty = TRUE;
2309 self->priv->effect_to_redraw = NULL;
2312 /* If the actor isn't visible, we still had to emit the signal
2313 * to allow for a ClutterClone, but the appearance of the parent
2314 * won't change so we don't have to propagate up the hierarchy.
2316 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2319 /* Although we could determine here that a full stage redraw
2320 * has already been queued and immediately bail out, we actually
2321 * guarantee that we will propagate a queue-redraw signal to our
2322 * parent at least once so that it's possible to implement a
2323 * container that tracks which of its children have queued a
2326 if (self->priv->propagated_one_redraw)
2328 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2329 if (stage != NULL &&
2330 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2334 self->priv->propagated_one_redraw = TRUE;
2336 /* notify parents, if they are all visible eventually we'll
2337 * queue redraw on the stage, which queues the redraw idle.
2339 parent = clutter_actor_get_parent (self);
2342 /* this will go up recursively */
2343 _clutter_actor_signal_queue_redraw (parent, origin);
2348 clutter_actor_real_queue_relayout (ClutterActor *self)
2350 ClutterActorPrivate *priv = self->priv;
2352 /* no point in queueing a redraw on a destroyed actor */
2353 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2356 priv->needs_width_request = TRUE;
2357 priv->needs_height_request = TRUE;
2358 priv->needs_allocation = TRUE;
2360 /* reset the cached size requests */
2361 memset (priv->width_requests, 0,
2362 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2363 memset (priv->height_requests, 0,
2364 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2366 /* We need to go all the way up the hierarchy */
2367 if (priv->parent != NULL)
2368 _clutter_actor_queue_only_relayout (priv->parent);
2372 * clutter_actor_apply_relative_transform_to_point:
2373 * @self: A #ClutterActor
2374 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2375 * default #ClutterStage
2376 * @point: A point as #ClutterVertex
2377 * @vertex: (out caller-allocates): The translated #ClutterVertex
2379 * Transforms @point in coordinates relative to the actor into
2380 * ancestor-relative coordinates using the relevant transform
2381 * stack (i.e. scale, rotation, etc).
2383 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2384 * this case, the coordinates returned will be the coordinates on
2385 * the stage before the projection is applied. This is different from
2386 * the behaviour of clutter_actor_apply_transform_to_point().
2391 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2392 ClutterActor *ancestor,
2393 const ClutterVertex *point,
2394 ClutterVertex *vertex)
2399 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2400 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2401 g_return_if_fail (point != NULL);
2402 g_return_if_fail (vertex != NULL);
2407 if (ancestor == NULL)
2408 ancestor = _clutter_actor_get_stage_internal (self);
2410 if (ancestor == NULL)
2416 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2417 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2421 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2422 const ClutterVertex *vertices_in,
2423 ClutterVertex *vertices_out,
2426 ClutterActor *stage;
2427 CoglMatrix modelview;
2428 CoglMatrix projection;
2431 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2433 stage = _clutter_actor_get_stage_internal (self);
2435 /* We really can't do anything meaningful in this case so don't try
2436 * to do any transform */
2440 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2441 * that gets us to stage coordinates, we want to go all the way to eye
2443 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2445 /* Fetch the projection and viewport */
2446 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2447 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2453 _clutter_util_fully_transform_vertices (&modelview,
2464 * clutter_actor_apply_transform_to_point:
2465 * @self: A #ClutterActor
2466 * @point: A point as #ClutterVertex
2467 * @vertex: (out caller-allocates): The translated #ClutterVertex
2469 * Transforms @point in coordinates relative to the actor
2470 * into screen-relative coordinates with the current actor
2471 * transformation (i.e. scale, rotation, etc)
2476 clutter_actor_apply_transform_to_point (ClutterActor *self,
2477 const ClutterVertex *point,
2478 ClutterVertex *vertex)
2480 g_return_if_fail (point != NULL);
2481 g_return_if_fail (vertex != NULL);
2482 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2486 * _clutter_actor_get_relative_transformation_matrix:
2487 * @self: The actor whose coordinate space you want to transform from.
2488 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2489 * or %NULL if you want to transform all the way to eye coordinates.
2490 * @matrix: A #CoglMatrix to store the transformation
2492 * This gets a transformation @matrix that will transform coordinates from the
2493 * coordinate space of @self into the coordinate space of @ancestor.
2495 * For example if you need a matrix that can transform the local actor
2496 * coordinates of @self into stage coordinates you would pass the actor's stage
2497 * pointer as the @ancestor.
2499 * If you pass %NULL then the transformation will take you all the way through
2500 * to eye coordinates. This can be useful if you want to extract the entire
2501 * modelview transform that Clutter applies before applying the projection
2502 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2503 * using cogl_set_modelview_matrix() for example then you would want a matrix
2504 * that transforms into eye coordinates.
2506 * <note><para>This function explicitly initializes the given @matrix. If you just
2507 * want clutter to multiply a relative transformation with an existing matrix
2508 * you can use clutter_actor_apply_relative_transformation_matrix()
2509 * instead.</para></note>
2512 /* XXX: We should consider caching the stage relative modelview along with
2513 * the actor itself */
2515 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2516 ClutterActor *ancestor,
2519 cogl_matrix_init_identity (matrix);
2521 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2524 /* Project the given @box into stage window coordinates, writing the
2525 * transformed vertices to @verts[]. */
2527 _clutter_actor_transform_and_project_box (ClutterActor *self,
2528 const ClutterActorBox *box,
2529 ClutterVertex verts[])
2531 ClutterVertex box_vertices[4];
2533 box_vertices[0].x = box->x1;
2534 box_vertices[0].y = box->y1;
2535 box_vertices[0].z = 0;
2536 box_vertices[1].x = box->x2;
2537 box_vertices[1].y = box->y1;
2538 box_vertices[1].z = 0;
2539 box_vertices[2].x = box->x1;
2540 box_vertices[2].y = box->y2;
2541 box_vertices[2].z = 0;
2542 box_vertices[3].x = box->x2;
2543 box_vertices[3].y = box->y2;
2544 box_vertices[3].z = 0;
2547 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2551 * clutter_actor_get_allocation_vertices:
2552 * @self: A #ClutterActor
2553 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2554 * against, or %NULL to use the #ClutterStage
2555 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2556 * location for an array of 4 #ClutterVertex in which to store the result
2558 * Calculates the transformed coordinates of the four corners of the
2559 * actor in the plane of @ancestor. The returned vertices relate to
2560 * the #ClutterActorBox coordinates as follows:
2562 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2563 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2564 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2565 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2568 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2569 * this case, the coordinates returned will be the coordinates on
2570 * the stage before the projection is applied. This is different from
2571 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2576 clutter_actor_get_allocation_vertices (ClutterActor *self,
2577 ClutterActor *ancestor,
2578 ClutterVertex verts[])
2580 ClutterActorPrivate *priv;
2581 ClutterActorBox box;
2582 ClutterVertex vertices[4];
2583 CoglMatrix modelview;
2585 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2586 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2588 if (ancestor == NULL)
2589 ancestor = _clutter_actor_get_stage_internal (self);
2591 /* Fallback to a NOP transform if the actor isn't parented under a
2593 if (ancestor == NULL)
2598 /* if the actor needs to be allocated we force a relayout, so that
2599 * we will have valid values to use in the transformations */
2600 if (priv->needs_allocation)
2602 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2604 _clutter_stage_maybe_relayout (stage);
2607 box.x1 = box.y1 = 0;
2608 /* The result isn't really meaningful in this case but at
2609 * least try to do something *vaguely* reasonable... */
2610 clutter_actor_get_size (self, &box.x2, &box.y2);
2614 clutter_actor_get_allocation_box (self, &box);
2616 vertices[0].x = box.x1;
2617 vertices[0].y = box.y1;
2619 vertices[1].x = box.x2;
2620 vertices[1].y = box.y1;
2622 vertices[2].x = box.x1;
2623 vertices[2].y = box.y2;
2625 vertices[3].x = box.x2;
2626 vertices[3].y = box.y2;
2629 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2632 cogl_matrix_transform_points (&modelview,
2634 sizeof (ClutterVertex),
2636 sizeof (ClutterVertex),
2642 * clutter_actor_get_abs_allocation_vertices:
2643 * @self: A #ClutterActor
2644 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2645 * of 4 #ClutterVertex where to store the result.
2647 * Calculates the transformed screen coordinates of the four corners of
2648 * the actor; the returned vertices relate to the #ClutterActorBox
2649 * coordinates as follows:
2651 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2652 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2653 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2654 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2660 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2661 ClutterVertex verts[])
2663 ClutterActorPrivate *priv;
2664 ClutterActorBox actor_space_allocation;
2666 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2670 /* if the actor needs to be allocated we force a relayout, so that
2671 * the actor allocation box will be valid for
2672 * _clutter_actor_transform_and_project_box()
2674 if (priv->needs_allocation)
2676 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2677 /* There's nothing meaningful we can do now */
2681 _clutter_stage_maybe_relayout (stage);
2684 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2685 * own coordinate space... */
2686 actor_space_allocation.x1 = 0;
2687 actor_space_allocation.y1 = 0;
2688 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2689 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2690 _clutter_actor_transform_and_project_box (self,
2691 &actor_space_allocation,
2696 clutter_actor_real_apply_transform (ClutterActor *self,
2699 ClutterActorPrivate *priv = self->priv;
2701 if (!priv->transform_valid)
2703 CoglMatrix *transform = &priv->transform;
2704 const ClutterTransformInfo *info;
2706 info = _clutter_actor_get_transform_info_or_defaults (self);
2708 cogl_matrix_init_identity (transform);
2710 cogl_matrix_translate (transform,
2711 priv->allocation.x1,
2712 priv->allocation.y1,
2716 cogl_matrix_translate (transform, 0, 0, info->depth);
2719 * because the rotation involves translations, we must scale
2720 * before applying the rotations (if we apply the scale after
2721 * the rotations, the translations included in the rotation are
2722 * not scaled and so the entire object will move on the screen
2723 * as a result of rotating it).
2725 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2727 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2728 &info->scale_center,
2729 cogl_matrix_scale (transform,
2736 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2738 cogl_matrix_rotate (transform,
2743 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2745 cogl_matrix_rotate (transform,
2750 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2752 cogl_matrix_rotate (transform,
2756 if (!clutter_anchor_coord_is_zero (&info->anchor))
2760 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2761 cogl_matrix_translate (transform, -x, -y, -z);
2764 priv->transform_valid = TRUE;
2767 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2770 /* Applies the transforms associated with this actor to the given
2773 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2776 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2780 * clutter_actor_apply_relative_transformation_matrix:
2781 * @self: The actor whose coordinate space you want to transform from.
2782 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2783 * or %NULL if you want to transform all the way to eye coordinates.
2784 * @matrix: A #CoglMatrix to apply the transformation too.
2786 * This multiplies a transform with @matrix that will transform coordinates
2787 * from the coordinate space of @self into the coordinate space of @ancestor.
2789 * For example if you need a matrix that can transform the local actor
2790 * coordinates of @self into stage coordinates you would pass the actor's stage
2791 * pointer as the @ancestor.
2793 * If you pass %NULL then the transformation will take you all the way through
2794 * to eye coordinates. This can be useful if you want to extract the entire
2795 * modelview transform that Clutter applies before applying the projection
2796 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2797 * using cogl_set_modelview_matrix() for example then you would want a matrix
2798 * that transforms into eye coordinates.
2800 * <note>This function doesn't initialize the given @matrix, it simply
2801 * multiplies the requested transformation matrix with the existing contents of
2802 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2803 * before calling this function, or you can use
2804 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2807 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2808 ClutterActor *ancestor,
2811 ClutterActor *parent;
2813 /* Note we terminate before ever calling stage->apply_transform()
2814 * since that would conceptually be relative to the underlying
2815 * window OpenGL coordinates so we'd need a special @ancestor
2816 * value to represent the fake parent of the stage. */
2817 if (self == ancestor)
2820 parent = clutter_actor_get_parent (self);
2823 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2826 _clutter_actor_apply_modelview_transform (self, matrix);
2830 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2831 ClutterPaintVolume *pv,
2833 const CoglColor *color)
2835 static CoglPipeline *outline = NULL;
2836 CoglPrimitive *prim;
2837 ClutterVertex line_ends[12 * 2];
2840 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2841 /* XXX: at some point we'll query this from the stage but we can't
2842 * do that until the osx backend uses Cogl natively. */
2843 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2845 if (outline == NULL)
2846 outline = cogl_pipeline_new (ctx);
2848 _clutter_paint_volume_complete (pv);
2850 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2853 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2854 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2855 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2856 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2861 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2862 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2863 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2864 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2866 /* Lines connecting front face to back face */
2867 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2868 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2869 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2870 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2873 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2875 (CoglVertexP3 *)line_ends);
2877 cogl_pipeline_set_color (outline, color);
2878 cogl_framebuffer_draw_primitive (fb, outline, prim);
2879 cogl_object_unref (prim);
2883 PangoLayout *layout;
2884 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2885 pango_layout_set_text (layout, label, -1);
2886 cogl_pango_render_layout (layout,
2891 g_object_unref (layout);
2896 _clutter_actor_draw_paint_volume (ClutterActor *self)
2898 ClutterPaintVolume *pv;
2901 pv = _clutter_actor_get_paint_volume_mutable (self);
2904 gfloat width, height;
2905 ClutterPaintVolume fake_pv;
2907 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2908 _clutter_paint_volume_init_static (&fake_pv, stage);
2910 clutter_actor_get_size (self, &width, &height);
2911 clutter_paint_volume_set_width (&fake_pv, width);
2912 clutter_paint_volume_set_height (&fake_pv, height);
2914 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2915 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2916 _clutter_actor_get_debug_name (self),
2919 clutter_paint_volume_free (&fake_pv);
2923 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2924 _clutter_actor_draw_paint_volume_full (self, pv,
2925 _clutter_actor_get_debug_name (self),
2931 _clutter_actor_paint_cull_result (ClutterActor *self,
2933 ClutterCullResult result)
2935 ClutterPaintVolume *pv;
2940 if (result == CLUTTER_CULL_RESULT_IN)
2941 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2942 else if (result == CLUTTER_CULL_RESULT_OUT)
2943 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2945 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2948 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2950 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2951 _clutter_actor_draw_paint_volume_full (self, pv,
2952 _clutter_actor_get_debug_name (self),
2956 PangoLayout *layout;
2958 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2959 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2960 cogl_set_source_color (&color);
2962 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2963 pango_layout_set_text (layout, label, -1);
2964 cogl_pango_render_layout (layout,
2970 g_object_unref (layout);
2974 static int clone_paint_level = 0;
2977 _clutter_actor_push_clone_paint (void)
2979 clone_paint_level++;
2983 _clutter_actor_pop_clone_paint (void)
2985 clone_paint_level--;
2989 in_clone_paint (void)
2991 return clone_paint_level > 0;
2994 /* Returns TRUE if the actor can be ignored */
2995 /* FIXME: we should return a ClutterCullResult, and
2996 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2997 * means there's no point in trying to cull descendants of the current
3000 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3002 ClutterActorPrivate *priv = self->priv;
3003 ClutterActor *stage;
3004 const ClutterPlane *stage_clip;
3006 if (!priv->last_paint_volume_valid)
3008 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3009 "->last_paint_volume_valid == FALSE",
3010 _clutter_actor_get_debug_name (self));
3014 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3017 stage = _clutter_actor_get_stage_internal (self);
3018 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3019 if (G_UNLIKELY (!stage_clip))
3021 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3022 "No stage clip set",
3023 _clutter_actor_get_debug_name (self));
3027 if (cogl_get_draw_framebuffer () !=
3028 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3030 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3031 "Current framebuffer doesn't correspond to stage",
3032 _clutter_actor_get_debug_name (self));
3037 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3042 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3044 ClutterActorPrivate *priv = self->priv;
3045 const ClutterPaintVolume *pv;
3047 if (priv->last_paint_volume_valid)
3049 clutter_paint_volume_free (&priv->last_paint_volume);
3050 priv->last_paint_volume_valid = FALSE;
3053 pv = clutter_actor_get_paint_volume (self);
3056 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3057 "Actor failed to report a paint volume",
3058 _clutter_actor_get_debug_name (self));
3062 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3064 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3065 NULL); /* eye coordinates */
3067 priv->last_paint_volume_valid = TRUE;
3070 static inline gboolean
3071 actor_has_shader_data (ClutterActor *self)
3073 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3077 _clutter_actor_get_pick_id (ClutterActor *self)
3079 if (self->priv->pick_id < 0)
3082 return self->priv->pick_id;
3085 /* This is the same as clutter_actor_add_effect except that it doesn't
3086 queue a redraw and it doesn't notify on the effect property */
3088 _clutter_actor_add_effect_internal (ClutterActor *self,
3089 ClutterEffect *effect)
3091 ClutterActorPrivate *priv = self->priv;
3093 if (priv->effects == NULL)
3095 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3096 priv->effects->actor = self;
3099 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3102 /* This is the same as clutter_actor_remove_effect except that it doesn't
3103 queue a redraw and it doesn't notify on the effect property */
3105 _clutter_actor_remove_effect_internal (ClutterActor *self,
3106 ClutterEffect *effect)
3108 ClutterActorPrivate *priv = self->priv;
3110 if (priv->effects == NULL)
3113 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3117 needs_flatten_effect (ClutterActor *self)
3119 ClutterActorPrivate *priv = self->priv;
3121 if (G_UNLIKELY (clutter_paint_debug_flags &
3122 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3125 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3127 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3129 if (clutter_actor_get_paint_opacity (self) < 255 &&
3130 clutter_actor_has_overlaps (self))
3138 add_or_remove_flatten_effect (ClutterActor *self)
3140 ClutterActorPrivate *priv = self->priv;
3142 /* Add or remove the flatten effect depending on the
3143 offscreen-redirect property. */
3144 if (needs_flatten_effect (self))
3146 if (priv->flatten_effect == NULL)
3148 ClutterActorMeta *actor_meta;
3151 priv->flatten_effect = _clutter_flatten_effect_new ();
3152 /* Keep a reference to the effect so that we can queue
3154 g_object_ref_sink (priv->flatten_effect);
3156 /* Set the priority of the effect to high so that it will
3157 always be applied to the actor first. It uses an internal
3158 priority so that it won't be visible to applications */
3159 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3160 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3161 _clutter_actor_meta_set_priority (actor_meta, priority);
3163 /* This will add the effect without queueing a redraw */
3164 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3169 if (priv->flatten_effect != NULL)
3171 /* Destroy the effect so that it will lose its fbo cache of
3173 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3174 g_object_unref (priv->flatten_effect);
3175 priv->flatten_effect = NULL;
3181 clutter_actor_real_paint (ClutterActor *actor)
3183 ClutterActorPrivate *priv = actor->priv;
3186 for (iter = priv->first_child;
3188 iter = iter->priv->next_sibling)
3190 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3191 _clutter_actor_get_debug_name (iter),
3192 _clutter_actor_get_debug_name (actor),
3193 iter->priv->allocation.x1,
3194 iter->priv->allocation.y1,
3195 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3196 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3198 clutter_actor_paint (iter);
3203 clutter_actor_paint_node (ClutterActor *actor,
3204 ClutterPaintNode *root)
3206 ClutterActorPrivate *priv = actor->priv;
3211 if (priv->bg_color_set &&
3212 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3214 ClutterPaintNode *node;
3215 ClutterColor bg_color;
3216 ClutterActorBox box;
3220 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3221 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3223 bg_color = priv->bg_color;
3224 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3225 * priv->bg_color.alpha
3228 node = clutter_color_node_new (&bg_color);
3229 clutter_paint_node_set_name (node, "backgroundColor");
3230 clutter_paint_node_add_rectangle (node, &box);
3231 clutter_paint_node_add_child (root, node);
3232 clutter_paint_node_unref (node);
3235 if (priv->content != NULL)
3236 _clutter_content_paint_content (priv->content, actor, root);
3238 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3239 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3241 if (clutter_paint_node_get_n_children (root) == 0)
3244 #ifdef CLUTTER_ENABLE_DEBUG
3245 if (CLUTTER_HAS_DEBUG (PAINT))
3247 /* dump the tree only if we have one */
3248 _clutter_paint_node_dump_tree (root);
3250 #endif /* CLUTTER_ENABLE_DEBUG */
3252 _clutter_paint_node_paint (root);
3254 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3260 * clutter_actor_paint:
3261 * @self: A #ClutterActor
3263 * Renders the actor to display.
3265 * This function should not be called directly by applications.
3266 * Call clutter_actor_queue_redraw() to queue paints, instead.
3268 * This function is context-aware, and will either cause a
3269 * regular paint or a pick paint.
3271 * This function will emit the #ClutterActor::paint signal or
3272 * the #ClutterActor::pick signal, depending on the context.
3274 * This function does not paint the actor if the actor is set to 0,
3275 * unless it is performing a pick paint.
3278 clutter_actor_paint (ClutterActor *self)
3280 ClutterActorPrivate *priv;
3281 ClutterPickMode pick_mode;
3282 gboolean clip_set = FALSE;
3283 gboolean shader_applied = FALSE;
3285 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3286 "Actor real-paint counter",
3287 "Increments each time any actor is painted",
3288 0 /* no application private data */);
3289 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3290 "Actor pick-paint counter",
3291 "Increments each time any actor is painted "
3293 0 /* no application private data */);
3295 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3297 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3302 pick_mode = _clutter_context_get_pick_mode ();
3304 if (pick_mode == CLUTTER_PICK_NONE)
3305 priv->propagated_one_redraw = FALSE;
3307 /* It's an important optimization that we consider painting of
3308 * actors with 0 opacity to be a NOP... */
3309 if (pick_mode == CLUTTER_PICK_NONE &&
3310 /* ignore top-levels, since they might be transparent */
3311 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3312 /* Use the override opacity if its been set */
3313 ((priv->opacity_override >= 0) ?
3314 priv->opacity_override : priv->opacity) == 0)
3317 /* if we aren't paintable (not in a toplevel with all
3318 * parents paintable) then do nothing.
3320 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3323 /* mark that we are in the paint process */
3324 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3328 if (priv->enable_model_view_transform)
3332 /* XXX: It could be better to cache the modelview with the actor
3333 * instead of progressively building up the transformations on
3334 * the matrix stack every time we paint. */
3335 cogl_get_modelview_matrix (&matrix);
3336 _clutter_actor_apply_modelview_transform (self, &matrix);
3338 #ifdef CLUTTER_ENABLE_DEBUG
3339 /* Catch when out-of-band transforms have been made by actors not as part
3340 * of an apply_transform vfunc... */
3341 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3343 CoglMatrix expected_matrix;
3345 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3348 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3350 GString *buf = g_string_sized_new (1024);
3351 ClutterActor *parent;
3354 while (parent != NULL)
3356 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3358 if (parent->priv->parent != NULL)
3359 g_string_append (buf, "->");
3361 parent = parent->priv->parent;
3364 g_warning ("Unexpected transform found when painting actor "
3365 "\"%s\". This will be caused by one of the actor's "
3366 "ancestors (%s) using the Cogl API directly to transform "
3367 "children instead of using ::apply_transform().",
3368 _clutter_actor_get_debug_name (self),
3371 g_string_free (buf, TRUE);
3374 #endif /* CLUTTER_ENABLE_DEBUG */
3376 cogl_set_modelview_matrix (&matrix);
3381 cogl_clip_push_rectangle (priv->clip.x,
3383 priv->clip.x + priv->clip.width,
3384 priv->clip.y + priv->clip.height);
3387 else if (priv->clip_to_allocation)
3389 gfloat width, height;
3391 width = priv->allocation.x2 - priv->allocation.x1;
3392 height = priv->allocation.y2 - priv->allocation.y1;
3394 cogl_clip_push_rectangle (0, 0, width, height);
3398 if (pick_mode == CLUTTER_PICK_NONE)
3400 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3402 /* We check whether we need to add the flatten effect before
3403 each paint so that we can avoid having a mechanism for
3404 applications to notify when the value of the
3405 has_overlaps virtual changes. */
3406 add_or_remove_flatten_effect (self);
3409 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3411 /* We save the current paint volume so that the next time the
3412 * actor queues a redraw we can constrain the redraw to just
3413 * cover the union of the new bounding box and the old.
3415 * We also fetch the current paint volume to perform culling so
3416 * we can avoid painting actors outside the current clip region.
3418 * If we are painting inside a clone, we should neither update
3419 * the paint volume or use it to cull painting, since the paint
3420 * box represents the location of the source actor on the
3423 * XXX: We are starting to do a lot of vertex transforms on
3424 * the CPU in a typical paint, so at some point we should
3425 * audit these and consider caching some things.
3427 * NB: We don't perform culling while picking at this point because
3428 * clutter-stage.c doesn't setup the clipping planes appropriately.
3430 * NB: We don't want to update the last-paint-volume during picking
3431 * because the last-paint-volume is used to determine the old screen
3432 * space location of an actor that has moved so we can know the
3433 * minimal region to redraw to clear an old view of the actor. If we
3434 * update this during picking then by the time we come around to
3435 * paint then the last-paint-volume would likely represent the new
3436 * actor position not the old.
3438 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3441 /* annoyingly gcc warns if uninitialized even though
3442 * the initialization is redundant :-( */
3443 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3445 if (G_LIKELY ((clutter_paint_debug_flags &
3446 (CLUTTER_DEBUG_DISABLE_CULLING |
3447 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3448 (CLUTTER_DEBUG_DISABLE_CULLING |
3449 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3450 _clutter_actor_update_last_paint_volume (self);
3452 success = cull_actor (self, &result);
3454 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3455 _clutter_actor_paint_cull_result (self, success, result);
3456 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3460 if (priv->effects == NULL)
3462 if (pick_mode == CLUTTER_PICK_NONE &&
3463 actor_has_shader_data (self))
3465 _clutter_actor_shader_pre_paint (self, FALSE);
3466 shader_applied = TRUE;
3469 priv->next_effect_to_paint = NULL;
3472 priv->next_effect_to_paint =
3473 _clutter_meta_group_peek_metas (priv->effects);
3475 clutter_actor_continue_paint (self);
3478 _clutter_actor_shader_post_paint (self);
3480 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3481 pick_mode == CLUTTER_PICK_NONE))
3482 _clutter_actor_draw_paint_volume (self);
3485 /* If we make it here then the actor has run through a complete
3486 paint run including all the effects so it's no longer dirty */
3487 if (pick_mode == CLUTTER_PICK_NONE)
3488 priv->is_dirty = FALSE;
3495 /* paint sequence complete */
3496 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3500 * clutter_actor_continue_paint:
3501 * @self: A #ClutterActor
3503 * Run the next stage of the paint sequence. This function should only
3504 * be called within the implementation of the ‘run’ virtual of a
3505 * #ClutterEffect. It will cause the run method of the next effect to
3506 * be applied, or it will paint the actual actor if the current effect
3507 * is the last effect in the chain.
3512 clutter_actor_continue_paint (ClutterActor *self)
3514 ClutterActorPrivate *priv;
3516 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3517 /* This should only be called from with in the ‘run’ implementation
3518 of a ClutterEffect */
3519 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3523 /* Skip any effects that are disabled */
3524 while (priv->next_effect_to_paint &&
3525 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3526 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3528 /* If this has come from the last effect then we'll just paint the
3530 if (priv->next_effect_to_paint == NULL)
3532 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3534 ClutterPaintNode *dummy;
3535 gboolean emit_paint;
3537 /* XXX - this will go away in 2.0, when we can get rid of this
3538 * stuff and switch to a pure retained render tree of PaintNodes
3539 * for the entire frame, starting from the Stage.
3541 dummy = _clutter_dummy_node_new ();
3542 clutter_paint_node_set_name (dummy, "Root");
3543 emit_paint = !clutter_actor_paint_node (self, dummy);
3544 clutter_paint_node_unref (dummy);
3546 if (emit_paint || CLUTTER_ACTOR_IS_TOPLEVEL (self))
3547 g_signal_emit (self, actor_signals[PAINT], 0);
3550 CLUTTER_NOTE (PAINT, "The actor '%s' painted using PaintNodes, "
3551 "skipping the emission of the paint signal.",
3552 _clutter_actor_get_debug_name (self));
3557 ClutterColor col = { 0, };
3559 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3561 /* Actor will then paint silhouette of itself in supplied
3562 * color. See clutter_stage_get_actor_at_pos() for where
3563 * picking is enabled.
3565 g_signal_emit (self, actor_signals[PICK], 0, &col);
3570 ClutterEffect *old_current_effect;
3571 ClutterEffectPaintFlags run_flags = 0;
3573 /* Cache the current effect so that we can put it back before
3575 old_current_effect = priv->current_effect;
3577 priv->current_effect = priv->next_effect_to_paint->data;
3578 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3580 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3584 /* If there's an effect queued with this redraw then all
3585 effects up to that one will be considered dirty. It
3586 is expected the queued effect will paint the cached
3587 image and not call clutter_actor_continue_paint again
3588 (although it should work ok if it does) */
3589 if (priv->effect_to_redraw == NULL ||
3590 priv->current_effect != priv->effect_to_redraw)
3591 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3594 _clutter_effect_paint (priv->current_effect, run_flags);
3598 /* We can't determine when an actor has been modified since
3599 its last pick so lets just assume it has always been
3601 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3603 _clutter_effect_pick (priv->current_effect, run_flags);
3606 priv->current_effect = old_current_effect;
3610 static ClutterActorTraverseVisitFlags
3611 invalidate_queue_redraw_entry (ClutterActor *self,
3615 ClutterActorPrivate *priv = self->priv;
3617 if (priv->queue_redraw_entry != NULL)
3619 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3620 priv->queue_redraw_entry = NULL;
3623 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3627 remove_child (ClutterActor *self,
3628 ClutterActor *child)
3630 ClutterActor *prev_sibling, *next_sibling;
3632 prev_sibling = child->priv->prev_sibling;
3633 next_sibling = child->priv->next_sibling;
3635 if (prev_sibling != NULL)
3636 prev_sibling->priv->next_sibling = next_sibling;
3638 if (next_sibling != NULL)
3639 next_sibling->priv->prev_sibling = prev_sibling;
3641 if (self->priv->first_child == child)
3642 self->priv->first_child = next_sibling;
3644 if (self->priv->last_child == child)
3645 self->priv->last_child = prev_sibling;
3647 child->priv->parent = NULL;
3648 child->priv->prev_sibling = NULL;
3649 child->priv->next_sibling = NULL;
3653 REMOVE_CHILD_DESTROY_META = 1 << 0,
3654 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3655 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3656 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3657 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3658 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3660 /* default flags for public API */
3661 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3662 REMOVE_CHILD_EMIT_PARENT_SET |
3663 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3664 REMOVE_CHILD_CHECK_STATE |
3665 REMOVE_CHILD_FLUSH_QUEUE |
3666 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3668 /* flags for legacy/deprecated API */
3669 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3670 REMOVE_CHILD_FLUSH_QUEUE |
3671 REMOVE_CHILD_EMIT_PARENT_SET |
3672 REMOVE_CHILD_NOTIFY_FIRST_LAST
3673 } ClutterActorRemoveChildFlags;
3676 * clutter_actor_remove_child_internal:
3677 * @self: a #ClutterActor
3678 * @child: the child of @self that has to be removed
3679 * @flags: control the removal operations
3681 * Removes @child from the list of children of @self.
3684 clutter_actor_remove_child_internal (ClutterActor *self,
3685 ClutterActor *child,
3686 ClutterActorRemoveChildFlags flags)
3688 ClutterActor *old_first, *old_last;
3689 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3690 gboolean flush_queue;
3691 gboolean notify_first_last;
3692 gboolean was_mapped;
3694 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3695 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3696 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3697 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3698 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3699 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3701 g_object_freeze_notify (G_OBJECT (self));
3704 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3708 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3710 /* we need to unrealize *before* we set parent_actor to NULL,
3711 * because in an unrealize method actors are dissociating from the
3712 * stage, which means they need to be able to
3713 * clutter_actor_get_stage().
3715 * yhis should unmap and unrealize, unless we're reparenting.
3717 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3724 /* We take this opportunity to invalidate any queue redraw entry
3725 * associated with the actor and descendants since we won't be able to
3726 * determine the appropriate stage after this.
3728 * we do this after we updated the mapped state because actors might
3729 * end up queueing redraws inside their mapped/unmapped virtual
3730 * functions, and if we invalidate the redraw entry we could end up
3731 * with an inconsistent state and weird memory corruption. see
3734 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3735 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3737 _clutter_actor_traverse (child,
3739 invalidate_queue_redraw_entry,
3744 old_first = self->priv->first_child;
3745 old_last = self->priv->last_child;
3747 remove_child (self, child);
3749 self->priv->n_children -= 1;
3751 self->priv->age += 1;
3753 /* clutter_actor_reparent() will emit ::parent-set for us */
3754 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3755 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3757 /* if the child was mapped then we need to relayout ourselves to account
3758 * for the removed child
3761 clutter_actor_queue_relayout (self);
3763 /* we need to emit the signal before dropping the reference */
3764 if (emit_actor_removed)
3765 g_signal_emit_by_name (self, "actor-removed", child);
3767 if (notify_first_last)
3769 if (old_first != self->priv->first_child)
3770 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3772 if (old_last != self->priv->last_child)
3773 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3776 g_object_thaw_notify (G_OBJECT (self));
3778 /* remove the reference we acquired in clutter_actor_add_child() */
3779 g_object_unref (child);
3782 static const ClutterTransformInfo default_transform_info = {
3783 0.0, { 0, }, /* rotation-x */
3784 0.0, { 0, }, /* rotation-y */
3785 0.0, { 0, }, /* rotation-z */
3787 1.0, 1.0, { 0, }, /* scale */
3789 { 0, }, /* anchor */
3795 * _clutter_actor_get_transform_info_or_defaults:
3796 * @self: a #ClutterActor
3798 * Retrieves the ClutterTransformInfo structure associated to an actor.
3800 * If the actor does not have a ClutterTransformInfo structure associated
3801 * to it, then the default structure will be returned.
3803 * This function should only be used for getters.
3805 * Return value: a const pointer to the ClutterTransformInfo structure
3807 const ClutterTransformInfo *
3808 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3810 ClutterTransformInfo *info;
3812 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3816 return &default_transform_info;
3820 clutter_transform_info_free (gpointer data)
3823 g_slice_free (ClutterTransformInfo, data);
3827 * _clutter_actor_get_transform_info:
3828 * @self: a #ClutterActor
3830 * Retrieves a pointer to the ClutterTransformInfo structure.
3832 * If the actor does not have a ClutterTransformInfo associated to it, one
3833 * will be created and initialized to the default values.
3835 * This function should be used for setters.
3837 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3840 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3843 ClutterTransformInfo *
3844 _clutter_actor_get_transform_info (ClutterActor *self)
3846 ClutterTransformInfo *info;
3848 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3851 info = g_slice_new (ClutterTransformInfo);
3853 *info = default_transform_info;
3855 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3857 clutter_transform_info_free);
3864 * clutter_actor_set_rotation_angle_internal:
3865 * @self: a #ClutterActor
3866 * @axis: the axis of the angle to change
3867 * @angle: the angle of rotation
3869 * Sets the rotation angle on the given axis without affecting the
3870 * rotation center point.
3873 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3874 ClutterRotateAxis axis,
3877 GObject *obj = G_OBJECT (self);
3878 ClutterTransformInfo *info;
3880 info = _clutter_actor_get_transform_info (self);
3882 g_object_freeze_notify (obj);
3886 case CLUTTER_X_AXIS:
3887 info->rx_angle = angle;
3888 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3891 case CLUTTER_Y_AXIS:
3892 info->ry_angle = angle;
3893 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3896 case CLUTTER_Z_AXIS:
3897 info->rz_angle = angle;
3898 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3902 self->priv->transform_valid = FALSE;
3904 g_object_thaw_notify (obj);
3906 clutter_actor_queue_redraw (self);
3910 clutter_actor_set_rotation_angle (ClutterActor *self,
3911 ClutterRotateAxis axis,
3914 ClutterTransformInfo *info;
3916 info = _clutter_actor_get_transform_info (self);
3918 if (clutter_actor_get_easing_duration (self) != 0)
3920 ClutterTransition *transition;
3921 GParamSpec *pspec = NULL;
3922 double *cur_angle_p = NULL;
3926 case CLUTTER_X_AXIS:
3927 cur_angle_p = &info->rx_angle;
3928 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3931 case CLUTTER_Y_AXIS:
3932 cur_angle_p = &info->ry_angle;
3933 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3936 case CLUTTER_Z_AXIS:
3937 cur_angle_p = &info->rz_angle;
3938 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3942 g_assert (pspec != NULL);
3943 g_assert (cur_angle_p != NULL);
3945 transition = _clutter_actor_get_transition (self, pspec);
3946 if (transition == NULL)
3948 transition = _clutter_actor_create_transition (self, pspec,
3951 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3954 _clutter_actor_update_transition (self, pspec, angle);
3956 self->priv->transform_valid = FALSE;
3957 clutter_actor_queue_redraw (self);
3960 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3964 * clutter_actor_set_rotation_center_internal:
3965 * @self: a #ClutterActor
3966 * @axis: the axis of the center to change
3967 * @center: the coordinates of the rotation center
3969 * Sets the rotation center on the given axis without affecting the
3973 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3974 ClutterRotateAxis axis,
3975 const ClutterVertex *center)
3977 GObject *obj = G_OBJECT (self);
3978 ClutterTransformInfo *info;
3979 ClutterVertex v = { 0, 0, 0 };
3981 info = _clutter_actor_get_transform_info (self);
3986 g_object_freeze_notify (obj);
3990 case CLUTTER_X_AXIS:
3991 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3992 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3995 case CLUTTER_Y_AXIS:
3996 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3997 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4000 case CLUTTER_Z_AXIS:
4001 /* if the previously set rotation center was fractional, then
4002 * setting explicit coordinates will have to notify the
4003 * :rotation-center-z-gravity property as well
4005 if (info->rz_center.is_fractional)
4006 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4008 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4009 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4013 self->priv->transform_valid = FALSE;
4015 g_object_thaw_notify (obj);
4017 clutter_actor_queue_redraw (self);
4021 clutter_actor_animate_scale_factor (ClutterActor *self,
4026 ClutterTransition *transition;
4028 transition = _clutter_actor_get_transition (self, pspec);
4029 if (transition == NULL)
4031 transition = _clutter_actor_create_transition (self, pspec,
4034 clutter_timeline_start (CLUTTER_TIMELINE (transition));
4037 _clutter_actor_update_transition (self, pspec, new_factor);
4040 self->priv->transform_valid = FALSE;
4041 clutter_actor_queue_redraw (self);
4045 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4049 GObject *obj = G_OBJECT (self);
4050 ClutterTransformInfo *info;
4052 info = _clutter_actor_get_transform_info (self);
4054 if (pspec == obj_props[PROP_SCALE_X])
4055 info->scale_x = factor;
4057 info->scale_y = factor;
4059 self->priv->transform_valid = FALSE;
4060 clutter_actor_queue_redraw (self);
4061 g_object_notify_by_pspec (obj, pspec);
4065 clutter_actor_set_scale_factor (ClutterActor *self,
4066 ClutterRotateAxis axis,
4069 GObject *obj = G_OBJECT (self);
4070 ClutterTransformInfo *info;
4073 info = _clutter_actor_get_transform_info (self);
4075 g_object_freeze_notify (obj);
4079 case CLUTTER_X_AXIS:
4080 pspec = obj_props[PROP_SCALE_X];
4082 if (clutter_actor_get_easing_duration (self) != 0)
4083 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4085 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4088 case CLUTTER_Y_AXIS:
4089 pspec = obj_props[PROP_SCALE_Y];
4091 if (clutter_actor_get_easing_duration (self) != 0)
4092 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4094 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4098 g_assert_not_reached ();
4101 g_object_thaw_notify (obj);
4105 clutter_actor_set_scale_center (ClutterActor *self,
4106 ClutterRotateAxis axis,
4109 GObject *obj = G_OBJECT (self);
4110 ClutterTransformInfo *info;
4111 gfloat center_x, center_y;
4113 info = _clutter_actor_get_transform_info (self);
4115 g_object_freeze_notify (obj);
4117 /* get the current scale center coordinates */
4118 clutter_anchor_coord_get_units (self, &info->scale_center,
4123 /* we need to notify this too, because setting explicit coordinates will
4124 * change the gravity as a side effect
4126 if (info->scale_center.is_fractional)
4127 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4131 case CLUTTER_X_AXIS:
4132 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4133 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4136 case CLUTTER_Y_AXIS:
4137 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4138 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4142 g_assert_not_reached ();
4145 self->priv->transform_valid = FALSE;
4147 clutter_actor_queue_redraw (self);
4149 g_object_thaw_notify (obj);
4153 clutter_actor_set_anchor_coord (ClutterActor *self,
4154 ClutterRotateAxis axis,
4157 GObject *obj = G_OBJECT (self);
4158 ClutterTransformInfo *info;
4159 gfloat anchor_x, anchor_y;
4161 info = _clutter_actor_get_transform_info (self);
4163 g_object_freeze_notify (obj);
4165 clutter_anchor_coord_get_units (self, &info->anchor,
4170 if (info->anchor.is_fractional)
4171 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4175 case CLUTTER_X_AXIS:
4176 clutter_anchor_coord_set_units (&info->anchor,
4180 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4183 case CLUTTER_Y_AXIS:
4184 clutter_anchor_coord_set_units (&info->anchor,
4188 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4192 g_assert_not_reached ();
4195 self->priv->transform_valid = FALSE;
4197 clutter_actor_queue_redraw (self);
4199 g_object_thaw_notify (obj);
4203 clutter_actor_set_property (GObject *object,
4205 const GValue *value,
4208 ClutterActor *actor = CLUTTER_ACTOR (object);
4209 ClutterActorPrivate *priv = actor->priv;
4214 clutter_actor_set_x (actor, g_value_get_float (value));
4218 clutter_actor_set_y (actor, g_value_get_float (value));
4222 clutter_actor_set_width (actor, g_value_get_float (value));
4226 clutter_actor_set_height (actor, g_value_get_float (value));
4230 clutter_actor_set_x (actor, g_value_get_float (value));
4234 clutter_actor_set_y (actor, g_value_get_float (value));
4237 case PROP_FIXED_POSITION_SET:
4238 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4241 case PROP_MIN_WIDTH:
4242 clutter_actor_set_min_width (actor, g_value_get_float (value));
4245 case PROP_MIN_HEIGHT:
4246 clutter_actor_set_min_height (actor, g_value_get_float (value));
4249 case PROP_NATURAL_WIDTH:
4250 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4253 case PROP_NATURAL_HEIGHT:
4254 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4257 case PROP_MIN_WIDTH_SET:
4258 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4261 case PROP_MIN_HEIGHT_SET:
4262 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4265 case PROP_NATURAL_WIDTH_SET:
4266 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4269 case PROP_NATURAL_HEIGHT_SET:
4270 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4273 case PROP_REQUEST_MODE:
4274 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4278 clutter_actor_set_depth (actor, g_value_get_float (value));
4282 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4285 case PROP_OFFSCREEN_REDIRECT:
4286 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4290 clutter_actor_set_name (actor, g_value_get_string (value));
4294 if (g_value_get_boolean (value) == TRUE)
4295 clutter_actor_show (actor);
4297 clutter_actor_hide (actor);
4301 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4302 g_value_get_double (value));
4306 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4307 g_value_get_double (value));
4310 case PROP_SCALE_CENTER_X:
4311 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4312 g_value_get_float (value));
4315 case PROP_SCALE_CENTER_Y:
4316 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4317 g_value_get_float (value));
4320 case PROP_SCALE_GRAVITY:
4322 const ClutterTransformInfo *info;
4323 ClutterGravity gravity;
4325 info = _clutter_actor_get_transform_info_or_defaults (actor);
4326 gravity = g_value_get_enum (value);
4328 clutter_actor_set_scale_with_gravity (actor,
4337 const ClutterGeometry *geom = g_value_get_boxed (value);
4339 clutter_actor_set_clip (actor,
4341 geom->width, geom->height);
4345 case PROP_CLIP_TO_ALLOCATION:
4346 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4350 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4353 case PROP_ROTATION_ANGLE_X:
4354 clutter_actor_set_rotation_angle (actor,
4356 g_value_get_double (value));
4359 case PROP_ROTATION_ANGLE_Y:
4360 clutter_actor_set_rotation_angle (actor,
4362 g_value_get_double (value));
4365 case PROP_ROTATION_ANGLE_Z:
4366 clutter_actor_set_rotation_angle (actor,
4368 g_value_get_double (value));
4371 case PROP_ROTATION_CENTER_X:
4372 clutter_actor_set_rotation_center_internal (actor,
4374 g_value_get_boxed (value));
4377 case PROP_ROTATION_CENTER_Y:
4378 clutter_actor_set_rotation_center_internal (actor,
4380 g_value_get_boxed (value));
4383 case PROP_ROTATION_CENTER_Z:
4384 clutter_actor_set_rotation_center_internal (actor,
4386 g_value_get_boxed (value));
4389 case PROP_ROTATION_CENTER_Z_GRAVITY:
4391 const ClutterTransformInfo *info;
4393 info = _clutter_actor_get_transform_info_or_defaults (actor);
4394 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4395 g_value_get_enum (value));
4400 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4401 g_value_get_float (value));
4405 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4406 g_value_get_float (value));
4409 case PROP_ANCHOR_GRAVITY:
4410 clutter_actor_set_anchor_point_from_gravity (actor,
4411 g_value_get_enum (value));
4414 case PROP_SHOW_ON_SET_PARENT:
4415 priv->show_on_set_parent = g_value_get_boolean (value);
4418 case PROP_TEXT_DIRECTION:
4419 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4423 clutter_actor_add_action (actor, g_value_get_object (value));
4426 case PROP_CONSTRAINTS:
4427 clutter_actor_add_constraint (actor, g_value_get_object (value));
4431 clutter_actor_add_effect (actor, g_value_get_object (value));
4434 case PROP_LAYOUT_MANAGER:
4435 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4439 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4443 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4446 case PROP_MARGIN_TOP:
4447 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4450 case PROP_MARGIN_BOTTOM:
4451 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4454 case PROP_MARGIN_LEFT:
4455 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4458 case PROP_MARGIN_RIGHT:
4459 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4462 case PROP_BACKGROUND_COLOR:
4463 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4467 clutter_actor_set_content (actor, g_value_get_object (value));
4470 case PROP_CONTENT_GRAVITY:
4471 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4475 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4481 clutter_actor_get_property (GObject *object,
4486 ClutterActor *actor = CLUTTER_ACTOR (object);
4487 ClutterActorPrivate *priv = actor->priv;
4492 g_value_set_float (value, clutter_actor_get_x (actor));
4496 g_value_set_float (value, clutter_actor_get_y (actor));
4500 g_value_set_float (value, clutter_actor_get_width (actor));
4504 g_value_set_float (value, clutter_actor_get_height (actor));
4509 const ClutterLayoutInfo *info;
4511 info = _clutter_actor_get_layout_info_or_defaults (actor);
4512 g_value_set_float (value, info->fixed_x);
4518 const ClutterLayoutInfo *info;
4520 info = _clutter_actor_get_layout_info_or_defaults (actor);
4521 g_value_set_float (value, info->fixed_y);
4525 case PROP_FIXED_POSITION_SET:
4526 g_value_set_boolean (value, priv->position_set);
4529 case PROP_MIN_WIDTH:
4531 const ClutterLayoutInfo *info;
4533 info = _clutter_actor_get_layout_info_or_defaults (actor);
4534 g_value_set_float (value, info->min_width);
4538 case PROP_MIN_HEIGHT:
4540 const ClutterLayoutInfo *info;
4542 info = _clutter_actor_get_layout_info_or_defaults (actor);
4543 g_value_set_float (value, info->min_height);
4547 case PROP_NATURAL_WIDTH:
4549 const ClutterLayoutInfo *info;
4551 info = _clutter_actor_get_layout_info_or_defaults (actor);
4552 g_value_set_float (value, info->natural_width);
4556 case PROP_NATURAL_HEIGHT:
4558 const ClutterLayoutInfo *info;
4560 info = _clutter_actor_get_layout_info_or_defaults (actor);
4561 g_value_set_float (value, info->natural_height);
4565 case PROP_MIN_WIDTH_SET:
4566 g_value_set_boolean (value, priv->min_width_set);
4569 case PROP_MIN_HEIGHT_SET:
4570 g_value_set_boolean (value, priv->min_height_set);
4573 case PROP_NATURAL_WIDTH_SET:
4574 g_value_set_boolean (value, priv->natural_width_set);
4577 case PROP_NATURAL_HEIGHT_SET:
4578 g_value_set_boolean (value, priv->natural_height_set);
4581 case PROP_REQUEST_MODE:
4582 g_value_set_enum (value, priv->request_mode);
4585 case PROP_ALLOCATION:
4586 g_value_set_boxed (value, &priv->allocation);
4590 g_value_set_float (value, clutter_actor_get_depth (actor));
4594 g_value_set_uint (value, priv->opacity);
4597 case PROP_OFFSCREEN_REDIRECT:
4598 g_value_set_enum (value, priv->offscreen_redirect);
4602 g_value_set_string (value, priv->name);
4606 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4610 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4614 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4618 g_value_set_boolean (value, priv->has_clip);
4623 ClutterGeometry clip;
4625 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4626 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4627 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4628 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4630 g_value_set_boxed (value, &clip);
4634 case PROP_CLIP_TO_ALLOCATION:
4635 g_value_set_boolean (value, priv->clip_to_allocation);
4640 const ClutterTransformInfo *info;
4642 info = _clutter_actor_get_transform_info_or_defaults (actor);
4643 g_value_set_double (value, info->scale_x);
4649 const ClutterTransformInfo *info;
4651 info = _clutter_actor_get_transform_info_or_defaults (actor);
4652 g_value_set_double (value, info->scale_y);
4656 case PROP_SCALE_CENTER_X:
4660 clutter_actor_get_scale_center (actor, ¢er, NULL);
4662 g_value_set_float (value, center);
4666 case PROP_SCALE_CENTER_Y:
4670 clutter_actor_get_scale_center (actor, NULL, ¢er);
4672 g_value_set_float (value, center);
4676 case PROP_SCALE_GRAVITY:
4677 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4681 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4684 case PROP_ROTATION_ANGLE_X:
4686 const ClutterTransformInfo *info;
4688 info = _clutter_actor_get_transform_info_or_defaults (actor);
4689 g_value_set_double (value, info->rx_angle);
4693 case PROP_ROTATION_ANGLE_Y:
4695 const ClutterTransformInfo *info;
4697 info = _clutter_actor_get_transform_info_or_defaults (actor);
4698 g_value_set_double (value, info->ry_angle);
4702 case PROP_ROTATION_ANGLE_Z:
4704 const ClutterTransformInfo *info;
4706 info = _clutter_actor_get_transform_info_or_defaults (actor);
4707 g_value_set_double (value, info->rz_angle);
4711 case PROP_ROTATION_CENTER_X:
4713 ClutterVertex center;
4715 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4720 g_value_set_boxed (value, ¢er);
4724 case PROP_ROTATION_CENTER_Y:
4726 ClutterVertex center;
4728 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4733 g_value_set_boxed (value, ¢er);
4737 case PROP_ROTATION_CENTER_Z:
4739 ClutterVertex center;
4741 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4746 g_value_set_boxed (value, ¢er);
4750 case PROP_ROTATION_CENTER_Z_GRAVITY:
4751 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4756 const ClutterTransformInfo *info;
4759 info = _clutter_actor_get_transform_info_or_defaults (actor);
4760 clutter_anchor_coord_get_units (actor, &info->anchor,
4764 g_value_set_float (value, anchor_x);
4770 const ClutterTransformInfo *info;
4773 info = _clutter_actor_get_transform_info_or_defaults (actor);
4774 clutter_anchor_coord_get_units (actor, &info->anchor,
4778 g_value_set_float (value, anchor_y);
4782 case PROP_ANCHOR_GRAVITY:
4783 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4786 case PROP_SHOW_ON_SET_PARENT:
4787 g_value_set_boolean (value, priv->show_on_set_parent);
4790 case PROP_TEXT_DIRECTION:
4791 g_value_set_enum (value, priv->text_direction);
4794 case PROP_HAS_POINTER:
4795 g_value_set_boolean (value, priv->has_pointer);
4798 case PROP_LAYOUT_MANAGER:
4799 g_value_set_object (value, priv->layout_manager);
4804 const ClutterLayoutInfo *info;
4806 info = _clutter_actor_get_layout_info_or_defaults (actor);
4807 g_value_set_enum (value, info->x_align);
4813 const ClutterLayoutInfo *info;
4815 info = _clutter_actor_get_layout_info_or_defaults (actor);
4816 g_value_set_enum (value, info->y_align);
4820 case PROP_MARGIN_TOP:
4822 const ClutterLayoutInfo *info;
4824 info = _clutter_actor_get_layout_info_or_defaults (actor);
4825 g_value_set_float (value, info->margin.top);
4829 case PROP_MARGIN_BOTTOM:
4831 const ClutterLayoutInfo *info;
4833 info = _clutter_actor_get_layout_info_or_defaults (actor);
4834 g_value_set_float (value, info->margin.bottom);
4838 case PROP_MARGIN_LEFT:
4840 const ClutterLayoutInfo *info;
4842 info = _clutter_actor_get_layout_info_or_defaults (actor);
4843 g_value_set_float (value, info->margin.left);
4847 case PROP_MARGIN_RIGHT:
4849 const ClutterLayoutInfo *info;
4851 info = _clutter_actor_get_layout_info_or_defaults (actor);
4852 g_value_set_float (value, info->margin.right);
4856 case PROP_BACKGROUND_COLOR_SET:
4857 g_value_set_boolean (value, priv->bg_color_set);
4860 case PROP_BACKGROUND_COLOR:
4861 g_value_set_boxed (value, &priv->bg_color);
4864 case PROP_FIRST_CHILD:
4865 g_value_set_object (value, priv->first_child);
4868 case PROP_LAST_CHILD:
4869 g_value_set_object (value, priv->last_child);
4873 g_value_set_object (value, priv->content);
4876 case PROP_CONTENT_GRAVITY:
4877 g_value_set_enum (value, priv->content_gravity);
4880 case PROP_CONTENT_BOX:
4882 ClutterActorBox box = { 0, };
4884 clutter_actor_get_content_box (actor, &box);
4885 g_value_set_boxed (value, &box);
4890 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4896 clutter_actor_dispose (GObject *object)
4898 ClutterActor *self = CLUTTER_ACTOR (object);
4899 ClutterActorPrivate *priv = self->priv;
4901 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4903 g_type_name (G_OBJECT_TYPE (self)),
4906 g_signal_emit (self, actor_signals[DESTROY], 0);
4908 /* avoid recursing when called from clutter_actor_destroy() */
4909 if (priv->parent != NULL)
4911 ClutterActor *parent = priv->parent;
4913 /* go through the Container implementation unless this
4914 * is an internal child and has been marked as such.
4916 * removing the actor from its parent will reset the
4917 * realized and mapped states.
4919 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4920 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4922 clutter_actor_remove_child_internal (parent, self,
4923 REMOVE_CHILD_LEGACY_FLAGS);
4926 /* parent must be gone at this point */
4927 g_assert (priv->parent == NULL);
4929 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4931 /* can't be mapped or realized with no parent */
4932 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4933 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4936 g_clear_object (&priv->pango_context);
4937 g_clear_object (&priv->actions);
4938 g_clear_object (&priv->constraints);
4939 g_clear_object (&priv->effects);
4940 g_clear_object (&priv->flatten_effect);
4942 if (priv->layout_manager != NULL)
4944 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4945 g_clear_object (&priv->layout_manager);
4948 if (priv->content != NULL)
4950 _clutter_content_detached (priv->content, self);
4951 g_clear_object (&priv->content);
4954 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4958 clutter_actor_finalize (GObject *object)
4960 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4962 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4963 priv->name != NULL ? priv->name : "<none>",
4965 g_type_name (G_OBJECT_TYPE (object)));
4967 _clutter_context_release_id (priv->id);
4969 g_free (priv->name);
4971 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4976 * clutter_actor_get_accessible:
4977 * @self: a #ClutterActor
4979 * Returns the accessible object that describes the actor to an
4980 * assistive technology.
4982 * If no class-specific #AtkObject implementation is available for the
4983 * actor instance in question, it will inherit an #AtkObject
4984 * implementation from the first ancestor class for which such an
4985 * implementation is defined.
4987 * The documentation of the <ulink
4988 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4989 * library contains more information about accessible objects and
4992 * Returns: (transfer none): the #AtkObject associated with @actor
4995 clutter_actor_get_accessible (ClutterActor *self)
4997 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4999 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5003 clutter_actor_real_get_accessible (ClutterActor *actor)
5005 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5009 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5011 AtkObject *accessible;
5013 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5014 if (accessible != NULL)
5015 g_object_ref (accessible);
5021 atk_implementor_iface_init (AtkImplementorIface *iface)
5023 iface->ref_accessible = _clutter_actor_ref_accessible;
5027 clutter_actor_update_default_paint_volume (ClutterActor *self,
5028 ClutterPaintVolume *volume)
5030 ClutterActorPrivate *priv = self->priv;
5031 gboolean res = FALSE;
5033 /* we start from the allocation */
5034 clutter_paint_volume_set_width (volume,
5035 priv->allocation.x2 - priv->allocation.x1);
5036 clutter_paint_volume_set_height (volume,
5037 priv->allocation.y2 - priv->allocation.y1);
5039 /* if the actor has a clip set then we have a pretty definite
5040 * size for the paint volume: the actor cannot possibly paint
5041 * outside the clip region.
5043 if (priv->clip_to_allocation)
5045 /* the allocation has already been set, so we just flip the
5052 ClutterActor *child;
5054 if (priv->has_clip &&
5055 priv->clip.width >= 0 &&
5056 priv->clip.height >= 0)
5058 ClutterVertex origin;
5060 origin.x = priv->clip.x;
5061 origin.y = priv->clip.y;
5064 clutter_paint_volume_set_origin (volume, &origin);
5065 clutter_paint_volume_set_width (volume, priv->clip.width);
5066 clutter_paint_volume_set_height (volume, priv->clip.height);
5071 /* if we don't have children we just bail out here... */
5072 if (priv->n_children == 0)
5075 /* ...but if we have children then we ask for their paint volume in
5076 * our coordinates. if any of our children replies that it doesn't
5077 * have a paint volume, we bail out
5079 for (child = priv->first_child;
5081 child = child->priv->next_sibling)
5083 const ClutterPaintVolume *child_volume;
5085 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5086 if (child_volume == NULL)
5092 clutter_paint_volume_union (volume, child_volume);
5102 clutter_actor_real_get_paint_volume (ClutterActor *self,
5103 ClutterPaintVolume *volume)
5105 ClutterActorClass *klass;
5108 klass = CLUTTER_ACTOR_GET_CLASS (self);
5110 /* XXX - this thoroughly sucks, but we don't want to penalize users
5111 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5112 * redraw. This should go away in 2.0.
5114 if (klass->paint == clutter_actor_real_paint &&
5115 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5121 /* this is the default return value: we cannot know if a class
5122 * is going to paint outside its allocation, so we take the
5123 * conservative approach.
5128 if (clutter_actor_update_default_paint_volume (self, volume))
5135 * clutter_actor_get_default_paint_volume:
5136 * @self: a #ClutterActor
5138 * Retrieves the default paint volume for @self.
5140 * This function provides the same #ClutterPaintVolume that would be
5141 * computed by the default implementation inside #ClutterActor of the
5142 * #ClutterActorClass.get_paint_volume() virtual function.
5144 * This function should only be used by #ClutterActor subclasses that
5145 * cannot chain up to the parent implementation when computing their
5148 * Return value: (transfer none): a pointer to the default
5149 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5150 * the actor could not compute a valid paint volume. The returned value
5151 * is not guaranteed to be stable across multiple frames, so if you
5152 * want to retain it, you will need to copy it using
5153 * clutter_paint_volume_copy().
5157 const ClutterPaintVolume *
5158 clutter_actor_get_default_paint_volume (ClutterActor *self)
5160 ClutterPaintVolume volume;
5161 ClutterPaintVolume *res;
5163 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5166 _clutter_paint_volume_init_static (&volume, self);
5167 if (clutter_actor_update_default_paint_volume (self, &volume))
5169 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5173 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5174 _clutter_paint_volume_copy_static (&volume, res);
5178 clutter_paint_volume_free (&volume);
5184 clutter_actor_real_has_overlaps (ClutterActor *self)
5186 /* By default we'll assume that all actors need an offscreen redirect to get
5187 * the correct opacity. Actors such as ClutterTexture that would never need
5188 * an offscreen redirect can override this to return FALSE. */
5193 clutter_actor_real_destroy (ClutterActor *actor)
5195 ClutterActorIter iter;
5197 clutter_actor_iter_init (&iter, actor);
5198 while (clutter_actor_iter_next (&iter, NULL))
5199 clutter_actor_iter_destroy (&iter);
5203 clutter_actor_constructor (GType gtype,
5205 GObjectConstructParam *props)
5207 GObjectClass *gobject_class;
5211 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5212 retval = gobject_class->constructor (gtype, n_props, props);
5213 self = CLUTTER_ACTOR (retval);
5215 if (self->priv->layout_manager == NULL)
5217 ClutterLayoutManager *default_layout;
5219 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5221 default_layout = clutter_fixed_layout_new ();
5222 clutter_actor_set_layout_manager (self, default_layout);
5229 clutter_actor_class_init (ClutterActorClass *klass)
5231 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5233 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5234 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5235 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5236 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5238 object_class->constructor = clutter_actor_constructor;
5239 object_class->set_property = clutter_actor_set_property;
5240 object_class->get_property = clutter_actor_get_property;
5241 object_class->dispose = clutter_actor_dispose;
5242 object_class->finalize = clutter_actor_finalize;
5244 klass->show = clutter_actor_real_show;
5245 klass->show_all = clutter_actor_show;
5246 klass->hide = clutter_actor_real_hide;
5247 klass->hide_all = clutter_actor_hide;
5248 klass->map = clutter_actor_real_map;
5249 klass->unmap = clutter_actor_real_unmap;
5250 klass->unrealize = clutter_actor_real_unrealize;
5251 klass->pick = clutter_actor_real_pick;
5252 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5253 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5254 klass->allocate = clutter_actor_real_allocate;
5255 klass->queue_redraw = clutter_actor_real_queue_redraw;
5256 klass->queue_relayout = clutter_actor_real_queue_relayout;
5257 klass->apply_transform = clutter_actor_real_apply_transform;
5258 klass->get_accessible = clutter_actor_real_get_accessible;
5259 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5260 klass->has_overlaps = clutter_actor_real_has_overlaps;
5261 klass->paint = clutter_actor_real_paint;
5262 klass->destroy = clutter_actor_real_destroy;
5264 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5269 * X coordinate of the actor in pixels. If written, forces a fixed
5270 * position for the actor. If read, returns the fixed position if any,
5271 * otherwise the allocation if available, otherwise 0.
5273 * The #ClutterActor:x property is animatable.
5276 g_param_spec_float ("x",
5278 P_("X coordinate of the actor"),
5279 -G_MAXFLOAT, G_MAXFLOAT,
5282 G_PARAM_STATIC_STRINGS |
5283 CLUTTER_PARAM_ANIMATABLE);
5288 * Y coordinate of the actor in pixels. If written, forces a fixed
5289 * position for the actor. If read, returns the fixed position if
5290 * any, otherwise the allocation if available, otherwise 0.
5292 * The #ClutterActor:y property is animatable.
5295 g_param_spec_float ("y",
5297 P_("Y coordinate of the actor"),
5298 -G_MAXFLOAT, G_MAXFLOAT,
5301 G_PARAM_STATIC_STRINGS |
5302 CLUTTER_PARAM_ANIMATABLE);
5305 * ClutterActor:width:
5307 * Width of the actor (in pixels). If written, forces the minimum and
5308 * natural size request of the actor to the given width. If read, returns
5309 * the allocated width if available, otherwise the width request.
5311 * The #ClutterActor:width property is animatable.
5313 obj_props[PROP_WIDTH] =
5314 g_param_spec_float ("width",
5316 P_("Width of the actor"),
5320 G_PARAM_STATIC_STRINGS |
5321 CLUTTER_PARAM_ANIMATABLE);
5324 * ClutterActor:height:
5326 * Height of the actor (in pixels). If written, forces the minimum and
5327 * natural size request of the actor to the given height. If read, returns
5328 * the allocated height if available, otherwise the height request.
5330 * The #ClutterActor:height property is animatable.
5332 obj_props[PROP_HEIGHT] =
5333 g_param_spec_float ("height",
5335 P_("Height of the actor"),
5339 G_PARAM_STATIC_STRINGS |
5340 CLUTTER_PARAM_ANIMATABLE);
5343 * ClutterActor:fixed-x:
5345 * The fixed X position of the actor in pixels.
5347 * Writing this property sets #ClutterActor:fixed-position-set
5348 * property as well, as a side effect
5352 obj_props[PROP_FIXED_X] =
5353 g_param_spec_float ("fixed-x",
5355 P_("Forced X position of the actor"),
5356 -G_MAXFLOAT, G_MAXFLOAT,
5358 CLUTTER_PARAM_READWRITE);
5361 * ClutterActor:fixed-y:
5363 * The fixed Y position of the actor in pixels.
5365 * Writing this property sets the #ClutterActor:fixed-position-set
5366 * property as well, as a side effect
5370 obj_props[PROP_FIXED_Y] =
5371 g_param_spec_float ("fixed-y",
5373 P_("Forced Y position of the actor"),
5374 -G_MAXFLOAT, G_MAXFLOAT,
5376 CLUTTER_PARAM_READWRITE);
5379 * ClutterActor:fixed-position-set:
5381 * This flag controls whether the #ClutterActor:fixed-x and
5382 * #ClutterActor:fixed-y properties are used
5386 obj_props[PROP_FIXED_POSITION_SET] =
5387 g_param_spec_boolean ("fixed-position-set",
5388 P_("Fixed position set"),
5389 P_("Whether to use fixed positioning for the actor"),
5391 CLUTTER_PARAM_READWRITE);
5394 * ClutterActor:min-width:
5396 * A forced minimum width request for the actor, in pixels
5398 * Writing this property sets the #ClutterActor:min-width-set property
5399 * as well, as a side effect.
5401 *This property overrides the usual width request of the actor.
5405 obj_props[PROP_MIN_WIDTH] =
5406 g_param_spec_float ("min-width",
5408 P_("Forced minimum width request for the actor"),
5411 CLUTTER_PARAM_READWRITE);
5414 * ClutterActor:min-height:
5416 * A forced minimum height request for the actor, in pixels
5418 * Writing this property sets the #ClutterActor:min-height-set property
5419 * as well, as a side effect. This property overrides the usual height
5420 * request of the actor.
5424 obj_props[PROP_MIN_HEIGHT] =
5425 g_param_spec_float ("min-height",
5427 P_("Forced minimum height request for the actor"),
5430 CLUTTER_PARAM_READWRITE);
5433 * ClutterActor:natural-width:
5435 * A forced natural width request for the actor, in pixels
5437 * Writing this property sets the #ClutterActor:natural-width-set
5438 * property as well, as a side effect. This property overrides the
5439 * usual width request of the actor
5443 obj_props[PROP_NATURAL_WIDTH] =
5444 g_param_spec_float ("natural-width",
5445 P_("Natural Width"),
5446 P_("Forced natural width request for the actor"),
5449 CLUTTER_PARAM_READWRITE);
5452 * ClutterActor:natural-height:
5454 * A forced natural height request for the actor, in pixels
5456 * Writing this property sets the #ClutterActor:natural-height-set
5457 * property as well, as a side effect. This property overrides the
5458 * usual height request of the actor
5462 obj_props[PROP_NATURAL_HEIGHT] =
5463 g_param_spec_float ("natural-height",
5464 P_("Natural Height"),
5465 P_("Forced natural height request for the actor"),
5468 CLUTTER_PARAM_READWRITE);
5471 * ClutterActor:min-width-set:
5473 * This flag controls whether the #ClutterActor:min-width property
5478 obj_props[PROP_MIN_WIDTH_SET] =
5479 g_param_spec_boolean ("min-width-set",
5480 P_("Minimum width set"),
5481 P_("Whether to use the min-width property"),
5483 CLUTTER_PARAM_READWRITE);
5486 * ClutterActor:min-height-set:
5488 * This flag controls whether the #ClutterActor:min-height property
5493 obj_props[PROP_MIN_HEIGHT_SET] =
5494 g_param_spec_boolean ("min-height-set",
5495 P_("Minimum height set"),
5496 P_("Whether to use the min-height property"),
5498 CLUTTER_PARAM_READWRITE);
5501 * ClutterActor:natural-width-set:
5503 * This flag controls whether the #ClutterActor:natural-width property
5508 obj_props[PROP_NATURAL_WIDTH_SET] =
5509 g_param_spec_boolean ("natural-width-set",
5510 P_("Natural width set"),
5511 P_("Whether to use the natural-width property"),
5513 CLUTTER_PARAM_READWRITE);
5516 * ClutterActor:natural-height-set:
5518 * This flag controls whether the #ClutterActor:natural-height property
5523 obj_props[PROP_NATURAL_HEIGHT_SET] =
5524 g_param_spec_boolean ("natural-height-set",
5525 P_("Natural height set"),
5526 P_("Whether to use the natural-height property"),
5528 CLUTTER_PARAM_READWRITE);
5531 * ClutterActor:allocation:
5533 * The allocation for the actor, in pixels
5535 * This is property is read-only, but you might monitor it to know when an
5536 * actor moves or resizes
5540 obj_props[PROP_ALLOCATION] =
5541 g_param_spec_boxed ("allocation",
5543 P_("The actor's allocation"),
5544 CLUTTER_TYPE_ACTOR_BOX,
5545 CLUTTER_PARAM_READABLE);
5548 * ClutterActor:request-mode:
5550 * Request mode for the #ClutterActor. The request mode determines the
5551 * type of geometry management used by the actor, either height for width
5552 * (the default) or width for height.
5554 * For actors implementing height for width, the parent container should get
5555 * the preferred width first, and then the preferred height for that width.
5557 * For actors implementing width for height, the parent container should get
5558 * the preferred height first, and then the preferred width for that height.
5563 * ClutterRequestMode mode;
5564 * gfloat natural_width, min_width;
5565 * gfloat natural_height, min_height;
5567 * mode = clutter_actor_get_request_mode (child);
5568 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5570 * clutter_actor_get_preferred_width (child, -1,
5572 * &natural_width);
5573 * clutter_actor_get_preferred_height (child, natural_width,
5575 * &natural_height);
5579 * clutter_actor_get_preferred_height (child, -1,
5581 * &natural_height);
5582 * clutter_actor_get_preferred_width (child, natural_height,
5584 * &natural_width);
5588 * will retrieve the minimum and natural width and height depending on the
5589 * preferred request mode of the #ClutterActor "child".
5591 * The clutter_actor_get_preferred_size() function will implement this
5596 obj_props[PROP_REQUEST_MODE] =
5597 g_param_spec_enum ("request-mode",
5599 P_("The actor's request mode"),
5600 CLUTTER_TYPE_REQUEST_MODE,
5601 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5602 CLUTTER_PARAM_READWRITE);
5605 * ClutterActor:depth:
5607 * The position of the actor on the Z axis.
5609 * The #ClutterActor:depth property is relative to the parent's
5612 * The #ClutterActor:depth property is animatable.
5616 obj_props[PROP_DEPTH] =
5617 g_param_spec_float ("depth",
5619 P_("Position on the Z axis"),
5620 -G_MAXFLOAT, G_MAXFLOAT,
5623 G_PARAM_STATIC_STRINGS |
5624 CLUTTER_PARAM_ANIMATABLE);
5627 * ClutterActor:opacity:
5629 * Opacity of an actor, between 0 (fully transparent) and
5630 * 255 (fully opaque)
5632 * The #ClutterActor:opacity property is animatable.
5634 obj_props[PROP_OPACITY] =
5635 g_param_spec_uint ("opacity",
5637 P_("Opacity of an actor"),
5641 G_PARAM_STATIC_STRINGS |
5642 CLUTTER_PARAM_ANIMATABLE);
5645 * ClutterActor:offscreen-redirect:
5647 * Determines the conditions in which the actor will be redirected
5648 * to an offscreen framebuffer while being painted. For example this
5649 * can be used to cache an actor in a framebuffer or for improved
5650 * handling of transparent actors. See
5651 * clutter_actor_set_offscreen_redirect() for details.
5655 obj_props[PROP_OFFSCREEN_REDIRECT] =
5656 g_param_spec_flags ("offscreen-redirect",
5657 P_("Offscreen redirect"),
5658 P_("Flags controlling when to flatten the actor into a single image"),
5659 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5661 CLUTTER_PARAM_READWRITE);
5664 * ClutterActor:visible:
5666 * Whether the actor is set to be visible or not
5668 * See also #ClutterActor:mapped
5670 obj_props[PROP_VISIBLE] =
5671 g_param_spec_boolean ("visible",
5673 P_("Whether the actor is visible or not"),
5675 CLUTTER_PARAM_READWRITE);
5678 * ClutterActor:mapped:
5680 * Whether the actor is mapped (will be painted when the stage
5681 * to which it belongs is mapped)
5685 obj_props[PROP_MAPPED] =
5686 g_param_spec_boolean ("mapped",
5688 P_("Whether the actor will be painted"),
5690 CLUTTER_PARAM_READABLE);
5693 * ClutterActor:realized:
5695 * Whether the actor has been realized
5699 obj_props[PROP_REALIZED] =
5700 g_param_spec_boolean ("realized",
5702 P_("Whether the actor has been realized"),
5704 CLUTTER_PARAM_READABLE);
5707 * ClutterActor:reactive:
5709 * Whether the actor is reactive to events or not
5711 * Only reactive actors will emit event-related signals
5715 obj_props[PROP_REACTIVE] =
5716 g_param_spec_boolean ("reactive",
5718 P_("Whether the actor is reactive to events"),
5720 CLUTTER_PARAM_READWRITE);
5723 * ClutterActor:has-clip:
5725 * Whether the actor has the #ClutterActor:clip property set or not
5727 obj_props[PROP_HAS_CLIP] =
5728 g_param_spec_boolean ("has-clip",
5730 P_("Whether the actor has a clip set"),
5732 CLUTTER_PARAM_READABLE);
5735 * ClutterActor:clip:
5737 * The clip region for the actor, in actor-relative coordinates
5739 * Every part of the actor outside the clip region will not be
5742 obj_props[PROP_CLIP] =
5743 g_param_spec_boxed ("clip",
5745 P_("The clip region for the actor"),
5746 CLUTTER_TYPE_GEOMETRY,
5747 CLUTTER_PARAM_READWRITE);
5750 * ClutterActor:name:
5752 * The name of the actor
5756 obj_props[PROP_NAME] =
5757 g_param_spec_string ("name",
5759 P_("Name of the actor"),
5761 CLUTTER_PARAM_READWRITE);
5764 * ClutterActor:scale-x:
5766 * The horizontal scale of the actor.
5768 * The #ClutterActor:scale-x property is animatable.
5772 obj_props[PROP_SCALE_X] =
5773 g_param_spec_double ("scale-x",
5775 P_("Scale factor on the X axis"),
5779 G_PARAM_STATIC_STRINGS |
5780 CLUTTER_PARAM_ANIMATABLE);
5783 * ClutterActor:scale-y:
5785 * The vertical scale of the actor.
5787 * The #ClutterActor:scale-y property is animatable.
5791 obj_props[PROP_SCALE_Y] =
5792 g_param_spec_double ("scale-y",
5794 P_("Scale factor on the Y axis"),
5798 G_PARAM_STATIC_STRINGS |
5799 CLUTTER_PARAM_ANIMATABLE);
5802 * ClutterActor:scale-center-x:
5804 * The horizontal center point for scaling
5808 obj_props[PROP_SCALE_CENTER_X] =
5809 g_param_spec_float ("scale-center-x",
5810 P_("Scale Center X"),
5811 P_("Horizontal scale center"),
5812 -G_MAXFLOAT, G_MAXFLOAT,
5814 CLUTTER_PARAM_READWRITE);
5817 * ClutterActor:scale-center-y:
5819 * The vertical center point for scaling
5823 obj_props[PROP_SCALE_CENTER_Y] =
5824 g_param_spec_float ("scale-center-y",
5825 P_("Scale Center Y"),
5826 P_("Vertical scale center"),
5827 -G_MAXFLOAT, G_MAXFLOAT,
5829 CLUTTER_PARAM_READWRITE);
5832 * ClutterActor:scale-gravity:
5834 * The center point for scaling expressed as a #ClutterGravity
5838 obj_props[PROP_SCALE_GRAVITY] =
5839 g_param_spec_enum ("scale-gravity",
5840 P_("Scale Gravity"),
5841 P_("The center of scaling"),
5842 CLUTTER_TYPE_GRAVITY,
5843 CLUTTER_GRAVITY_NONE,
5844 CLUTTER_PARAM_READWRITE);
5847 * ClutterActor:rotation-angle-x:
5849 * The rotation angle on the X axis.
5851 * The #ClutterActor:rotation-angle-x property is animatable.
5855 obj_props[PROP_ROTATION_ANGLE_X] =
5856 g_param_spec_double ("rotation-angle-x",
5857 P_("Rotation Angle X"),
5858 P_("The rotation angle on the X axis"),
5859 -G_MAXDOUBLE, G_MAXDOUBLE,
5862 G_PARAM_STATIC_STRINGS |
5863 CLUTTER_PARAM_ANIMATABLE);
5866 * ClutterActor:rotation-angle-y:
5868 * The rotation angle on the Y axis
5870 * The #ClutterActor:rotation-angle-y property is animatable.
5874 obj_props[PROP_ROTATION_ANGLE_Y] =
5875 g_param_spec_double ("rotation-angle-y",
5876 P_("Rotation Angle Y"),
5877 P_("The rotation angle on the Y axis"),
5878 -G_MAXDOUBLE, G_MAXDOUBLE,
5881 G_PARAM_STATIC_STRINGS |
5882 CLUTTER_PARAM_ANIMATABLE);
5885 * ClutterActor:rotation-angle-z:
5887 * The rotation angle on the Z axis
5889 * The #ClutterActor:rotation-angle-z property is animatable.
5893 obj_props[PROP_ROTATION_ANGLE_Z] =
5894 g_param_spec_double ("rotation-angle-z",
5895 P_("Rotation Angle Z"),
5896 P_("The rotation angle on the Z axis"),
5897 -G_MAXDOUBLE, G_MAXDOUBLE,
5900 G_PARAM_STATIC_STRINGS |
5901 CLUTTER_PARAM_ANIMATABLE);
5904 * ClutterActor:rotation-center-x:
5906 * The rotation center on the X axis.
5910 obj_props[PROP_ROTATION_CENTER_X] =
5911 g_param_spec_boxed ("rotation-center-x",
5912 P_("Rotation Center X"),
5913 P_("The rotation center on the X axis"),
5914 CLUTTER_TYPE_VERTEX,
5915 CLUTTER_PARAM_READWRITE);
5918 * ClutterActor:rotation-center-y:
5920 * The rotation center on the Y axis.
5924 obj_props[PROP_ROTATION_CENTER_Y] =
5925 g_param_spec_boxed ("rotation-center-y",
5926 P_("Rotation Center Y"),
5927 P_("The rotation center on the Y axis"),
5928 CLUTTER_TYPE_VERTEX,
5929 CLUTTER_PARAM_READWRITE);
5932 * ClutterActor:rotation-center-z:
5934 * The rotation center on the Z axis.
5938 obj_props[PROP_ROTATION_CENTER_Z] =
5939 g_param_spec_boxed ("rotation-center-z",
5940 P_("Rotation Center Z"),
5941 P_("The rotation center on the Z axis"),
5942 CLUTTER_TYPE_VERTEX,
5943 CLUTTER_PARAM_READWRITE);
5946 * ClutterActor:rotation-center-z-gravity:
5948 * The rotation center on the Z axis expressed as a #ClutterGravity.
5952 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5953 g_param_spec_enum ("rotation-center-z-gravity",
5954 P_("Rotation Center Z Gravity"),
5955 P_("Center point for rotation around the Z axis"),
5956 CLUTTER_TYPE_GRAVITY,
5957 CLUTTER_GRAVITY_NONE,
5958 CLUTTER_PARAM_READWRITE);
5961 * ClutterActor:anchor-x:
5963 * The X coordinate of an actor's anchor point, relative to
5964 * the actor coordinate space, in pixels
5968 obj_props[PROP_ANCHOR_X] =
5969 g_param_spec_float ("anchor-x",
5971 P_("X coordinate of the anchor point"),
5972 -G_MAXFLOAT, G_MAXFLOAT,
5974 CLUTTER_PARAM_READWRITE);
5977 * ClutterActor:anchor-y:
5979 * The Y coordinate of an actor's anchor point, relative to
5980 * the actor coordinate space, in pixels
5984 obj_props[PROP_ANCHOR_Y] =
5985 g_param_spec_float ("anchor-y",
5987 P_("Y coordinate of the anchor point"),
5988 -G_MAXFLOAT, G_MAXFLOAT,
5990 CLUTTER_PARAM_READWRITE);
5993 * ClutterActor:anchor-gravity:
5995 * The anchor point expressed as a #ClutterGravity
5999 obj_props[PROP_ANCHOR_GRAVITY] =
6000 g_param_spec_enum ("anchor-gravity",
6001 P_("Anchor Gravity"),
6002 P_("The anchor point as a ClutterGravity"),
6003 CLUTTER_TYPE_GRAVITY,
6004 CLUTTER_GRAVITY_NONE,
6005 CLUTTER_PARAM_READWRITE);
6008 * ClutterActor:show-on-set-parent:
6010 * If %TRUE, the actor is automatically shown when parented.
6012 * Calling clutter_actor_hide() on an actor which has not been
6013 * parented will set this property to %FALSE as a side effect.
6017 obj_props[PROP_SHOW_ON_SET_PARENT] =
6018 g_param_spec_boolean ("show-on-set-parent",
6019 P_("Show on set parent"),
6020 P_("Whether the actor is shown when parented"),
6022 CLUTTER_PARAM_READWRITE);
6025 * ClutterActor:clip-to-allocation:
6027 * Whether the clip region should track the allocated area
6030 * This property is ignored if a clip area has been explicitly
6031 * set using clutter_actor_set_clip().
6035 obj_props[PROP_CLIP_TO_ALLOCATION] =
6036 g_param_spec_boolean ("clip-to-allocation",
6037 P_("Clip to Allocation"),
6038 P_("Sets the clip region to track the actor's allocation"),
6040 CLUTTER_PARAM_READWRITE);
6043 * ClutterActor:text-direction:
6045 * The direction of the text inside a #ClutterActor.
6049 obj_props[PROP_TEXT_DIRECTION] =
6050 g_param_spec_enum ("text-direction",
6051 P_("Text Direction"),
6052 P_("Direction of the text"),
6053 CLUTTER_TYPE_TEXT_DIRECTION,
6054 CLUTTER_TEXT_DIRECTION_LTR,
6055 CLUTTER_PARAM_READWRITE);
6058 * ClutterActor:has-pointer:
6060 * Whether the actor contains the pointer of a #ClutterInputDevice
6065 obj_props[PROP_HAS_POINTER] =
6066 g_param_spec_boolean ("has-pointer",
6068 P_("Whether the actor contains the pointer of an input device"),
6070 CLUTTER_PARAM_READABLE);
6073 * ClutterActor:actions:
6075 * Adds a #ClutterAction to the actor
6079 obj_props[PROP_ACTIONS] =
6080 g_param_spec_object ("actions",
6082 P_("Adds an action to the actor"),
6083 CLUTTER_TYPE_ACTION,
6084 CLUTTER_PARAM_WRITABLE);
6087 * ClutterActor:constraints:
6089 * Adds a #ClutterConstraint to the actor
6093 obj_props[PROP_CONSTRAINTS] =
6094 g_param_spec_object ("constraints",
6096 P_("Adds a constraint to the actor"),
6097 CLUTTER_TYPE_CONSTRAINT,
6098 CLUTTER_PARAM_WRITABLE);
6101 * ClutterActor:effect:
6103 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6107 obj_props[PROP_EFFECT] =
6108 g_param_spec_object ("effect",
6110 P_("Add an effect to be applied on the actor"),
6111 CLUTTER_TYPE_EFFECT,
6112 CLUTTER_PARAM_WRITABLE);
6115 * ClutterActor:layout-manager:
6117 * A delegate object for controlling the layout of the children of
6122 obj_props[PROP_LAYOUT_MANAGER] =
6123 g_param_spec_object ("layout-manager",
6124 P_("Layout Manager"),
6125 P_("The object controlling the layout of an actor's children"),
6126 CLUTTER_TYPE_LAYOUT_MANAGER,
6127 CLUTTER_PARAM_READWRITE);
6131 * ClutterActor:x-align:
6133 * The alignment of an actor on the X axis, if the actor has been given
6134 * extra space for its allocation.
6138 obj_props[PROP_X_ALIGN] =
6139 g_param_spec_enum ("x-align",
6141 P_("The alignment of the actor on the X axis within its allocation"),
6142 CLUTTER_TYPE_ACTOR_ALIGN,
6143 CLUTTER_ACTOR_ALIGN_FILL,
6144 CLUTTER_PARAM_READWRITE);
6147 * ClutterActor:y-align:
6149 * The alignment of an actor on the Y axis, if the actor has been given
6150 * extra space for its allocation.
6154 obj_props[PROP_Y_ALIGN] =
6155 g_param_spec_enum ("y-align",
6157 P_("The alignment of the actor on the Y axis within its allocation"),
6158 CLUTTER_TYPE_ACTOR_ALIGN,
6159 CLUTTER_ACTOR_ALIGN_FILL,
6160 CLUTTER_PARAM_READWRITE);
6163 * ClutterActor:margin-top:
6165 * The margin (in pixels) from the top of the actor.
6167 * This property adds a margin to the actor's preferred size; the margin
6168 * will be automatically taken into account when allocating the actor.
6172 obj_props[PROP_MARGIN_TOP] =
6173 g_param_spec_float ("margin-top",
6175 P_("Extra space at the top"),
6178 CLUTTER_PARAM_READWRITE);
6181 * ClutterActor:margin-bottom:
6183 * The margin (in pixels) from the bottom of the actor.
6185 * This property adds a margin to the actor's preferred size; the margin
6186 * will be automatically taken into account when allocating the actor.
6190 obj_props[PROP_MARGIN_BOTTOM] =
6191 g_param_spec_float ("margin-bottom",
6192 P_("Margin Bottom"),
6193 P_("Extra space at the bottom"),
6196 CLUTTER_PARAM_READWRITE);
6199 * ClutterActor:margin-left:
6201 * The margin (in pixels) from the left of the actor.
6203 * This property adds a margin to the actor's preferred size; the margin
6204 * will be automatically taken into account when allocating the actor.
6208 obj_props[PROP_MARGIN_LEFT] =
6209 g_param_spec_float ("margin-left",
6211 P_("Extra space at the left"),
6214 CLUTTER_PARAM_READWRITE);
6217 * ClutterActor:margin-right:
6219 * The margin (in pixels) from the right of the actor.
6221 * This property adds a margin to the actor's preferred size; the margin
6222 * will be automatically taken into account when allocating the actor.
6226 obj_props[PROP_MARGIN_RIGHT] =
6227 g_param_spec_float ("margin-right",
6229 P_("Extra space at the right"),
6232 CLUTTER_PARAM_READWRITE);
6235 * ClutterActor:background-color-set:
6237 * Whether the #ClutterActor:background-color property has been set.
6241 obj_props[PROP_BACKGROUND_COLOR_SET] =
6242 g_param_spec_boolean ("background-color-set",
6243 P_("Background Color Set"),
6244 P_("Whether the background color is set"),
6246 CLUTTER_PARAM_READABLE);
6249 * ClutterActor:background-color:
6251 * Paints a solid fill of the actor's allocation using the specified
6254 * The #ClutterActor:background-color property is animatable.
6258 obj_props[PROP_BACKGROUND_COLOR] =
6259 clutter_param_spec_color ("background-color",
6260 P_("Background color"),
6261 P_("The actor's background color"),
6262 CLUTTER_COLOR_Transparent,
6264 G_PARAM_STATIC_STRINGS |
6265 CLUTTER_PARAM_ANIMATABLE);
6268 * ClutterActor:first-child:
6270 * The actor's first child.
6274 obj_props[PROP_FIRST_CHILD] =
6275 g_param_spec_object ("first-child",
6277 P_("The actor's first child"),
6279 CLUTTER_PARAM_READABLE);
6282 * ClutterActor:last-child:
6284 * The actor's last child.
6288 obj_props[PROP_LAST_CHILD] =
6289 g_param_spec_object ("last-child",
6291 P_("The actor's last child"),
6293 CLUTTER_PARAM_READABLE);
6296 * ClutterActor:content:
6298 * The #ClutterContent implementation that controls the content
6303 obj_props[PROP_CONTENT] =
6304 g_param_spec_object ("content",
6306 P_("Delegate object for painting the actor's content"),
6307 CLUTTER_TYPE_CONTENT,
6308 CLUTTER_PARAM_READWRITE);
6311 * ClutterActor:content-gravity:
6313 * The alignment that should be honoured by the #ClutterContent
6314 * set with the #ClutterActor:content property.
6316 * Changing the value of this property will change the bounding box of
6317 * the content; you can use the #ClutterActor:content-box property to
6318 * get the position and size of the content within the actor's
6321 * This property is meaningful only for #ClutterContent implementations
6322 * that have a preferred size, and if the preferred size is smaller than
6323 * the actor's allocation.
6327 obj_props[PROP_CONTENT_GRAVITY] =
6328 g_param_spec_enum ("content-gravity",
6329 P_("Content Gravity"),
6330 P_("Alignment of the actor's content"),
6331 CLUTTER_TYPE_CONTENT_GRAVITY,
6332 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6333 CLUTTER_PARAM_READWRITE);
6336 * ClutterActor:content-box:
6338 * The bounding box for the #ClutterContent used by the actor.
6340 * The value of this property is controlled by the #ClutterActor:allocation
6341 * and #ClutterActor:content-gravity properties of #ClutterActor.
6343 * The bounding box for the content is guaranteed to never exceed the
6344 * allocation's of the actor.
6348 obj_props[PROP_CONTENT_BOX] =
6349 g_param_spec_boxed ("content-box",
6351 P_("The bounding box of the actor's content"),
6352 CLUTTER_TYPE_ACTOR_BOX,
6353 CLUTTER_PARAM_READABLE);
6355 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6358 * ClutterActor::destroy:
6359 * @actor: the #ClutterActor which emitted the signal
6361 * The ::destroy signal notifies that all references held on the
6362 * actor which emitted it should be released.
6364 * The ::destroy signal should be used by all holders of a reference
6367 * This signal might result in the finalization of the #ClutterActor
6368 * if all references are released.
6370 * Composite actors and actors implementing the #ClutterContainer
6371 * interface should override the default implementation of the
6372 * class handler of this signal and call clutter_actor_destroy() on
6373 * their children. When overriding the default class handler, it is
6374 * required to chain up to the parent's implementation.
6378 actor_signals[DESTROY] =
6379 g_signal_new (I_("destroy"),
6380 G_TYPE_FROM_CLASS (object_class),
6381 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6382 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6384 _clutter_marshal_VOID__VOID,
6387 * ClutterActor::show:
6388 * @actor: the object which received the signal
6390 * The ::show signal is emitted when an actor is visible and
6391 * rendered on the stage.
6395 actor_signals[SHOW] =
6396 g_signal_new (I_("show"),
6397 G_TYPE_FROM_CLASS (object_class),
6399 G_STRUCT_OFFSET (ClutterActorClass, show),
6401 _clutter_marshal_VOID__VOID,
6404 * ClutterActor::hide:
6405 * @actor: the object which received the signal
6407 * The ::hide signal is emitted when an actor is no longer rendered
6412 actor_signals[HIDE] =
6413 g_signal_new (I_("hide"),
6414 G_TYPE_FROM_CLASS (object_class),
6416 G_STRUCT_OFFSET (ClutterActorClass, hide),
6418 _clutter_marshal_VOID__VOID,
6421 * ClutterActor::parent-set:
6422 * @actor: the object which received the signal
6423 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6425 * This signal is emitted when the parent of the actor changes.
6429 actor_signals[PARENT_SET] =
6430 g_signal_new (I_("parent-set"),
6431 G_TYPE_FROM_CLASS (object_class),
6433 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6435 _clutter_marshal_VOID__OBJECT,
6437 CLUTTER_TYPE_ACTOR);
6440 * ClutterActor::queue-redraw:
6441 * @actor: the actor we're bubbling the redraw request through
6442 * @origin: the actor which initiated the redraw request
6444 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6445 * is called on @origin.
6447 * The default implementation for #ClutterActor chains up to the
6448 * parent actor and queues a redraw on the parent, thus "bubbling"
6449 * the redraw queue up through the actor graph. The default
6450 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6451 * in a main loop idle handler.
6453 * Note that the @origin actor may be the stage, or a container; it
6454 * does not have to be a leaf node in the actor graph.
6456 * Toolkits embedding a #ClutterStage which require a redraw and
6457 * relayout cycle can stop the emission of this signal using the
6458 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6463 * on_redraw_complete (gpointer data)
6465 * ClutterStage *stage = data;
6467 * /* execute the Clutter drawing pipeline */
6468 * clutter_stage_ensure_redraw (stage);
6472 * on_stage_queue_redraw (ClutterStage *stage)
6474 * /* this prevents the default handler to run */
6475 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6477 * /* queue a redraw with the host toolkit and call
6478 * * a function when the redraw has been completed
6480 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6484 * <note><para>This signal is emitted before the Clutter paint
6485 * pipeline is executed. If you want to know when the pipeline has
6486 * been completed you should connect to the ::paint signal on the
6487 * Stage with g_signal_connect_after().</para></note>
6491 actor_signals[QUEUE_REDRAW] =
6492 g_signal_new (I_("queue-redraw"),
6493 G_TYPE_FROM_CLASS (object_class),
6496 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6498 _clutter_marshal_VOID__OBJECT,
6500 CLUTTER_TYPE_ACTOR);
6503 * ClutterActor::queue-relayout
6504 * @actor: the actor being queued for relayout
6506 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6507 * is called on an actor.
6509 * The default implementation for #ClutterActor chains up to the
6510 * parent actor and queues a relayout on the parent, thus "bubbling"
6511 * the relayout queue up through the actor graph.
6513 * The main purpose of this signal is to allow relayout to be propagated
6514 * properly in the procense of #ClutterClone actors. Applications will
6515 * not normally need to connect to this signal.
6519 actor_signals[QUEUE_RELAYOUT] =
6520 g_signal_new (I_("queue-relayout"),
6521 G_TYPE_FROM_CLASS (object_class),
6524 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6526 _clutter_marshal_VOID__VOID,
6530 * ClutterActor::event:
6531 * @actor: the actor which received the event
6532 * @event: a #ClutterEvent
6534 * The ::event signal is emitted each time an event is received
6535 * by the @actor. This signal will be emitted on every actor,
6536 * following the hierarchy chain, until it reaches the top-level
6537 * container (the #ClutterStage).
6539 * Return value: %TRUE if the event has been handled by the actor,
6540 * or %FALSE to continue the emission.
6544 actor_signals[EVENT] =
6545 g_signal_new (I_("event"),
6546 G_TYPE_FROM_CLASS (object_class),
6548 G_STRUCT_OFFSET (ClutterActorClass, event),
6549 _clutter_boolean_handled_accumulator, NULL,
6550 _clutter_marshal_BOOLEAN__BOXED,
6552 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6554 * ClutterActor::button-press-event:
6555 * @actor: the actor which received the event
6556 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6558 * The ::button-press-event signal is emitted each time a mouse button
6559 * is pressed on @actor.
6561 * Return value: %TRUE if the event has been handled by the actor,
6562 * or %FALSE to continue the emission.
6566 actor_signals[BUTTON_PRESS_EVENT] =
6567 g_signal_new (I_("button-press-event"),
6568 G_TYPE_FROM_CLASS (object_class),
6570 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6571 _clutter_boolean_handled_accumulator, NULL,
6572 _clutter_marshal_BOOLEAN__BOXED,
6574 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6576 * ClutterActor::button-release-event:
6577 * @actor: the actor which received the event
6578 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6580 * The ::button-release-event signal is emitted each time a mouse button
6581 * is released on @actor.
6583 * Return value: %TRUE if the event has been handled by the actor,
6584 * or %FALSE to continue the emission.
6588 actor_signals[BUTTON_RELEASE_EVENT] =
6589 g_signal_new (I_("button-release-event"),
6590 G_TYPE_FROM_CLASS (object_class),
6592 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6593 _clutter_boolean_handled_accumulator, NULL,
6594 _clutter_marshal_BOOLEAN__BOXED,
6596 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6598 * ClutterActor::scroll-event:
6599 * @actor: the actor which received the event
6600 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6602 * The ::scroll-event signal is emitted each time the mouse is
6603 * scrolled on @actor
6605 * Return value: %TRUE if the event has been handled by the actor,
6606 * or %FALSE to continue the emission.
6610 actor_signals[SCROLL_EVENT] =
6611 g_signal_new (I_("scroll-event"),
6612 G_TYPE_FROM_CLASS (object_class),
6614 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6615 _clutter_boolean_handled_accumulator, NULL,
6616 _clutter_marshal_BOOLEAN__BOXED,
6618 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6620 * ClutterActor::key-press-event:
6621 * @actor: the actor which received the event
6622 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6624 * The ::key-press-event signal is emitted each time a keyboard button
6625 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6627 * Return value: %TRUE if the event has been handled by the actor,
6628 * or %FALSE to continue the emission.
6632 actor_signals[KEY_PRESS_EVENT] =
6633 g_signal_new (I_("key-press-event"),
6634 G_TYPE_FROM_CLASS (object_class),
6636 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6637 _clutter_boolean_handled_accumulator, NULL,
6638 _clutter_marshal_BOOLEAN__BOXED,
6640 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6642 * ClutterActor::key-release-event:
6643 * @actor: the actor which received the event
6644 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6646 * The ::key-release-event signal is emitted each time a keyboard button
6647 * is released while @actor has key focus (see
6648 * clutter_stage_set_key_focus()).
6650 * Return value: %TRUE if the event has been handled by the actor,
6651 * or %FALSE to continue the emission.
6655 actor_signals[KEY_RELEASE_EVENT] =
6656 g_signal_new (I_("key-release-event"),
6657 G_TYPE_FROM_CLASS (object_class),
6659 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6660 _clutter_boolean_handled_accumulator, NULL,
6661 _clutter_marshal_BOOLEAN__BOXED,
6663 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6665 * ClutterActor::motion-event:
6666 * @actor: the actor which received the event
6667 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6669 * The ::motion-event signal is emitted each time the mouse pointer is
6670 * moved over @actor.
6672 * Return value: %TRUE if the event has been handled by the actor,
6673 * or %FALSE to continue the emission.
6677 actor_signals[MOTION_EVENT] =
6678 g_signal_new (I_("motion-event"),
6679 G_TYPE_FROM_CLASS (object_class),
6681 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6682 _clutter_boolean_handled_accumulator, NULL,
6683 _clutter_marshal_BOOLEAN__BOXED,
6685 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6688 * ClutterActor::key-focus-in:
6689 * @actor: the actor which now has key focus
6691 * The ::key-focus-in signal is emitted when @actor receives key focus.
6695 actor_signals[KEY_FOCUS_IN] =
6696 g_signal_new (I_("key-focus-in"),
6697 G_TYPE_FROM_CLASS (object_class),
6699 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6701 _clutter_marshal_VOID__VOID,
6705 * ClutterActor::key-focus-out:
6706 * @actor: the actor which now has key focus
6708 * The ::key-focus-out signal is emitted when @actor loses key focus.
6712 actor_signals[KEY_FOCUS_OUT] =
6713 g_signal_new (I_("key-focus-out"),
6714 G_TYPE_FROM_CLASS (object_class),
6716 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6718 _clutter_marshal_VOID__VOID,
6722 * ClutterActor::enter-event:
6723 * @actor: the actor which the pointer has entered.
6724 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6726 * The ::enter-event signal is emitted when the pointer enters the @actor
6728 * Return value: %TRUE if the event has been handled by the actor,
6729 * or %FALSE to continue the emission.
6733 actor_signals[ENTER_EVENT] =
6734 g_signal_new (I_("enter-event"),
6735 G_TYPE_FROM_CLASS (object_class),
6737 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6738 _clutter_boolean_handled_accumulator, NULL,
6739 _clutter_marshal_BOOLEAN__BOXED,
6741 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6744 * ClutterActor::leave-event:
6745 * @actor: the actor which the pointer has left
6746 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6748 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6750 * Return value: %TRUE if the event has been handled by the actor,
6751 * or %FALSE to continue the emission.
6755 actor_signals[LEAVE_EVENT] =
6756 g_signal_new (I_("leave-event"),
6757 G_TYPE_FROM_CLASS (object_class),
6759 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6760 _clutter_boolean_handled_accumulator, NULL,
6761 _clutter_marshal_BOOLEAN__BOXED,
6763 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6766 * ClutterActor::captured-event:
6767 * @actor: the actor which received the signal
6768 * @event: a #ClutterEvent
6770 * The ::captured-event signal is emitted when an event is captured
6771 * by Clutter. This signal will be emitted starting from the top-level
6772 * container (the #ClutterStage) to the actor which received the event
6773 * going down the hierarchy. This signal can be used to intercept every
6774 * event before the specialized events (like
6775 * ClutterActor::button-press-event or ::key-released-event) are
6778 * Return value: %TRUE if the event has been handled by the actor,
6779 * or %FALSE to continue the emission.
6783 actor_signals[CAPTURED_EVENT] =
6784 g_signal_new (I_("captured-event"),
6785 G_TYPE_FROM_CLASS (object_class),
6787 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6788 _clutter_boolean_handled_accumulator, NULL,
6789 _clutter_marshal_BOOLEAN__BOXED,
6791 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6794 * ClutterActor::paint:
6795 * @actor: the #ClutterActor that received the signal
6797 * The ::paint signal is emitted each time an actor is being painted.
6799 * Subclasses of #ClutterActor should override the class signal handler
6800 * and paint themselves in that function.
6802 * It is possible to connect a handler to the ::paint signal in order
6803 * to set up some custom aspect of a paint.
6807 actor_signals[PAINT] =
6808 g_signal_new (I_("paint"),
6809 G_TYPE_FROM_CLASS (object_class),
6812 G_STRUCT_OFFSET (ClutterActorClass, paint),
6814 _clutter_marshal_VOID__VOID,
6817 * ClutterActor::realize:
6818 * @actor: the #ClutterActor that received the signal
6820 * The ::realize signal is emitted each time an actor is being
6825 actor_signals[REALIZE] =
6826 g_signal_new (I_("realize"),
6827 G_TYPE_FROM_CLASS (object_class),
6829 G_STRUCT_OFFSET (ClutterActorClass, realize),
6831 _clutter_marshal_VOID__VOID,
6834 * ClutterActor::unrealize:
6835 * @actor: the #ClutterActor that received the signal
6837 * The ::unrealize signal is emitted each time an actor is being
6842 actor_signals[UNREALIZE] =
6843 g_signal_new (I_("unrealize"),
6844 G_TYPE_FROM_CLASS (object_class),
6846 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6848 _clutter_marshal_VOID__VOID,
6852 * ClutterActor::pick:
6853 * @actor: the #ClutterActor that received the signal
6854 * @color: the #ClutterColor to be used when picking
6856 * The ::pick signal is emitted each time an actor is being painted
6857 * in "pick mode". The pick mode is used to identify the actor during
6858 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6859 * The actor should paint its shape using the passed @pick_color.
6861 * Subclasses of #ClutterActor should override the class signal handler
6862 * and paint themselves in that function.
6864 * It is possible to connect a handler to the ::pick signal in order
6865 * to set up some custom aspect of a paint in pick mode.
6869 actor_signals[PICK] =
6870 g_signal_new (I_("pick"),
6871 G_TYPE_FROM_CLASS (object_class),
6873 G_STRUCT_OFFSET (ClutterActorClass, pick),
6875 _clutter_marshal_VOID__BOXED,
6877 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6880 * ClutterActor::allocation-changed:
6881 * @actor: the #ClutterActor that emitted the signal
6882 * @box: a #ClutterActorBox with the new allocation
6883 * @flags: #ClutterAllocationFlags for the allocation
6885 * The ::allocation-changed signal is emitted when the
6886 * #ClutterActor:allocation property changes. Usually, application
6887 * code should just use the notifications for the :allocation property
6888 * but if you want to track the allocation flags as well, for instance
6889 * to know whether the absolute origin of @actor changed, then you might
6890 * want use this signal instead.
6894 actor_signals[ALLOCATION_CHANGED] =
6895 g_signal_new (I_("allocation-changed"),
6896 G_TYPE_FROM_CLASS (object_class),
6900 _clutter_marshal_VOID__BOXED_FLAGS,
6902 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6903 CLUTTER_TYPE_ALLOCATION_FLAGS);
6907 clutter_actor_init (ClutterActor *self)
6909 ClutterActorPrivate *priv;
6911 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6913 priv->id = _clutter_context_acquire_id (self);
6916 priv->opacity = 0xff;
6917 priv->show_on_set_parent = TRUE;
6919 priv->needs_width_request = TRUE;
6920 priv->needs_height_request = TRUE;
6921 priv->needs_allocation = TRUE;
6923 priv->cached_width_age = 1;
6924 priv->cached_height_age = 1;
6926 priv->opacity_override = -1;
6927 priv->enable_model_view_transform = TRUE;
6929 /* Initialize an empty paint volume to start with */
6930 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6931 priv->last_paint_volume_valid = TRUE;
6933 priv->transform_valid = FALSE;
6935 /* the default is to stretch the content, to match the
6936 * current behaviour of basically all actors. also, it's
6937 * the easiest thing to compute.
6939 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6943 * clutter_actor_new:
6945 * Creates a new #ClutterActor.
6947 * A newly created actor has a floating reference, which will be sunk
6948 * when it is added to another actor.
6950 * Return value: (transfer full): the newly created #ClutterActor
6955 clutter_actor_new (void)
6957 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6961 * clutter_actor_destroy:
6962 * @self: a #ClutterActor
6964 * Destroys an actor. When an actor is destroyed, it will break any
6965 * references it holds to other objects. If the actor is inside a
6966 * container, the actor will be removed.
6968 * When you destroy a container, its children will be destroyed as well.
6970 * Note: you cannot destroy the #ClutterStage returned by
6971 * clutter_stage_get_default().
6974 clutter_actor_destroy (ClutterActor *self)
6976 g_return_if_fail (CLUTTER_IS_ACTOR (self));
6978 g_object_ref (self);
6980 /* avoid recursion while destroying */
6981 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6983 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6985 g_object_run_dispose (G_OBJECT (self));
6987 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6990 g_object_unref (self);
6994 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6995 ClutterPaintVolume *clip)
6997 ClutterActorPrivate *priv = self->priv;
6998 ClutterPaintVolume *pv;
7001 /* Remove queue entry early in the process, otherwise a new
7002 queue_redraw() during signal handling could put back this
7003 object in the stage redraw list (but the entry is freed as
7004 soon as we return from this function, causing a segfault
7007 priv->queue_redraw_entry = NULL;
7009 /* If we've been explicitly passed a clip volume then there's
7010 * nothing more to calculate, but otherwise the only thing we know
7011 * is that the change is constrained to the given actor.
7013 * The idea is that if we know the paint volume for where the actor
7014 * was last drawn (in eye coordinates) and we also have the paint
7015 * volume for where it will be drawn next (in actor coordinates)
7016 * then if we queue a redraw for both these volumes that will cover
7017 * everything that needs to be redrawn to clear the old view and
7018 * show the latest view of the actor.
7020 * Don't clip this redraw if we don't know what position we had for
7021 * the previous redraw since we don't know where to set the clip so
7022 * it will clear the actor as it is currently.
7026 _clutter_actor_set_queue_redraw_clip (self, clip);
7029 else if (G_LIKELY (priv->last_paint_volume_valid))
7031 pv = _clutter_actor_get_paint_volume_mutable (self);
7034 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7036 /* make sure we redraw the actors old position... */
7037 _clutter_actor_set_queue_redraw_clip (stage,
7038 &priv->last_paint_volume);
7039 _clutter_actor_signal_queue_redraw (stage, stage);
7040 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7042 /* XXX: Ideally the redraw signal would take a clip volume
7043 * argument, but that would be an ABI break. Until we can
7044 * break the ABI we pass the argument out-of-band
7047 /* setup the clip for the actors new position... */
7048 _clutter_actor_set_queue_redraw_clip (self, pv);
7057 _clutter_actor_signal_queue_redraw (self, self);
7059 /* Just in case anyone is manually firing redraw signals without
7060 * using the public queue_redraw() API we are careful to ensure that
7061 * our out-of-band clip member is cleared before returning...
7063 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7065 if (G_LIKELY (clipped))
7066 _clutter_actor_set_queue_redraw_clip (self, NULL);
7070 _clutter_actor_get_allocation_clip (ClutterActor *self,
7071 ClutterActorBox *clip)
7073 ClutterActorBox allocation;
7075 /* XXX: we don't care if we get an out of date allocation here
7076 * because clutter_actor_queue_redraw_with_clip knows to ignore
7077 * the clip if the actor's allocation is invalid.
7079 * This is noted because clutter_actor_get_allocation_box does some
7080 * unnecessary work to support buggy code with a comment suggesting
7081 * that it could be changed later which would be good for this use
7084 clutter_actor_get_allocation_box (self, &allocation);
7086 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7087 * actor's own coordinate space but the allocation is in parent
7091 clip->x2 = allocation.x2 - allocation.x1;
7092 clip->y2 = allocation.y2 - allocation.y1;
7096 _clutter_actor_queue_redraw_full (ClutterActor *self,
7097 ClutterRedrawFlags flags,
7098 ClutterPaintVolume *volume,
7099 ClutterEffect *effect)
7101 ClutterActorPrivate *priv = self->priv;
7102 ClutterPaintVolume allocation_pv;
7103 ClutterPaintVolume *pv;
7104 gboolean should_free_pv;
7105 ClutterActor *stage;
7107 /* Here's an outline of the actor queue redraw mechanism:
7109 * The process starts in one of the following two functions which
7110 * are wrappers for this function:
7111 * clutter_actor_queue_redraw
7112 * _clutter_actor_queue_redraw_with_clip
7114 * additionally, an effect can queue a redraw by wrapping this
7115 * function in clutter_effect_queue_rerun
7117 * This functions queues an entry in a list associated with the
7118 * stage which is a list of actors that queued a redraw while
7119 * updating the timelines, performing layouting and processing other
7120 * mainloop sources before the next paint starts.
7122 * We aim to minimize the processing done at this point because
7123 * there is a good chance other events will happen while updating
7124 * the scenegraph that would invalidate any expensive work we might
7125 * otherwise try to do here. For example we don't try and resolve
7126 * the screen space bounding box of an actor at this stage so as to
7127 * minimize how much of the screen redraw because it's possible
7128 * something else will happen which will force a full redraw anyway.
7130 * When all updates are complete and we come to paint the stage then
7131 * we iterate this list and actually emit the "queue-redraw" signals
7132 * for each of the listed actors which will bubble up to the stage
7133 * for each actor and at that point we will transform the actors
7134 * paint volume into screen coordinates to determine the clip region
7135 * for what needs to be redrawn in the next paint.
7137 * Besides minimizing redundant work another reason for this
7138 * deferred design is that it's more likely we will be able to
7139 * determine the paint volume of an actor once we've finished
7140 * updating the scenegraph because its allocation should be up to
7141 * date. NB: If we can't determine an actors paint volume then we
7142 * can't automatically queue a clipped redraw which can make a big
7143 * difference to performance.
7145 * So the control flow goes like this:
7146 * One of clutter_actor_queue_redraw,
7147 * _clutter_actor_queue_redraw_with_clip
7148 * or clutter_effect_queue_rerun
7150 * then control moves to:
7151 * _clutter_stage_queue_actor_redraw
7153 * later during _clutter_stage_do_update, once relayouting is done
7154 * and the scenegraph has been updated we will call:
7155 * _clutter_stage_finish_queue_redraws
7157 * _clutter_stage_finish_queue_redraws will call
7158 * _clutter_actor_finish_queue_redraw for each listed actor.
7159 * Note: actors *are* allowed to queue further redraws during this
7160 * process (considering clone actors or texture_new_from_actor which
7161 * respond to their source queueing a redraw by queuing a redraw
7162 * themselves). We repeat the process until the list is empty.
7164 * This will result in the "queue-redraw" signal being fired for
7165 * each actor which will pass control to the default signal handler:
7166 * clutter_actor_real_queue_redraw
7168 * This will bubble up to the stages handler:
7169 * clutter_stage_real_queue_redraw
7171 * clutter_stage_real_queue_redraw will transform the actors paint
7172 * volume into screen space and add it as a clip region for the next
7176 /* ignore queueing a redraw for actors being destroyed */
7177 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7180 stage = _clutter_actor_get_stage_internal (self);
7182 /* Ignore queueing a redraw for actors not descended from a stage */
7186 /* ignore queueing a redraw on stages that are being destroyed */
7187 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7190 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7192 ClutterActorBox allocation_clip;
7193 ClutterVertex origin;
7195 /* If the actor doesn't have a valid allocation then we will
7196 * queue a full stage redraw. */
7197 if (priv->needs_allocation)
7199 /* NB: NULL denotes an undefined clip which will result in a
7201 _clutter_actor_set_queue_redraw_clip (self, NULL);
7202 _clutter_actor_signal_queue_redraw (self, self);
7206 _clutter_paint_volume_init_static (&allocation_pv, self);
7207 pv = &allocation_pv;
7209 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7211 origin.x = allocation_clip.x1;
7212 origin.y = allocation_clip.y1;
7214 clutter_paint_volume_set_origin (pv, &origin);
7215 clutter_paint_volume_set_width (pv,
7216 allocation_clip.x2 - allocation_clip.x1);
7217 clutter_paint_volume_set_height (pv,
7218 allocation_clip.y2 -
7219 allocation_clip.y1);
7220 should_free_pv = TRUE;
7225 should_free_pv = FALSE;
7228 self->priv->queue_redraw_entry =
7229 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7230 priv->queue_redraw_entry,
7235 clutter_paint_volume_free (pv);
7237 /* If this is the first redraw queued then we can directly use the
7239 if (!priv->is_dirty)
7240 priv->effect_to_redraw = effect;
7241 /* Otherwise we need to merge it with the existing effect parameter */
7242 else if (effect != NULL)
7244 /* If there's already an effect then we need to use whichever is
7245 later in the chain of actors. Otherwise a full redraw has
7246 already been queued on the actor so we need to ignore the
7248 if (priv->effect_to_redraw != NULL)
7250 if (priv->effects == NULL)
7251 g_warning ("Redraw queued with an effect that is "
7252 "not applied to the actor");
7257 for (l = _clutter_meta_group_peek_metas (priv->effects);
7261 if (l->data == priv->effect_to_redraw ||
7263 priv->effect_to_redraw = l->data;
7270 /* If no effect is specified then we need to redraw the whole
7272 priv->effect_to_redraw = NULL;
7275 priv->is_dirty = TRUE;
7279 * clutter_actor_queue_redraw:
7280 * @self: A #ClutterActor
7282 * Queues up a redraw of an actor and any children. The redraw occurs
7283 * once the main loop becomes idle (after the current batch of events
7284 * has been processed, roughly).
7286 * Applications rarely need to call this, as redraws are handled
7287 * automatically by modification functions.
7289 * This function will not do anything if @self is not visible, or
7290 * if the actor is inside an invisible part of the scenegraph.
7292 * Also be aware that painting is a NOP for actors with an opacity of
7295 * When you are implementing a custom actor you must queue a redraw
7296 * whenever some private state changes that will affect painting or
7297 * picking of your actor.
7300 clutter_actor_queue_redraw (ClutterActor *self)
7302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7304 _clutter_actor_queue_redraw_full (self,
7306 NULL, /* clip volume */
7311 * _clutter_actor_queue_redraw_with_clip:
7312 * @self: A #ClutterActor
7313 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7314 * this queue redraw.
7315 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7316 * redrawn or %NULL if you are just using a @flag to state your
7319 * Queues up a clipped redraw of an actor and any children. The redraw
7320 * occurs once the main loop becomes idle (after the current batch of
7321 * events has been processed, roughly).
7323 * If no flags are given the clip volume is defined by @volume
7324 * specified in actor coordinates and tells Clutter that only content
7325 * within this volume has been changed so Clutter can optionally
7326 * optimize the redraw.
7328 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7329 * should be %NULL and this tells Clutter to use the actor's current
7330 * allocation as a clip box. This flag can only be used for 2D actors,
7331 * because any actor with depth may be projected outside its
7334 * Applications rarely need to call this, as redraws are handled
7335 * automatically by modification functions.
7337 * This function will not do anything if @self is not visible, or if
7338 * the actor is inside an invisible part of the scenegraph.
7340 * Also be aware that painting is a NOP for actors with an opacity of
7343 * When you are implementing a custom actor you must queue a redraw
7344 * whenever some private state changes that will affect painting or
7345 * picking of your actor.
7348 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7349 ClutterRedrawFlags flags,
7350 ClutterPaintVolume *volume)
7352 _clutter_actor_queue_redraw_full (self,
7354 volume, /* clip volume */
7359 _clutter_actor_queue_only_relayout (ClutterActor *self)
7361 ClutterActorPrivate *priv = self->priv;
7363 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7366 if (priv->needs_width_request &&
7367 priv->needs_height_request &&
7368 priv->needs_allocation)
7369 return; /* save some cpu cycles */
7371 #if CLUTTER_ENABLE_DEBUG
7372 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7374 g_warning ("The actor '%s' is currently inside an allocation "
7375 "cycle; calling clutter_actor_queue_relayout() is "
7377 _clutter_actor_get_debug_name (self));
7379 #endif /* CLUTTER_ENABLE_DEBUG */
7381 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7385 * clutter_actor_queue_redraw_with_clip:
7386 * @self: a #ClutterActor
7387 * @clip: (allow-none): a rectangular clip region, or %NULL
7389 * Queues a redraw on @self limited to a specific, actor-relative
7392 * If @clip is %NULL this function is equivalent to
7393 * clutter_actor_queue_redraw().
7398 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7399 const cairo_rectangle_int_t *clip)
7401 ClutterPaintVolume volume;
7402 ClutterVertex origin;
7404 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7408 clutter_actor_queue_redraw (self);
7412 _clutter_paint_volume_init_static (&volume, self);
7418 clutter_paint_volume_set_origin (&volume, &origin);
7419 clutter_paint_volume_set_width (&volume, clip->width);
7420 clutter_paint_volume_set_height (&volume, clip->height);
7422 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7424 clutter_paint_volume_free (&volume);
7428 * clutter_actor_queue_relayout:
7429 * @self: A #ClutterActor
7431 * Indicates that the actor's size request or other layout-affecting
7432 * properties may have changed. This function is used inside #ClutterActor
7433 * subclass implementations, not by applications directly.
7435 * Queueing a new layout automatically queues a redraw as well.
7440 clutter_actor_queue_relayout (ClutterActor *self)
7442 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7444 _clutter_actor_queue_only_relayout (self);
7445 clutter_actor_queue_redraw (self);
7449 * clutter_actor_get_preferred_size:
7450 * @self: a #ClutterActor
7451 * @min_width_p: (out) (allow-none): return location for the minimum
7453 * @min_height_p: (out) (allow-none): return location for the minimum
7455 * @natural_width_p: (out) (allow-none): return location for the natural
7457 * @natural_height_p: (out) (allow-none): return location for the natural
7460 * Computes the preferred minimum and natural size of an actor, taking into
7461 * account the actor's geometry management (either height-for-width
7462 * or width-for-height).
7464 * The width and height used to compute the preferred height and preferred
7465 * width are the actor's natural ones.
7467 * If you need to control the height for the preferred width, or the width for
7468 * the preferred height, you should use clutter_actor_get_preferred_width()
7469 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7470 * geometry management using the #ClutterActor:request-mode property.
7475 clutter_actor_get_preferred_size (ClutterActor *self,
7476 gfloat *min_width_p,
7477 gfloat *min_height_p,
7478 gfloat *natural_width_p,
7479 gfloat *natural_height_p)
7481 ClutterActorPrivate *priv;
7482 gfloat min_width, min_height;
7483 gfloat natural_width, natural_height;
7485 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7489 min_width = min_height = 0;
7490 natural_width = natural_height = 0;
7492 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7494 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7495 clutter_actor_get_preferred_width (self, -1,
7498 clutter_actor_get_preferred_height (self, natural_width,
7504 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7505 clutter_actor_get_preferred_height (self, -1,
7508 clutter_actor_get_preferred_width (self, natural_height,
7514 *min_width_p = min_width;
7517 *min_height_p = min_height;
7519 if (natural_width_p)
7520 *natural_width_p = natural_width;
7522 if (natural_height_p)
7523 *natural_height_p = natural_height;
7528 * @align: a #ClutterActorAlign
7529 * @direction: a #ClutterTextDirection
7531 * Retrieves the correct alignment depending on the text direction
7533 * Return value: the effective alignment
7535 static ClutterActorAlign
7536 effective_align (ClutterActorAlign align,
7537 ClutterTextDirection direction)
7539 ClutterActorAlign res;
7543 case CLUTTER_ACTOR_ALIGN_START:
7544 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7545 ? CLUTTER_ACTOR_ALIGN_END
7546 : CLUTTER_ACTOR_ALIGN_START;
7549 case CLUTTER_ACTOR_ALIGN_END:
7550 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7551 ? CLUTTER_ACTOR_ALIGN_START
7552 : CLUTTER_ACTOR_ALIGN_END;
7564 adjust_for_margin (float margin_start,
7566 float *minimum_size,
7567 float *natural_size,
7568 float *allocated_start,
7569 float *allocated_end)
7571 *minimum_size -= (margin_start + margin_end);
7572 *natural_size -= (margin_start + margin_end);
7573 *allocated_start += margin_start;
7574 *allocated_end -= margin_end;
7578 adjust_for_alignment (ClutterActorAlign alignment,
7580 float *allocated_start,
7581 float *allocated_end)
7583 float allocated_size = *allocated_end - *allocated_start;
7587 case CLUTTER_ACTOR_ALIGN_FILL:
7591 case CLUTTER_ACTOR_ALIGN_START:
7593 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7596 case CLUTTER_ACTOR_ALIGN_END:
7597 if (allocated_size > natural_size)
7599 *allocated_start += (allocated_size - natural_size);
7600 *allocated_end = *allocated_start + natural_size;
7604 case CLUTTER_ACTOR_ALIGN_CENTER:
7605 if (allocated_size > natural_size)
7607 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7608 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7615 * clutter_actor_adjust_width:
7616 * @self: a #ClutterActor
7617 * @minimum_width: (inout): the actor's preferred minimum width, which
7618 * will be adjusted depending on the margin
7619 * @natural_width: (inout): the actor's preferred natural width, which
7620 * will be adjusted depending on the margin
7621 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7622 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7624 * Adjusts the preferred and allocated position and size of an actor,
7625 * depending on the margin and alignment properties.
7628 clutter_actor_adjust_width (ClutterActor *self,
7629 gfloat *minimum_width,
7630 gfloat *natural_width,
7631 gfloat *adjusted_x1,
7632 gfloat *adjusted_x2)
7634 ClutterTextDirection text_dir;
7635 const ClutterLayoutInfo *info;
7637 info = _clutter_actor_get_layout_info_or_defaults (self);
7638 text_dir = clutter_actor_get_text_direction (self);
7640 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7642 /* this will tweak natural_width to remove the margin, so that
7643 * adjust_for_alignment() will use the correct size
7645 adjust_for_margin (info->margin.left, info->margin.right,
7646 minimum_width, natural_width,
7647 adjusted_x1, adjusted_x2);
7649 adjust_for_alignment (effective_align (info->x_align, text_dir),
7651 adjusted_x1, adjusted_x2);
7655 * clutter_actor_adjust_height:
7656 * @self: a #ClutterActor
7657 * @minimum_height: (inout): the actor's preferred minimum height, which
7658 * will be adjusted depending on the margin
7659 * @natural_height: (inout): the actor's preferred natural height, which
7660 * will be adjusted depending on the margin
7661 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7662 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7664 * Adjusts the preferred and allocated position and size of an actor,
7665 * depending on the margin and alignment properties.
7668 clutter_actor_adjust_height (ClutterActor *self,
7669 gfloat *minimum_height,
7670 gfloat *natural_height,
7671 gfloat *adjusted_y1,
7672 gfloat *adjusted_y2)
7674 const ClutterLayoutInfo *info;
7676 info = _clutter_actor_get_layout_info_or_defaults (self);
7678 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7680 /* this will tweak natural_height to remove the margin, so that
7681 * adjust_for_alignment() will use the correct size
7683 adjust_for_margin (info->margin.top, info->margin.bottom,
7684 minimum_height, natural_height,
7688 /* we don't use effective_align() here, because text direction
7689 * only affects the horizontal axis
7691 adjust_for_alignment (info->y_align,
7698 /* looks for a cached size request for this for_size. If not
7699 * found, returns the oldest entry so it can be overwritten */
7701 _clutter_actor_get_cached_size_request (gfloat for_size,
7702 SizeRequest *cached_size_requests,
7703 SizeRequest **result)
7707 *result = &cached_size_requests[0];
7709 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7713 sr = &cached_size_requests[i];
7716 sr->for_size == for_size)
7718 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7722 else if (sr->age < (*result)->age)
7728 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7734 * clutter_actor_get_preferred_width:
7735 * @self: A #ClutterActor
7736 * @for_height: available height when computing the preferred width,
7737 * or a negative value to indicate that no height is defined
7738 * @min_width_p: (out) (allow-none): return location for minimum width,
7740 * @natural_width_p: (out) (allow-none): return location for the natural
7743 * Computes the requested minimum and natural widths for an actor,
7744 * optionally depending on the specified height, or if they are
7745 * already computed, returns the cached values.
7747 * An actor may not get its request - depending on the layout
7748 * manager that's in effect.
7750 * A request should not incorporate the actor's scale or anchor point;
7751 * those transformations do not affect layout, only rendering.
7756 clutter_actor_get_preferred_width (ClutterActor *self,
7758 gfloat *min_width_p,
7759 gfloat *natural_width_p)
7761 float request_min_width, request_natural_width;
7762 SizeRequest *cached_size_request;
7763 const ClutterLayoutInfo *info;
7764 ClutterActorPrivate *priv;
7765 gboolean found_in_cache;
7767 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7771 info = _clutter_actor_get_layout_info_or_defaults (self);
7773 /* we shortcircuit the case of a fixed size set using set_width() */
7774 if (priv->min_width_set && priv->natural_width_set)
7776 if (min_width_p != NULL)
7777 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7779 if (natural_width_p != NULL)
7780 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7785 /* the remaining cases are:
7787 * - either min_width or natural_width have been set
7788 * - neither min_width or natural_width have been set
7790 * in both cases, we go through the cache (and through the actor in case
7791 * of cache misses) and determine the authoritative value depending on
7795 if (!priv->needs_width_request)
7798 _clutter_actor_get_cached_size_request (for_height,
7799 priv->width_requests,
7800 &cached_size_request);
7804 /* if the actor needs a width request we use the first slot */
7805 found_in_cache = FALSE;
7806 cached_size_request = &priv->width_requests[0];
7809 if (!found_in_cache)
7811 gfloat minimum_width, natural_width;
7812 ClutterActorClass *klass;
7814 minimum_width = natural_width = 0;
7816 /* adjust for the margin */
7817 if (for_height >= 0)
7819 for_height -= (info->margin.top + info->margin.bottom);
7824 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7826 klass = CLUTTER_ACTOR_GET_CLASS (self);
7827 klass->get_preferred_width (self, for_height,
7831 /* adjust for the margin */
7832 minimum_width += (info->margin.left + info->margin.right);
7833 natural_width += (info->margin.left + info->margin.right);
7835 /* Due to accumulated float errors, it's better not to warn
7836 * on this, but just fix it.
7838 if (natural_width < minimum_width)
7839 natural_width = minimum_width;
7841 cached_size_request->min_size = minimum_width;
7842 cached_size_request->natural_size = natural_width;
7843 cached_size_request->for_size = for_height;
7844 cached_size_request->age = priv->cached_width_age;
7846 priv->cached_width_age += 1;
7847 priv->needs_width_request = FALSE;
7850 if (!priv->min_width_set)
7851 request_min_width = cached_size_request->min_size;
7853 request_min_width = info->min_width;
7855 if (!priv->natural_width_set)
7856 request_natural_width = cached_size_request->natural_size;
7858 request_natural_width = info->natural_width;
7861 *min_width_p = request_min_width;
7863 if (natural_width_p)
7864 *natural_width_p = request_natural_width;
7868 * clutter_actor_get_preferred_height:
7869 * @self: A #ClutterActor
7870 * @for_width: available width to assume in computing desired height,
7871 * or a negative value to indicate that no width is defined
7872 * @min_height_p: (out) (allow-none): return location for minimum height,
7874 * @natural_height_p: (out) (allow-none): return location for natural
7877 * Computes the requested minimum and natural heights for an actor,
7878 * or if they are already computed, returns the cached values.
7880 * An actor may not get its request - depending on the layout
7881 * manager that's in effect.
7883 * A request should not incorporate the actor's scale or anchor point;
7884 * those transformations do not affect layout, only rendering.
7889 clutter_actor_get_preferred_height (ClutterActor *self,
7891 gfloat *min_height_p,
7892 gfloat *natural_height_p)
7894 float request_min_height, request_natural_height;
7895 SizeRequest *cached_size_request;
7896 const ClutterLayoutInfo *info;
7897 ClutterActorPrivate *priv;
7898 gboolean found_in_cache;
7900 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7904 info = _clutter_actor_get_layout_info_or_defaults (self);
7906 /* we shortcircuit the case of a fixed size set using set_height() */
7907 if (priv->min_height_set && priv->natural_height_set)
7909 if (min_height_p != NULL)
7910 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7912 if (natural_height_p != NULL)
7913 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7918 /* the remaining cases are:
7920 * - either min_height or natural_height have been set
7921 * - neither min_height or natural_height have been set
7923 * in both cases, we go through the cache (and through the actor in case
7924 * of cache misses) and determine the authoritative value depending on
7928 if (!priv->needs_height_request)
7931 _clutter_actor_get_cached_size_request (for_width,
7932 priv->height_requests,
7933 &cached_size_request);
7937 found_in_cache = FALSE;
7938 cached_size_request = &priv->height_requests[0];
7941 if (!found_in_cache)
7943 gfloat minimum_height, natural_height;
7944 ClutterActorClass *klass;
7946 minimum_height = natural_height = 0;
7948 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7950 /* adjust for margin */
7953 for_width -= (info->margin.left + info->margin.right);
7958 klass = CLUTTER_ACTOR_GET_CLASS (self);
7959 klass->get_preferred_height (self, for_width,
7963 /* adjust for margin */
7964 minimum_height += (info->margin.top + info->margin.bottom);
7965 natural_height += (info->margin.top + info->margin.bottom);
7967 /* Due to accumulated float errors, it's better not to warn
7968 * on this, but just fix it.
7970 if (natural_height < minimum_height)
7971 natural_height = minimum_height;
7973 cached_size_request->min_size = minimum_height;
7974 cached_size_request->natural_size = natural_height;
7975 cached_size_request->for_size = for_width;
7976 cached_size_request->age = priv->cached_height_age;
7978 priv->cached_height_age += 1;
7979 priv->needs_height_request = FALSE;
7982 if (!priv->min_height_set)
7983 request_min_height = cached_size_request->min_size;
7985 request_min_height = info->min_height;
7987 if (!priv->natural_height_set)
7988 request_natural_height = cached_size_request->natural_size;
7990 request_natural_height = info->natural_height;
7993 *min_height_p = request_min_height;
7995 if (natural_height_p)
7996 *natural_height_p = request_natural_height;
8000 * clutter_actor_get_allocation_box:
8001 * @self: A #ClutterActor
8002 * @box: (out): the function fills this in with the actor's allocation
8004 * Gets the layout box an actor has been assigned. The allocation can
8005 * only be assumed valid inside a paint() method; anywhere else, it
8006 * may be out-of-date.
8008 * An allocation does not incorporate the actor's scale or anchor point;
8009 * those transformations do not affect layout, only rendering.
8011 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8012 * of functions inside the implementation of the get_preferred_width()
8013 * or get_preferred_height() virtual functions.</note>
8018 clutter_actor_get_allocation_box (ClutterActor *self,
8019 ClutterActorBox *box)
8021 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8023 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8024 * which limits calling get_allocation to inside paint() basically; or
8025 * we can 2) force a layout, which could be expensive if someone calls
8026 * get_allocation somewhere silly; or we can 3) just return the latest
8027 * value, allowing it to be out-of-date, and assume people know what
8030 * The least-surprises approach that keeps existing code working is
8031 * likely to be 2). People can end up doing some inefficient things,
8032 * though, and in general code that requires 2) is probably broken.
8035 /* this implements 2) */
8036 if (G_UNLIKELY (self->priv->needs_allocation))
8038 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8040 /* do not queue a relayout on an unparented actor */
8042 _clutter_stage_maybe_relayout (stage);
8045 /* commenting out the code above and just keeping this assigment
8048 *box = self->priv->allocation;
8052 * clutter_actor_get_allocation_geometry:
8053 * @self: A #ClutterActor
8054 * @geom: (out): allocation geometry in pixels
8056 * Gets the layout box an actor has been assigned. The allocation can
8057 * only be assumed valid inside a paint() method; anywhere else, it
8058 * may be out-of-date.
8060 * An allocation does not incorporate the actor's scale or anchor point;
8061 * those transformations do not affect layout, only rendering.
8063 * The returned rectangle is in pixels.
8068 clutter_actor_get_allocation_geometry (ClutterActor *self,
8069 ClutterGeometry *geom)
8071 ClutterActorBox box;
8073 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8074 g_return_if_fail (geom != NULL);
8076 clutter_actor_get_allocation_box (self, &box);
8078 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8079 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8080 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8081 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8085 clutter_actor_update_constraints (ClutterActor *self,
8086 ClutterActorBox *allocation)
8088 ClutterActorPrivate *priv = self->priv;
8089 const GList *constraints, *l;
8091 if (priv->constraints == NULL)
8094 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8095 for (l = constraints; l != NULL; l = l->next)
8097 ClutterConstraint *constraint = l->data;
8098 ClutterActorMeta *meta = l->data;
8100 if (clutter_actor_meta_get_enabled (meta))
8102 _clutter_constraint_update_allocation (constraint,
8110 * clutter_actor_adjust_allocation:
8111 * @self: a #ClutterActor
8112 * @allocation: (inout): the allocation to adjust
8114 * Adjusts the passed allocation box taking into account the actor's
8115 * layout information, like alignment, expansion, and margin.
8118 clutter_actor_adjust_allocation (ClutterActor *self,
8119 ClutterActorBox *allocation)
8121 ClutterActorBox adj_allocation;
8122 float alloc_width, alloc_height;
8123 float min_width, min_height;
8124 float nat_width, nat_height;
8125 ClutterRequestMode req_mode;
8127 adj_allocation = *allocation;
8129 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8131 /* we want to hit the cache, so we use the public API */
8132 req_mode = clutter_actor_get_request_mode (self);
8134 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8136 clutter_actor_get_preferred_width (self, -1,
8139 clutter_actor_get_preferred_height (self, alloc_width,
8143 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8145 clutter_actor_get_preferred_height (self, -1,
8148 clutter_actor_get_preferred_height (self, alloc_height,
8153 #ifdef CLUTTER_ENABLE_DEBUG
8154 /* warn about underallocations */
8155 if (_clutter_diagnostic_enabled () &&
8156 (floorf (min_width - alloc_width) > 0 ||
8157 floorf (min_height - alloc_height) > 0))
8159 ClutterActor *parent = clutter_actor_get_parent (self);
8161 /* the only actors that are allowed to be underallocated are the Stage,
8162 * as it doesn't have an implicit size, and Actors that specifically
8163 * told us that they want to opt-out from layout control mechanisms
8164 * through the NO_LAYOUT escape hatch.
8166 if (parent != NULL &&
8167 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8169 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8170 "of %.2f x %.2f from its parent actor '%s', but its "
8171 "requested minimum size is of %.2f x %.2f",
8172 _clutter_actor_get_debug_name (self),
8173 alloc_width, alloc_height,
8174 _clutter_actor_get_debug_name (parent),
8175 min_width, min_height);
8180 clutter_actor_adjust_width (self,
8184 &adj_allocation.x2);
8186 clutter_actor_adjust_height (self,
8190 &adj_allocation.y2);
8192 /* we maintain the invariant that an allocation cannot be adjusted
8193 * to be outside the parent-given box
8195 if (adj_allocation.x1 < allocation->x1 ||
8196 adj_allocation.y1 < allocation->y1 ||
8197 adj_allocation.x2 > allocation->x2 ||
8198 adj_allocation.y2 > allocation->y2)
8200 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8201 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8202 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8203 _clutter_actor_get_debug_name (self),
8204 adj_allocation.x1, adj_allocation.y1,
8205 adj_allocation.x2 - adj_allocation.x1,
8206 adj_allocation.y2 - adj_allocation.y1,
8207 allocation->x1, allocation->y1,
8208 allocation->x2 - allocation->x1,
8209 allocation->y2 - allocation->y1);
8213 *allocation = adj_allocation;
8217 * clutter_actor_allocate:
8218 * @self: A #ClutterActor
8219 * @box: new allocation of the actor, in parent-relative coordinates
8220 * @flags: flags that control the allocation
8222 * Called by the parent of an actor to assign the actor its size.
8223 * Should never be called by applications (except when implementing
8224 * a container or layout manager).
8226 * Actors can know from their allocation box whether they have moved
8227 * with respect to their parent actor. The @flags parameter describes
8228 * additional information about the allocation, for instance whether
8229 * the parent has moved with respect to the stage, for example because
8230 * a grandparent's origin has moved.
8235 clutter_actor_allocate (ClutterActor *self,
8236 const ClutterActorBox *box,
8237 ClutterAllocationFlags flags)
8239 ClutterActorPrivate *priv;
8240 ClutterActorClass *klass;
8241 ClutterActorBox old_allocation, real_allocation;
8242 gboolean origin_changed, child_moved, size_changed;
8243 gboolean stage_allocation_changed;
8245 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8246 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8248 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8249 "which isn't a descendent of the stage!\n",
8250 self, _clutter_actor_get_debug_name (self));
8256 old_allocation = priv->allocation;
8257 real_allocation = *box;
8259 /* constraints are allowed to modify the allocation only here; we do
8260 * this prior to all the other checks so that we can bail out if the
8261 * allocation did not change
8263 clutter_actor_update_constraints (self, &real_allocation);
8265 /* adjust the allocation depending on the align/margin properties */
8266 clutter_actor_adjust_allocation (self, &real_allocation);
8268 if (real_allocation.x2 < real_allocation.x1 ||
8269 real_allocation.y2 < real_allocation.y1)
8271 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8272 _clutter_actor_get_debug_name (self),
8273 real_allocation.x2 - real_allocation.x1,
8274 real_allocation.y2 - real_allocation.y1);
8277 /* we allow 0-sized actors, but not negative-sized ones */
8278 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8279 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8281 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8283 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8284 real_allocation.y1 != old_allocation.y1);
8286 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8287 real_allocation.y2 != old_allocation.y2);
8289 if (origin_changed || child_moved || size_changed)
8290 stage_allocation_changed = TRUE;
8292 stage_allocation_changed = FALSE;
8294 /* If we get an allocation "out of the blue"
8295 * (we did not queue relayout), then we want to
8296 * ignore it. But if we have needs_allocation set,
8297 * we want to guarantee that allocate() virtual
8298 * method is always called, i.e. that queue_relayout()
8299 * always results in an allocate() invocation on
8302 * The optimization here is to avoid re-allocating
8303 * actors that did not queue relayout and were
8306 if (!priv->needs_allocation && !stage_allocation_changed)
8308 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8312 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8313 * clutter_actor_allocate(), it indicates whether the parent has its
8314 * absolute origin moved; when passed in to ClutterActor::allocate()
8315 * virtual method though, it indicates whether the child has its
8316 * absolute origin moved. So we set it when child_moved is TRUE
8319 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8321 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8323 klass = CLUTTER_ACTOR_GET_CLASS (self);
8324 klass->allocate (self, &real_allocation, flags);
8326 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8328 if (stage_allocation_changed)
8329 clutter_actor_queue_redraw (self);
8333 * clutter_actor_set_allocation:
8334 * @self: a #ClutterActor
8335 * @box: a #ClutterActorBox
8336 * @flags: allocation flags
8338 * Stores the allocation of @self as defined by @box.
8340 * This function can only be called from within the implementation of
8341 * the #ClutterActorClass.allocate() virtual function.
8343 * The allocation should have been adjusted to take into account constraints,
8344 * alignment, and margin properties. If you are implementing a #ClutterActor
8345 * subclass that provides its own layout management policy for its children
8346 * instead of using a #ClutterLayoutManager delegate, you should not call
8347 * this function on the children of @self; instead, you should call
8348 * clutter_actor_allocate(), which will adjust the allocation box for
8351 * This function should only be used by subclasses of #ClutterActor
8352 * that wish to store their allocation but cannot chain up to the
8353 * parent's implementation; the default implementation of the
8354 * #ClutterActorClass.allocate() virtual function will call this
8357 * It is important to note that, while chaining up was the recommended
8358 * behaviour for #ClutterActor subclasses prior to the introduction of
8359 * this function, it is recommended to call clutter_actor_set_allocation()
8362 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8363 * to handle the allocation of its children, this function will call
8364 * the clutter_layout_manager_allocate() function only if the
8365 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8366 * expected that the subclass will call clutter_layout_manager_allocate()
8367 * by itself. For instance, the following code:
8371 * my_actor_allocate (ClutterActor *actor,
8372 * const ClutterActorBox *allocation,
8373 * ClutterAllocationFlags flags)
8375 * ClutterActorBox new_alloc;
8376 * ClutterAllocationFlags new_flags;
8378 * adjust_allocation (allocation, &new_alloc);
8380 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8382 * /* this will use the layout manager set on the actor */
8383 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8387 * is equivalent to this:
8391 * my_actor_allocate (ClutterActor *actor,
8392 * const ClutterActorBox *allocation,
8393 * ClutterAllocationFlags flags)
8395 * ClutterLayoutManager *layout;
8396 * ClutterActorBox new_alloc;
8398 * adjust_allocation (allocation, &new_alloc);
8400 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8402 * layout = clutter_actor_get_layout_manager (actor);
8403 * clutter_layout_manager_allocate (layout,
8404 * CLUTTER_CONTAINER (actor),
8413 clutter_actor_set_allocation (ClutterActor *self,
8414 const ClutterActorBox *box,
8415 ClutterAllocationFlags flags)
8417 ClutterActorPrivate *priv;
8420 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8421 g_return_if_fail (box != NULL);
8423 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8425 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8426 "can only be called from within the implementation of "
8427 "the ClutterActor::allocate() virtual function.");
8433 g_object_freeze_notify (G_OBJECT (self));
8435 changed = clutter_actor_set_allocation_internal (self, box, flags);
8437 /* we allocate our children before we notify changes in our geometry,
8438 * so that people connecting to properties will be able to get valid
8439 * data out of the sub-tree of the scene graph that has this actor at
8442 clutter_actor_maybe_layout_children (self, box, flags);
8446 ClutterActorBox signal_box = priv->allocation;
8447 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8449 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8454 g_object_thaw_notify (G_OBJECT (self));
8458 * clutter_actor_set_geometry:
8459 * @self: A #ClutterActor
8460 * @geometry: A #ClutterGeometry
8462 * Sets the actor's fixed position and forces its minimum and natural
8463 * size, in pixels. This means the untransformed actor will have the
8464 * given geometry. This is the same as calling clutter_actor_set_position()
8465 * and clutter_actor_set_size().
8467 * Deprecated: 1.10: Use clutter_actor_set_position() and
8468 * clutter_actor_set_size() instead.
8471 clutter_actor_set_geometry (ClutterActor *self,
8472 const ClutterGeometry *geometry)
8474 g_object_freeze_notify (G_OBJECT (self));
8476 clutter_actor_set_position (self, geometry->x, geometry->y);
8477 clutter_actor_set_size (self, geometry->width, geometry->height);
8479 g_object_thaw_notify (G_OBJECT (self));
8483 * clutter_actor_get_geometry:
8484 * @self: A #ClutterActor
8485 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8487 * Gets the size and position of an actor relative to its parent
8488 * actor. This is the same as calling clutter_actor_get_position() and
8489 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8490 * requested size and position if the actor's allocation is invalid.
8492 * Deprecated: 1.10: Use clutter_actor_get_position() and
8493 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8497 clutter_actor_get_geometry (ClutterActor *self,
8498 ClutterGeometry *geometry)
8500 gfloat x, y, width, height;
8502 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8503 g_return_if_fail (geometry != NULL);
8505 clutter_actor_get_position (self, &x, &y);
8506 clutter_actor_get_size (self, &width, &height);
8508 geometry->x = (int) x;
8509 geometry->y = (int) y;
8510 geometry->width = (int) width;
8511 geometry->height = (int) height;
8515 * clutter_actor_set_position:
8516 * @self: A #ClutterActor
8517 * @x: New left position of actor in pixels.
8518 * @y: New top position of actor in pixels.
8520 * Sets the actor's fixed position in pixels relative to any parent
8523 * If a layout manager is in use, this position will override the
8524 * layout manager and force a fixed position.
8527 clutter_actor_set_position (ClutterActor *self,
8531 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8533 g_object_freeze_notify (G_OBJECT (self));
8535 clutter_actor_set_x (self, x);
8536 clutter_actor_set_y (self, y);
8538 g_object_thaw_notify (G_OBJECT (self));
8542 * clutter_actor_get_fixed_position_set:
8543 * @self: A #ClutterActor
8545 * Checks whether an actor has a fixed position set (and will thus be
8546 * unaffected by any layout manager).
8548 * Return value: %TRUE if the fixed position is set on the actor
8553 clutter_actor_get_fixed_position_set (ClutterActor *self)
8555 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8557 return self->priv->position_set;
8561 * clutter_actor_set_fixed_position_set:
8562 * @self: A #ClutterActor
8563 * @is_set: whether to use fixed position
8565 * Sets whether an actor has a fixed position set (and will thus be
8566 * unaffected by any layout manager).
8571 clutter_actor_set_fixed_position_set (ClutterActor *self,
8574 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8576 if (self->priv->position_set == (is_set != FALSE))
8579 self->priv->position_set = is_set != FALSE;
8580 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8582 clutter_actor_queue_relayout (self);
8586 * clutter_actor_move_by:
8587 * @self: A #ClutterActor
8588 * @dx: Distance to move Actor on X axis.
8589 * @dy: Distance to move Actor on Y axis.
8591 * Moves an actor by the specified distance relative to its current
8592 * position in pixels.
8594 * This function modifies the fixed position of an actor and thus removes
8595 * it from any layout management. Another way to move an actor is with an
8596 * anchor point, see clutter_actor_set_anchor_point().
8601 clutter_actor_move_by (ClutterActor *self,
8605 const ClutterLayoutInfo *info;
8608 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8610 info = _clutter_actor_get_layout_info_or_defaults (self);
8614 clutter_actor_set_position (self, x + dx, y + dy);
8618 clutter_actor_set_min_width (ClutterActor *self,
8621 ClutterActorPrivate *priv = self->priv;
8622 ClutterActorBox old = { 0, };
8623 ClutterLayoutInfo *info;
8625 /* if we are setting the size on a top-level actor and the
8626 * backend only supports static top-levels (e.g. framebuffers)
8627 * then we ignore the passed value and we override it with
8628 * the stage implementation's preferred size.
8630 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8631 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8634 info = _clutter_actor_get_layout_info (self);
8636 if (priv->min_width_set && min_width == info->min_width)
8639 g_object_freeze_notify (G_OBJECT (self));
8641 clutter_actor_store_old_geometry (self, &old);
8643 info->min_width = min_width;
8644 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8645 clutter_actor_set_min_width_set (self, TRUE);
8647 clutter_actor_notify_if_geometry_changed (self, &old);
8649 g_object_thaw_notify (G_OBJECT (self));
8651 clutter_actor_queue_relayout (self);
8655 clutter_actor_set_min_height (ClutterActor *self,
8659 ClutterActorPrivate *priv = self->priv;
8660 ClutterActorBox old = { 0, };
8661 ClutterLayoutInfo *info;
8663 /* if we are setting the size on a top-level actor and the
8664 * backend only supports static top-levels (e.g. framebuffers)
8665 * then we ignore the passed value and we override it with
8666 * the stage implementation's preferred size.
8668 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8669 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8672 info = _clutter_actor_get_layout_info (self);
8674 if (priv->min_height_set && min_height == info->min_height)
8677 g_object_freeze_notify (G_OBJECT (self));
8679 clutter_actor_store_old_geometry (self, &old);
8681 info->min_height = min_height;
8682 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8683 clutter_actor_set_min_height_set (self, TRUE);
8685 clutter_actor_notify_if_geometry_changed (self, &old);
8687 g_object_thaw_notify (G_OBJECT (self));
8689 clutter_actor_queue_relayout (self);
8693 clutter_actor_set_natural_width (ClutterActor *self,
8694 gfloat natural_width)
8696 ClutterActorPrivate *priv = self->priv;
8697 ClutterActorBox old = { 0, };
8698 ClutterLayoutInfo *info;
8700 /* if we are setting the size on a top-level actor and the
8701 * backend only supports static top-levels (e.g. framebuffers)
8702 * then we ignore the passed value and we override it with
8703 * the stage implementation's preferred size.
8705 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8706 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8709 info = _clutter_actor_get_layout_info (self);
8711 if (priv->natural_width_set && natural_width == info->natural_width)
8714 g_object_freeze_notify (G_OBJECT (self));
8716 clutter_actor_store_old_geometry (self, &old);
8718 info->natural_width = natural_width;
8719 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8720 clutter_actor_set_natural_width_set (self, TRUE);
8722 clutter_actor_notify_if_geometry_changed (self, &old);
8724 g_object_thaw_notify (G_OBJECT (self));
8726 clutter_actor_queue_relayout (self);
8730 clutter_actor_set_natural_height (ClutterActor *self,
8731 gfloat natural_height)
8733 ClutterActorPrivate *priv = self->priv;
8734 ClutterActorBox old = { 0, };
8735 ClutterLayoutInfo *info;
8737 /* if we are setting the size on a top-level actor and the
8738 * backend only supports static top-levels (e.g. framebuffers)
8739 * then we ignore the passed value and we override it with
8740 * the stage implementation's preferred size.
8742 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8743 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8746 info = _clutter_actor_get_layout_info (self);
8748 if (priv->natural_height_set && natural_height == info->natural_height)
8751 g_object_freeze_notify (G_OBJECT (self));
8753 clutter_actor_store_old_geometry (self, &old);
8755 info->natural_height = natural_height;
8756 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8757 clutter_actor_set_natural_height_set (self, TRUE);
8759 clutter_actor_notify_if_geometry_changed (self, &old);
8761 g_object_thaw_notify (G_OBJECT (self));
8763 clutter_actor_queue_relayout (self);
8767 clutter_actor_set_min_width_set (ClutterActor *self,
8768 gboolean use_min_width)
8770 ClutterActorPrivate *priv = self->priv;
8771 ClutterActorBox old = { 0, };
8773 if (priv->min_width_set == (use_min_width != FALSE))
8776 clutter_actor_store_old_geometry (self, &old);
8778 priv->min_width_set = use_min_width != FALSE;
8779 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8781 clutter_actor_notify_if_geometry_changed (self, &old);
8783 clutter_actor_queue_relayout (self);
8787 clutter_actor_set_min_height_set (ClutterActor *self,
8788 gboolean use_min_height)
8790 ClutterActorPrivate *priv = self->priv;
8791 ClutterActorBox old = { 0, };
8793 if (priv->min_height_set == (use_min_height != FALSE))
8796 clutter_actor_store_old_geometry (self, &old);
8798 priv->min_height_set = use_min_height != FALSE;
8799 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8801 clutter_actor_notify_if_geometry_changed (self, &old);
8803 clutter_actor_queue_relayout (self);
8807 clutter_actor_set_natural_width_set (ClutterActor *self,
8808 gboolean use_natural_width)
8810 ClutterActorPrivate *priv = self->priv;
8811 ClutterActorBox old = { 0, };
8813 if (priv->natural_width_set == (use_natural_width != FALSE))
8816 clutter_actor_store_old_geometry (self, &old);
8818 priv->natural_width_set = use_natural_width != FALSE;
8819 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8821 clutter_actor_notify_if_geometry_changed (self, &old);
8823 clutter_actor_queue_relayout (self);
8827 clutter_actor_set_natural_height_set (ClutterActor *self,
8828 gboolean use_natural_height)
8830 ClutterActorPrivate *priv = self->priv;
8831 ClutterActorBox old = { 0, };
8833 if (priv->natural_height_set == (use_natural_height != FALSE))
8836 clutter_actor_store_old_geometry (self, &old);
8838 priv->natural_height_set = use_natural_height != FALSE;
8839 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8841 clutter_actor_notify_if_geometry_changed (self, &old);
8843 clutter_actor_queue_relayout (self);
8847 * clutter_actor_set_request_mode:
8848 * @self: a #ClutterActor
8849 * @mode: the request mode
8851 * Sets the geometry request mode of @self.
8853 * The @mode determines the order for invoking
8854 * clutter_actor_get_preferred_width() and
8855 * clutter_actor_get_preferred_height()
8860 clutter_actor_set_request_mode (ClutterActor *self,
8861 ClutterRequestMode mode)
8863 ClutterActorPrivate *priv;
8865 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8869 if (priv->request_mode == mode)
8872 priv->request_mode = mode;
8874 priv->needs_width_request = TRUE;
8875 priv->needs_height_request = TRUE;
8877 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8879 clutter_actor_queue_relayout (self);
8883 * clutter_actor_get_request_mode:
8884 * @self: a #ClutterActor
8886 * Retrieves the geometry request mode of @self
8888 * Return value: the request mode for the actor
8893 clutter_actor_get_request_mode (ClutterActor *self)
8895 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8896 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8898 return self->priv->request_mode;
8901 /* variant of set_width() without checks and without notification
8902 * freeze+thaw, for internal usage only
8905 clutter_actor_set_width_internal (ClutterActor *self,
8910 /* the Stage will use the :min-width to control the minimum
8911 * width to be resized to, so we should not be setting it
8912 * along with the :natural-width
8914 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8915 clutter_actor_set_min_width (self, width);
8917 clutter_actor_set_natural_width (self, width);
8921 /* we only unset the :natural-width for the Stage */
8922 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8923 clutter_actor_set_min_width_set (self, FALSE);
8925 clutter_actor_set_natural_width_set (self, FALSE);
8929 /* variant of set_height() without checks and without notification
8930 * freeze+thaw, for internal usage only
8933 clutter_actor_set_height_internal (ClutterActor *self,
8938 /* see the comment above in set_width_internal() */
8939 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8940 clutter_actor_set_min_height (self, height);
8942 clutter_actor_set_natural_height (self, height);
8946 /* see the comment above in set_width_internal() */
8947 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8948 clutter_actor_set_min_height_set (self, FALSE);
8950 clutter_actor_set_natural_height_set (self, FALSE);
8955 * clutter_actor_set_size:
8956 * @self: A #ClutterActor
8957 * @width: New width of actor in pixels, or -1
8958 * @height: New height of actor in pixels, or -1
8960 * Sets the actor's size request in pixels. This overrides any
8961 * "normal" size request the actor would have. For example
8962 * a text actor might normally request the size of the text;
8963 * this function would force a specific size instead.
8965 * If @width and/or @height are -1 the actor will use its
8966 * "normal" size request instead of overriding it, i.e.
8967 * you can "unset" the size with -1.
8969 * This function sets or unsets both the minimum and natural size.
8972 clutter_actor_set_size (ClutterActor *self,
8976 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8978 g_object_freeze_notify (G_OBJECT (self));
8980 clutter_actor_set_width (self, width);
8981 clutter_actor_set_height (self, height);
8983 g_object_thaw_notify (G_OBJECT (self));
8987 * clutter_actor_get_size:
8988 * @self: A #ClutterActor
8989 * @width: (out) (allow-none): return location for the width, or %NULL.
8990 * @height: (out) (allow-none): return location for the height, or %NULL.
8992 * This function tries to "do what you mean" and return
8993 * the size an actor will have. If the actor has a valid
8994 * allocation, the allocation will be returned; otherwise,
8995 * the actors natural size request will be returned.
8997 * If you care whether you get the request vs. the allocation, you
8998 * should probably call a different function like
8999 * clutter_actor_get_allocation_box() or
9000 * clutter_actor_get_preferred_width().
9005 clutter_actor_get_size (ClutterActor *self,
9009 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9012 *width = clutter_actor_get_width (self);
9015 *height = clutter_actor_get_height (self);
9019 * clutter_actor_get_position:
9020 * @self: a #ClutterActor
9021 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9022 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9024 * This function tries to "do what you mean" and tell you where the
9025 * actor is, prior to any transformations. Retrieves the fixed
9026 * position of an actor in pixels, if one has been set; otherwise, if
9027 * the allocation is valid, returns the actor's allocated position;
9028 * otherwise, returns 0,0.
9030 * The returned position is in pixels.
9035 clutter_actor_get_position (ClutterActor *self,
9039 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9042 *x = clutter_actor_get_x (self);
9045 *y = clutter_actor_get_y (self);
9049 * clutter_actor_get_transformed_position:
9050 * @self: A #ClutterActor
9051 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9052 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9054 * Gets the absolute position of an actor, in pixels relative to the stage.
9059 clutter_actor_get_transformed_position (ClutterActor *self,
9066 v1.x = v1.y = v1.z = 0;
9067 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9077 * clutter_actor_get_transformed_size:
9078 * @self: A #ClutterActor
9079 * @width: (out) (allow-none): return location for the width, or %NULL
9080 * @height: (out) (allow-none): return location for the height, or %NULL
9082 * Gets the absolute size of an actor in pixels, taking into account the
9085 * If the actor has a valid allocation, the allocated size will be used.
9086 * If the actor has not a valid allocation then the preferred size will
9087 * be transformed and returned.
9089 * If you want the transformed allocation, see
9090 * clutter_actor_get_abs_allocation_vertices() instead.
9092 * <note>When the actor (or one of its ancestors) is rotated around the
9093 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9094 * as a generic quadrangle; in that case this function returns the size
9095 * of the smallest rectangle that encapsulates the entire quad. Please
9096 * note that in this case no assumptions can be made about the relative
9097 * position of this envelope to the absolute position of the actor, as
9098 * returned by clutter_actor_get_transformed_position(); if you need this
9099 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9100 * to get the coords of the actual quadrangle.</note>
9105 clutter_actor_get_transformed_size (ClutterActor *self,
9109 ClutterActorPrivate *priv;
9111 gfloat x_min, x_max, y_min, y_max;
9114 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9118 /* if the actor hasn't been allocated yet, get the preferred
9119 * size and transform that
9121 if (priv->needs_allocation)
9123 gfloat natural_width, natural_height;
9124 ClutterActorBox box;
9126 /* Make a fake allocation to transform.
9128 * NB: _clutter_actor_transform_and_project_box expects a box in
9129 * the actor's coordinate space... */
9134 natural_width = natural_height = 0;
9135 clutter_actor_get_preferred_size (self, NULL, NULL,
9139 box.x2 = natural_width;
9140 box.y2 = natural_height;
9142 _clutter_actor_transform_and_project_box (self, &box, v);
9145 clutter_actor_get_abs_allocation_vertices (self, v);
9147 x_min = x_max = v[0].x;
9148 y_min = y_max = v[0].y;
9150 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9166 *width = x_max - x_min;
9169 *height = y_max - y_min;
9173 * clutter_actor_get_width:
9174 * @self: A #ClutterActor
9176 * Retrieves the width of a #ClutterActor.
9178 * If the actor has a valid allocation, this function will return the
9179 * width of the allocated area given to the actor.
9181 * If the actor does not have a valid allocation, this function will
9182 * return the actor's natural width, that is the preferred width of
9185 * If you care whether you get the preferred width or the width that
9186 * has been assigned to the actor, you should probably call a different
9187 * function like clutter_actor_get_allocation_box() to retrieve the
9188 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9191 * If an actor has a fixed width, for instance a width that has been
9192 * assigned using clutter_actor_set_width(), the width returned will
9193 * be the same value.
9195 * Return value: the width of the actor, in pixels
9198 clutter_actor_get_width (ClutterActor *self)
9200 ClutterActorPrivate *priv;
9202 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9206 if (priv->needs_allocation)
9208 gfloat natural_width = 0;
9210 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9211 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9214 gfloat natural_height = 0;
9216 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9217 clutter_actor_get_preferred_width (self, natural_height,
9222 return natural_width;
9225 return priv->allocation.x2 - priv->allocation.x1;
9229 * clutter_actor_get_height:
9230 * @self: A #ClutterActor
9232 * Retrieves the height of a #ClutterActor.
9234 * If the actor has a valid allocation, this function will return the
9235 * height of the allocated area given to the actor.
9237 * If the actor does not have a valid allocation, this function will
9238 * return the actor's natural height, that is the preferred height of
9241 * If you care whether you get the preferred height or the height that
9242 * has been assigned to the actor, you should probably call a different
9243 * function like clutter_actor_get_allocation_box() to retrieve the
9244 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9247 * If an actor has a fixed height, for instance a height that has been
9248 * assigned using clutter_actor_set_height(), the height returned will
9249 * be the same value.
9251 * Return value: the height of the actor, in pixels
9254 clutter_actor_get_height (ClutterActor *self)
9256 ClutterActorPrivate *priv;
9258 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9262 if (priv->needs_allocation)
9264 gfloat natural_height = 0;
9266 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9268 gfloat natural_width = 0;
9270 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9271 clutter_actor_get_preferred_height (self, natural_width,
9272 NULL, &natural_height);
9275 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9277 return natural_height;
9280 return priv->allocation.y2 - priv->allocation.y1;
9284 * clutter_actor_set_width:
9285 * @self: A #ClutterActor
9286 * @width: Requested new width for the actor, in pixels, or -1
9288 * Forces a width on an actor, causing the actor's preferred width
9289 * and height (if any) to be ignored.
9291 * If @width is -1 the actor will use its preferred width request
9292 * instead of overriding it, i.e. you can "unset" the width with -1.
9294 * This function sets both the minimum and natural size of the actor.
9299 clutter_actor_set_width (ClutterActor *self,
9302 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9304 if (clutter_actor_get_easing_duration (self) != 0)
9306 ClutterTransition *transition;
9308 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9309 if (transition == NULL)
9311 float old_width = clutter_actor_get_width (self);
9313 transition = _clutter_actor_create_transition (self,
9314 obj_props[PROP_WIDTH],
9317 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9320 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9322 clutter_actor_queue_relayout (self);
9326 g_object_freeze_notify (G_OBJECT (self));
9328 clutter_actor_set_width_internal (self, width);
9330 g_object_thaw_notify (G_OBJECT (self));
9335 * clutter_actor_set_height:
9336 * @self: A #ClutterActor
9337 * @height: Requested new height for the actor, in pixels, or -1
9339 * Forces a height on an actor, causing the actor's preferred width
9340 * and height (if any) to be ignored.
9342 * If @height is -1 the actor will use its preferred height instead of
9343 * overriding it, i.e. you can "unset" the height with -1.
9345 * This function sets both the minimum and natural size of the actor.
9350 clutter_actor_set_height (ClutterActor *self,
9353 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9355 if (clutter_actor_get_easing_duration (self) != 0)
9357 ClutterTransition *transition;
9359 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9360 if (transition == NULL)
9362 float old_height = clutter_actor_get_height (self);
9364 transition = _clutter_actor_create_transition (self,
9365 obj_props[PROP_HEIGHT],
9368 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9371 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9373 clutter_actor_queue_relayout (self);
9377 g_object_freeze_notify (G_OBJECT (self));
9379 clutter_actor_set_height_internal (self, height);
9381 g_object_thaw_notify (G_OBJECT (self));
9386 clutter_actor_set_x_internal (ClutterActor *self,
9389 ClutterActorPrivate *priv = self->priv;
9390 ClutterLayoutInfo *linfo;
9391 ClutterActorBox old = { 0, };
9393 linfo = _clutter_actor_get_layout_info (self);
9395 if (priv->position_set && linfo->fixed_x == x)
9398 clutter_actor_store_old_geometry (self, &old);
9401 clutter_actor_set_fixed_position_set (self, TRUE);
9403 clutter_actor_notify_if_geometry_changed (self, &old);
9405 clutter_actor_queue_relayout (self);
9409 clutter_actor_set_y_internal (ClutterActor *self,
9412 ClutterActorPrivate *priv = self->priv;
9413 ClutterLayoutInfo *linfo;
9414 ClutterActorBox old = { 0, };
9416 linfo = _clutter_actor_get_layout_info (self);
9418 if (priv->position_set && linfo->fixed_y == y)
9421 clutter_actor_store_old_geometry (self, &old);
9424 clutter_actor_set_fixed_position_set (self, TRUE);
9426 clutter_actor_notify_if_geometry_changed (self, &old);
9430 * clutter_actor_set_x:
9431 * @self: a #ClutterActor
9432 * @x: the actor's position on the X axis
9434 * Sets the actor's X coordinate, relative to its parent, in pixels.
9436 * Overrides any layout manager and forces a fixed position for
9439 * The #ClutterActor:x property is animatable.
9444 clutter_actor_set_x (ClutterActor *self,
9447 const ClutterLayoutInfo *linfo;
9449 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9451 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9453 if (clutter_actor_get_easing_duration (self) != 0)
9455 ClutterTransition *transition;
9457 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9458 if (transition == NULL)
9460 transition = _clutter_actor_create_transition (self,
9465 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9468 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9470 clutter_actor_queue_relayout (self);
9473 clutter_actor_set_x_internal (self, x);
9477 * clutter_actor_set_y:
9478 * @self: a #ClutterActor
9479 * @y: the actor's position on the Y axis
9481 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9483 * Overrides any layout manager and forces a fixed position for
9486 * The #ClutterActor:y property is animatable.
9491 clutter_actor_set_y (ClutterActor *self,
9494 const ClutterLayoutInfo *linfo;
9496 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9498 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9500 if (clutter_actor_get_easing_duration (self) != 0)
9502 ClutterTransition *transition;
9504 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9505 if (transition == NULL)
9507 transition = _clutter_actor_create_transition (self,
9512 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9515 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9517 clutter_actor_queue_relayout (self);
9520 clutter_actor_set_y_internal (self, y);
9522 clutter_actor_queue_relayout (self);
9526 * clutter_actor_get_x:
9527 * @self: A #ClutterActor
9529 * Retrieves the X coordinate of a #ClutterActor.
9531 * This function tries to "do what you mean", by returning the
9532 * correct value depending on the actor's state.
9534 * If the actor has a valid allocation, this function will return
9535 * the X coordinate of the origin of the allocation box.
9537 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9538 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9539 * function will return that coordinate.
9541 * If both the allocation and a fixed position are missing, this function
9544 * Return value: the X coordinate, in pixels, ignoring any
9545 * transformation (i.e. scaling, rotation)
9548 clutter_actor_get_x (ClutterActor *self)
9550 ClutterActorPrivate *priv;
9552 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9556 if (priv->needs_allocation)
9558 if (priv->position_set)
9560 const ClutterLayoutInfo *info;
9562 info = _clutter_actor_get_layout_info_or_defaults (self);
9564 return info->fixed_x;
9570 return priv->allocation.x1;
9574 * clutter_actor_get_y:
9575 * @self: A #ClutterActor
9577 * Retrieves the Y coordinate of a #ClutterActor.
9579 * This function tries to "do what you mean", by returning the
9580 * correct value depending on the actor's state.
9582 * If the actor has a valid allocation, this function will return
9583 * the Y coordinate of the origin of the allocation box.
9585 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9586 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9587 * function will return that coordinate.
9589 * If both the allocation and a fixed position are missing, this function
9592 * Return value: the Y coordinate, in pixels, ignoring any
9593 * transformation (i.e. scaling, rotation)
9596 clutter_actor_get_y (ClutterActor *self)
9598 ClutterActorPrivate *priv;
9600 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9604 if (priv->needs_allocation)
9606 if (priv->position_set)
9608 const ClutterLayoutInfo *info;
9610 info = _clutter_actor_get_layout_info_or_defaults (self);
9612 return info->fixed_y;
9618 return priv->allocation.y1;
9622 * clutter_actor_set_scale:
9623 * @self: A #ClutterActor
9624 * @scale_x: double factor to scale actor by horizontally.
9625 * @scale_y: double factor to scale actor by vertically.
9627 * Scales an actor with the given factors. The scaling is relative to
9628 * the scale center and the anchor point. The scale center is
9629 * unchanged by this function and defaults to 0,0.
9631 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9637 clutter_actor_set_scale (ClutterActor *self,
9641 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9643 g_object_freeze_notify (G_OBJECT (self));
9645 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9646 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9648 g_object_thaw_notify (G_OBJECT (self));
9652 * clutter_actor_set_scale_full:
9653 * @self: A #ClutterActor
9654 * @scale_x: double factor to scale actor by horizontally.
9655 * @scale_y: double factor to scale actor by vertically.
9656 * @center_x: X coordinate of the center of the scale.
9657 * @center_y: Y coordinate of the center of the scale
9659 * Scales an actor with the given factors around the given center
9660 * point. The center point is specified in pixels relative to the
9661 * anchor point (usually the top left corner of the actor).
9663 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9669 clutter_actor_set_scale_full (ClutterActor *self,
9675 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9677 g_object_freeze_notify (G_OBJECT (self));
9679 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9680 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9681 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9682 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9684 g_object_thaw_notify (G_OBJECT (self));
9688 * clutter_actor_set_scale_with_gravity:
9689 * @self: A #ClutterActor
9690 * @scale_x: double factor to scale actor by horizontally.
9691 * @scale_y: double factor to scale actor by vertically.
9692 * @gravity: the location of the scale center expressed as a compass
9695 * Scales an actor with the given factors around the given
9696 * center point. The center point is specified as one of the compass
9697 * directions in #ClutterGravity. For example, setting it to north
9698 * will cause the top of the actor to remain unchanged and the rest of
9699 * the actor to expand left, right and downwards.
9701 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9707 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9710 ClutterGravity gravity)
9712 ClutterTransformInfo *info;
9715 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9717 obj = G_OBJECT (self);
9719 g_object_freeze_notify (obj);
9721 info = _clutter_actor_get_transform_info (self);
9722 info->scale_x = scale_x;
9723 info->scale_y = scale_y;
9725 if (gravity == CLUTTER_GRAVITY_NONE)
9726 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9728 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9730 self->priv->transform_valid = FALSE;
9732 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9733 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9734 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9735 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9736 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9738 clutter_actor_queue_redraw (self);
9740 g_object_thaw_notify (obj);
9744 * clutter_actor_get_scale:
9745 * @self: A #ClutterActor
9746 * @scale_x: (out) (allow-none): Location to store horizonal
9747 * scale factor, or %NULL.
9748 * @scale_y: (out) (allow-none): Location to store vertical
9749 * scale factor, or %NULL.
9751 * Retrieves an actors scale factors.
9756 clutter_actor_get_scale (ClutterActor *self,
9760 const ClutterTransformInfo *info;
9762 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9764 info = _clutter_actor_get_transform_info_or_defaults (self);
9767 *scale_x = info->scale_x;
9770 *scale_y = info->scale_y;
9774 * clutter_actor_get_scale_center:
9775 * @self: A #ClutterActor
9776 * @center_x: (out) (allow-none): Location to store the X position
9777 * of the scale center, or %NULL.
9778 * @center_y: (out) (allow-none): Location to store the Y position
9779 * of the scale center, or %NULL.
9781 * Retrieves the scale center coordinate in pixels relative to the top
9782 * left corner of the actor. If the scale center was specified using a
9783 * #ClutterGravity this will calculate the pixel offset using the
9784 * current size of the actor.
9789 clutter_actor_get_scale_center (ClutterActor *self,
9793 const ClutterTransformInfo *info;
9795 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9797 info = _clutter_actor_get_transform_info_or_defaults (self);
9799 clutter_anchor_coord_get_units (self, &info->scale_center,
9806 * clutter_actor_get_scale_gravity:
9807 * @self: A #ClutterActor
9809 * Retrieves the scale center as a compass direction. If the scale
9810 * center was specified in pixels or units this will return
9811 * %CLUTTER_GRAVITY_NONE.
9813 * Return value: the scale gravity
9818 clutter_actor_get_scale_gravity (ClutterActor *self)
9820 const ClutterTransformInfo *info;
9822 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9824 info = _clutter_actor_get_transform_info_or_defaults (self);
9826 return clutter_anchor_coord_get_gravity (&info->scale_center);
9830 clutter_actor_set_opacity_internal (ClutterActor *self,
9833 ClutterActorPrivate *priv = self->priv;
9835 if (priv->opacity != opacity)
9837 priv->opacity = opacity;
9839 /* Queue a redraw from the flatten effect so that it can use
9840 its cached image if available instead of having to redraw the
9841 actual actor. If it doesn't end up using the FBO then the
9842 effect is still able to continue the paint anyway. If there
9843 is no flatten effect yet then this is equivalent to queueing
9845 _clutter_actor_queue_redraw_full (self,
9848 priv->flatten_effect);
9850 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9855 * clutter_actor_set_opacity:
9856 * @self: A #ClutterActor
9857 * @opacity: New opacity value for the actor.
9859 * Sets the actor's opacity, with zero being completely transparent and
9860 * 255 (0xff) being fully opaque.
9862 * The #ClutterActor:opacity property is animatable.
9865 clutter_actor_set_opacity (ClutterActor *self,
9868 ClutterActorPrivate *priv;
9870 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9874 if (clutter_actor_get_easing_duration (self) != 0)
9876 ClutterTransition *transition;
9878 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9879 if (transition == NULL)
9881 transition = _clutter_actor_create_transition (self,
9882 obj_props[PROP_OPACITY],
9885 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9888 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9890 clutter_actor_queue_redraw (self);
9893 clutter_actor_set_opacity_internal (self, opacity);
9897 * clutter_actor_get_paint_opacity_internal:
9898 * @self: a #ClutterActor
9900 * Retrieves the absolute opacity of the actor, as it appears on the stage
9902 * This function does not do type checks
9904 * Return value: the absolute opacity of the actor
9907 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9909 ClutterActorPrivate *priv = self->priv;
9910 ClutterActor *parent;
9912 /* override the top-level opacity to always be 255; even in
9913 * case of ClutterStage:use-alpha being TRUE we want the rest
9914 * of the scene to be painted
9916 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9919 if (priv->opacity_override >= 0)
9920 return priv->opacity_override;
9922 parent = priv->parent;
9924 /* Factor in the actual actors opacity with parents */
9927 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9929 if (opacity != 0xff)
9930 return (opacity * priv->opacity) / 0xff;
9933 return priv->opacity;
9938 * clutter_actor_get_paint_opacity:
9939 * @self: A #ClutterActor
9941 * Retrieves the absolute opacity of the actor, as it appears on the stage.
9943 * This function traverses the hierarchy chain and composites the opacity of
9944 * the actor with that of its parents.
9946 * This function is intended for subclasses to use in the paint virtual
9947 * function, to paint themselves with the correct opacity.
9949 * Return value: The actor opacity value.
9954 clutter_actor_get_paint_opacity (ClutterActor *self)
9956 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9958 return clutter_actor_get_paint_opacity_internal (self);
9962 * clutter_actor_get_opacity:
9963 * @self: a #ClutterActor
9965 * Retrieves the opacity value of an actor, as set by
9966 * clutter_actor_set_opacity().
9968 * For retrieving the absolute opacity of the actor inside a paint
9969 * virtual function, see clutter_actor_get_paint_opacity().
9971 * Return value: the opacity of the actor
9974 clutter_actor_get_opacity (ClutterActor *self)
9976 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9978 return self->priv->opacity;
9982 * clutter_actor_set_offscreen_redirect:
9983 * @self: A #ClutterActor
9984 * @redirect: New offscreen redirect flags for the actor.
9986 * Defines the circumstances where the actor should be redirected into
9987 * an offscreen image. The offscreen image is used to flatten the
9988 * actor into a single image while painting for two main reasons.
9989 * Firstly, when the actor is painted a second time without any of its
9990 * contents changing it can simply repaint the cached image without
9991 * descending further down the actor hierarchy. Secondly, it will make
9992 * the opacity look correct even if there are overlapping primitives
9995 * Caching the actor could in some cases be a performance win and in
9996 * some cases be a performance lose so it is important to determine
9997 * which value is right for an actor before modifying this value. For
9998 * example, there is never any reason to flatten an actor that is just
9999 * a single texture (such as a #ClutterTexture) because it is
10000 * effectively already cached in an image so the offscreen would be
10001 * redundant. Also if the actor contains primitives that are far apart
10002 * with a large transparent area in the middle (such as a large
10003 * CluterGroup with a small actor in the top left and a small actor in
10004 * the bottom right) then the cached image will contain the entire
10005 * image of the large area and the paint will waste time blending all
10006 * of the transparent pixels in the middle.
10008 * The default method of implementing opacity on a container simply
10009 * forwards on the opacity to all of the children. If the children are
10010 * overlapping then it will appear as if they are two separate glassy
10011 * objects and there will be a break in the color where they
10012 * overlap. By redirecting to an offscreen buffer it will be as if the
10013 * two opaque objects are combined into one and then made transparent
10014 * which is usually what is expected.
10016 * The image below demonstrates the difference between redirecting and
10017 * not. The image shows two Clutter groups, each containing a red and
10018 * a green rectangle which overlap. The opacity on the group is set to
10019 * 128 (which is 50%). When the offscreen redirect is not used, the
10020 * red rectangle can be seen through the blue rectangle as if the two
10021 * rectangles were separately transparent. When the redirect is used
10022 * the group as a whole is transparent instead so the red rectangle is
10023 * not visible where they overlap.
10025 * <figure id="offscreen-redirect">
10026 * <title>Sample of using an offscreen redirect for transparency</title>
10027 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10030 * The default value for this property is 0, so we effectively will
10031 * never redirect an actor offscreen by default. This means that there
10032 * are times that transparent actors may look glassy as described
10033 * above. The reason this is the default is because there is a
10034 * performance trade off between quality and performance here. In many
10035 * cases the default form of glassy opacity looks good enough, but if
10036 * it's not you will need to set the
10037 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10038 * redirection for opacity.
10040 * Custom actors that don't contain any overlapping primitives are
10041 * recommended to override the has_overlaps() virtual to return %FALSE
10042 * for maximum efficiency.
10047 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10048 ClutterOffscreenRedirect redirect)
10050 ClutterActorPrivate *priv;
10052 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10056 if (priv->offscreen_redirect != redirect)
10058 priv->offscreen_redirect = redirect;
10060 /* Queue a redraw from the effect so that it can use its cached
10061 image if available instead of having to redraw the actual
10062 actor. If it doesn't end up using the FBO then the effect is
10063 still able to continue the paint anyway. If there is no
10064 effect then this is equivalent to queuing a full redraw */
10065 _clutter_actor_queue_redraw_full (self,
10068 priv->flatten_effect);
10070 g_object_notify_by_pspec (G_OBJECT (self),
10071 obj_props[PROP_OFFSCREEN_REDIRECT]);
10076 * clutter_actor_get_offscreen_redirect:
10077 * @self: a #ClutterActor
10079 * Retrieves whether to redirect the actor to an offscreen buffer, as
10080 * set by clutter_actor_set_offscreen_redirect().
10082 * Return value: the value of the offscreen-redirect property of the actor
10086 ClutterOffscreenRedirect
10087 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10089 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10091 return self->priv->offscreen_redirect;
10095 * clutter_actor_set_name:
10096 * @self: A #ClutterActor
10097 * @name: Textual tag to apply to actor
10099 * Sets the given name to @self. The name can be used to identify
10103 clutter_actor_set_name (ClutterActor *self,
10106 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10108 g_free (self->priv->name);
10109 self->priv->name = g_strdup (name);
10111 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10115 * clutter_actor_get_name:
10116 * @self: A #ClutterActor
10118 * Retrieves the name of @self.
10120 * Return value: the name of the actor, or %NULL. The returned string is
10121 * owned by the actor and should not be modified or freed.
10124 clutter_actor_get_name (ClutterActor *self)
10126 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10128 return self->priv->name;
10132 * clutter_actor_get_gid:
10133 * @self: A #ClutterActor
10135 * Retrieves the unique id for @self.
10137 * Return value: Globally unique value for this object instance.
10141 * Deprecated: 1.8: The id is not used any longer.
10144 clutter_actor_get_gid (ClutterActor *self)
10146 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10148 return self->priv->id;
10152 clutter_actor_set_depth_internal (ClutterActor *self,
10155 ClutterTransformInfo *info;
10157 info = _clutter_actor_get_transform_info (self);
10159 if (info->depth != depth)
10161 /* Sets Z value - XXX 2.0: should we invert? */
10162 info->depth = depth;
10164 self->priv->transform_valid = FALSE;
10166 /* FIXME - remove this crap; sadly, there are still containers
10167 * in Clutter that depend on this utter brain damage
10169 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10171 clutter_actor_queue_redraw (self);
10173 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10178 * clutter_actor_set_depth:
10179 * @self: a #ClutterActor
10182 * Sets the Z coordinate of @self to @depth.
10184 * The unit used by @depth is dependant on the perspective setup. See
10185 * also clutter_stage_set_perspective().
10188 clutter_actor_set_depth (ClutterActor *self,
10191 const ClutterTransformInfo *tinfo;
10193 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10195 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10197 if (clutter_actor_get_easing_duration (self) != 0)
10199 ClutterTransition *transition;
10201 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10202 if (transition == NULL)
10204 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10207 clutter_timeline_start (CLUTTER_TIMELINE (transition));
10210 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10212 clutter_actor_queue_redraw (self);
10215 clutter_actor_set_depth_internal (self, depth);
10219 * clutter_actor_get_depth:
10220 * @self: a #ClutterActor
10222 * Retrieves the depth of @self.
10224 * Return value: the depth of the actor
10227 clutter_actor_get_depth (ClutterActor *self)
10229 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10231 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10235 * clutter_actor_set_rotation:
10236 * @self: a #ClutterActor
10237 * @axis: the axis of rotation
10238 * @angle: the angle of rotation
10239 * @x: X coordinate of the rotation center
10240 * @y: Y coordinate of the rotation center
10241 * @z: Z coordinate of the rotation center
10243 * Sets the rotation angle of @self around the given axis.
10245 * The rotation center coordinates used depend on the value of @axis:
10247 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10248 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10249 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10252 * The rotation coordinates are relative to the anchor point of the
10253 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10254 * point is set, the upper left corner is assumed as the origin.
10259 clutter_actor_set_rotation (ClutterActor *self,
10260 ClutterRotateAxis axis,
10268 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10274 g_object_freeze_notify (G_OBJECT (self));
10276 clutter_actor_set_rotation_angle (self, axis, angle);
10277 clutter_actor_set_rotation_center_internal (self, axis, &v);
10279 g_object_thaw_notify (G_OBJECT (self));
10283 * clutter_actor_set_z_rotation_from_gravity:
10284 * @self: a #ClutterActor
10285 * @angle: the angle of rotation
10286 * @gravity: the center point of the rotation
10288 * Sets the rotation angle of @self around the Z axis using the center
10289 * point specified as a compass point. For example to rotate such that
10290 * the center of the actor remains static you can use
10291 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10292 * will move accordingly.
10297 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10299 ClutterGravity gravity)
10301 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10303 if (gravity == CLUTTER_GRAVITY_NONE)
10304 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10307 GObject *obj = G_OBJECT (self);
10308 ClutterTransformInfo *info;
10310 info = _clutter_actor_get_transform_info (self);
10312 g_object_freeze_notify (obj);
10314 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10316 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10317 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10318 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10320 g_object_thaw_notify (obj);
10325 * clutter_actor_get_rotation:
10326 * @self: a #ClutterActor
10327 * @axis: the axis of rotation
10328 * @x: (out): return value for the X coordinate of the center of rotation
10329 * @y: (out): return value for the Y coordinate of the center of rotation
10330 * @z: (out): return value for the Z coordinate of the center of rotation
10332 * Retrieves the angle and center of rotation on the given axis,
10333 * set using clutter_actor_set_rotation().
10335 * Return value: the angle of rotation
10340 clutter_actor_get_rotation (ClutterActor *self,
10341 ClutterRotateAxis axis,
10346 const ClutterTransformInfo *info;
10347 const AnchorCoord *anchor_coord;
10348 gdouble retval = 0;
10350 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10352 info = _clutter_actor_get_transform_info_or_defaults (self);
10356 case CLUTTER_X_AXIS:
10357 anchor_coord = &info->rx_center;
10358 retval = info->rx_angle;
10361 case CLUTTER_Y_AXIS:
10362 anchor_coord = &info->ry_center;
10363 retval = info->ry_angle;
10366 case CLUTTER_Z_AXIS:
10367 anchor_coord = &info->rz_center;
10368 retval = info->rz_angle;
10372 anchor_coord = NULL;
10377 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10383 * clutter_actor_get_z_rotation_gravity:
10384 * @self: A #ClutterActor
10386 * Retrieves the center for the rotation around the Z axis as a
10387 * compass direction. If the center was specified in pixels or units
10388 * this will return %CLUTTER_GRAVITY_NONE.
10390 * Return value: the Z rotation center
10395 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10397 const ClutterTransformInfo *info;
10399 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10401 info = _clutter_actor_get_transform_info_or_defaults (self);
10403 return clutter_anchor_coord_get_gravity (&info->rz_center);
10407 * clutter_actor_set_clip:
10408 * @self: A #ClutterActor
10409 * @xoff: X offset of the clip rectangle
10410 * @yoff: Y offset of the clip rectangle
10411 * @width: Width of the clip rectangle
10412 * @height: Height of the clip rectangle
10414 * Sets clip area for @self. The clip area is always computed from the
10415 * upper left corner of the actor, even if the anchor point is set
10421 clutter_actor_set_clip (ClutterActor *self,
10427 ClutterActorPrivate *priv;
10429 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10433 if (priv->has_clip &&
10434 priv->clip.x == xoff &&
10435 priv->clip.y == yoff &&
10436 priv->clip.width == width &&
10437 priv->clip.height == height)
10440 priv->clip.x = xoff;
10441 priv->clip.y = yoff;
10442 priv->clip.width = width;
10443 priv->clip.height = height;
10445 priv->has_clip = TRUE;
10447 clutter_actor_queue_redraw (self);
10449 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10450 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10454 * clutter_actor_remove_clip:
10455 * @self: A #ClutterActor
10457 * Removes clip area from @self.
10460 clutter_actor_remove_clip (ClutterActor *self)
10462 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10464 if (!self->priv->has_clip)
10467 self->priv->has_clip = FALSE;
10469 clutter_actor_queue_redraw (self);
10471 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10475 * clutter_actor_has_clip:
10476 * @self: a #ClutterActor
10478 * Determines whether the actor has a clip area set or not.
10480 * Return value: %TRUE if the actor has a clip area set.
10485 clutter_actor_has_clip (ClutterActor *self)
10487 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10489 return self->priv->has_clip;
10493 * clutter_actor_get_clip:
10494 * @self: a #ClutterActor
10495 * @xoff: (out) (allow-none): return location for the X offset of
10496 * the clip rectangle, or %NULL
10497 * @yoff: (out) (allow-none): return location for the Y offset of
10498 * the clip rectangle, or %NULL
10499 * @width: (out) (allow-none): return location for the width of
10500 * the clip rectangle, or %NULL
10501 * @height: (out) (allow-none): return location for the height of
10502 * the clip rectangle, or %NULL
10504 * Gets the clip area for @self, if any is set
10509 clutter_actor_get_clip (ClutterActor *self,
10515 ClutterActorPrivate *priv;
10517 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10521 if (!priv->has_clip)
10525 *xoff = priv->clip.x;
10528 *yoff = priv->clip.y;
10531 *width = priv->clip.width;
10533 if (height != NULL)
10534 *height = priv->clip.height;
10538 * clutter_actor_get_children:
10539 * @self: a #ClutterActor
10541 * Retrieves the list of children of @self.
10543 * Return value: (transfer container) (element-type ClutterActor): A newly
10544 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10550 clutter_actor_get_children (ClutterActor *self)
10552 ClutterActor *iter;
10555 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10557 /* we walk the list backward so that we can use prepend(),
10560 for (iter = self->priv->last_child, res = NULL;
10562 iter = iter->priv->prev_sibling)
10564 res = g_list_prepend (res, iter);
10571 * insert_child_at_depth:
10572 * @self: a #ClutterActor
10573 * @child: a #ClutterActor
10575 * Inserts @child inside the list of children held by @self, using
10576 * the depth as the insertion criteria.
10578 * This sadly makes the insertion not O(1), but we can keep the
10579 * list sorted so that the painters algorithm we use for painting
10580 * the children will work correctly.
10583 insert_child_at_depth (ClutterActor *self,
10584 ClutterActor *child,
10585 gpointer dummy G_GNUC_UNUSED)
10587 ClutterActor *iter;
10590 child->priv->parent = self;
10593 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10595 /* special-case the first child */
10596 if (self->priv->n_children == 0)
10598 self->priv->first_child = child;
10599 self->priv->last_child = child;
10601 child->priv->next_sibling = NULL;
10602 child->priv->prev_sibling = NULL;
10607 /* Find the right place to insert the child so that it will still be
10608 sorted and the child will be after all of the actors at the same
10610 for (iter = self->priv->first_child;
10612 iter = iter->priv->next_sibling)
10617 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10619 if (iter_depth > child_depth)
10625 ClutterActor *tmp = iter->priv->prev_sibling;
10628 tmp->priv->next_sibling = child;
10630 /* Insert the node before the found one */
10631 child->priv->prev_sibling = iter->priv->prev_sibling;
10632 child->priv->next_sibling = iter;
10633 iter->priv->prev_sibling = child;
10637 ClutterActor *tmp = self->priv->last_child;
10640 tmp->priv->next_sibling = child;
10642 /* insert the node at the end of the list */
10643 child->priv->prev_sibling = self->priv->last_child;
10644 child->priv->next_sibling = NULL;
10647 if (child->priv->prev_sibling == NULL)
10648 self->priv->first_child = child;
10650 if (child->priv->next_sibling == NULL)
10651 self->priv->last_child = child;
10655 insert_child_at_index (ClutterActor *self,
10656 ClutterActor *child,
10659 gint index_ = GPOINTER_TO_INT (data_);
10661 child->priv->parent = self;
10665 ClutterActor *tmp = self->priv->first_child;
10668 tmp->priv->prev_sibling = child;
10670 child->priv->prev_sibling = NULL;
10671 child->priv->next_sibling = tmp;
10673 else if (index_ < 0 || index_ >= self->priv->n_children)
10675 ClutterActor *tmp = self->priv->last_child;
10678 tmp->priv->next_sibling = child;
10680 child->priv->prev_sibling = tmp;
10681 child->priv->next_sibling = NULL;
10685 ClutterActor *iter;
10688 for (iter = self->priv->first_child, i = 0;
10690 iter = iter->priv->next_sibling, i += 1)
10694 ClutterActor *tmp = iter->priv->prev_sibling;
10696 child->priv->prev_sibling = tmp;
10697 child->priv->next_sibling = iter;
10699 iter->priv->prev_sibling = child;
10702 tmp->priv->next_sibling = child;
10709 if (child->priv->prev_sibling == NULL)
10710 self->priv->first_child = child;
10712 if (child->priv->next_sibling == NULL)
10713 self->priv->last_child = child;
10717 insert_child_above (ClutterActor *self,
10718 ClutterActor *child,
10721 ClutterActor *sibling = data;
10723 child->priv->parent = self;
10725 if (sibling == NULL)
10726 sibling = self->priv->last_child;
10728 child->priv->prev_sibling = sibling;
10730 if (sibling != NULL)
10732 ClutterActor *tmp = sibling->priv->next_sibling;
10734 child->priv->next_sibling = tmp;
10737 tmp->priv->prev_sibling = child;
10739 sibling->priv->next_sibling = child;
10742 child->priv->next_sibling = NULL;
10744 if (child->priv->prev_sibling == NULL)
10745 self->priv->first_child = child;
10747 if (child->priv->next_sibling == NULL)
10748 self->priv->last_child = child;
10752 insert_child_below (ClutterActor *self,
10753 ClutterActor *child,
10756 ClutterActor *sibling = data;
10758 child->priv->parent = self;
10760 if (sibling == NULL)
10761 sibling = self->priv->first_child;
10763 child->priv->next_sibling = sibling;
10765 if (sibling != NULL)
10767 ClutterActor *tmp = sibling->priv->prev_sibling;
10769 child->priv->prev_sibling = tmp;
10772 tmp->priv->next_sibling = child;
10774 sibling->priv->prev_sibling = child;
10777 child->priv->prev_sibling = NULL;
10779 if (child->priv->prev_sibling == NULL)
10780 self->priv->first_child = child;
10782 if (child->priv->next_sibling == NULL)
10783 self->priv->last_child = child;
10786 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10787 ClutterActor *child,
10791 ADD_CHILD_CREATE_META = 1 << 0,
10792 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10793 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10794 ADD_CHILD_CHECK_STATE = 1 << 3,
10795 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10797 /* default flags for public API */
10798 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10799 ADD_CHILD_EMIT_PARENT_SET |
10800 ADD_CHILD_EMIT_ACTOR_ADDED |
10801 ADD_CHILD_CHECK_STATE |
10802 ADD_CHILD_NOTIFY_FIRST_LAST,
10804 /* flags for legacy/deprecated API */
10805 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10806 ADD_CHILD_CHECK_STATE |
10807 ADD_CHILD_NOTIFY_FIRST_LAST
10808 } ClutterActorAddChildFlags;
10811 * clutter_actor_add_child_internal:
10812 * @self: a #ClutterActor
10813 * @child: a #ClutterActor
10814 * @flags: control flags for actions
10815 * @add_func: delegate function
10816 * @data: (closure): data to pass to @add_func
10818 * Adds @child to the list of children of @self.
10820 * The actual insertion inside the list is delegated to @add_func: this
10821 * function will just set up the state, perform basic checks, and emit
10824 * The @flags argument is used to perform additional operations.
10827 clutter_actor_add_child_internal (ClutterActor *self,
10828 ClutterActor *child,
10829 ClutterActorAddChildFlags flags,
10830 ClutterActorAddChildFunc add_func,
10833 ClutterTextDirection text_dir;
10834 gboolean create_meta;
10835 gboolean emit_parent_set, emit_actor_added;
10836 gboolean check_state;
10837 gboolean notify_first_last;
10838 ClutterActor *old_first_child, *old_last_child;
10840 if (child->priv->parent != NULL)
10842 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10843 "use clutter_actor_remove_child() first.",
10844 _clutter_actor_get_debug_name (child),
10845 _clutter_actor_get_debug_name (child->priv->parent));
10849 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10851 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10852 "a child of another actor.",
10853 _clutter_actor_get_debug_name (child));
10858 /* XXX - this check disallows calling methods that change the stacking
10859 * order within the destruction sequence, by triggering a critical
10860 * warning first, and leaving the actor in an undefined state, which
10861 * then ends up being caught by an assertion.
10863 * the reproducible sequence is:
10865 * - actor gets destroyed;
10866 * - another actor, linked to the first, will try to change the
10867 * stacking order of the first actor;
10868 * - changing the stacking order is a composite operation composed
10869 * by the following steps:
10870 * 1. ref() the child;
10871 * 2. remove_child_internal(), which removes the reference;
10872 * 3. add_child_internal(), which adds a reference;
10873 * - the state of the actor is not changed between (2) and (3), as
10874 * it could be an expensive recomputation;
10875 * - if (3) bails out, then the actor is in an undefined state, but
10877 * - the destruction sequence terminates, but the actor is unparented
10878 * while its state indicates being parented instead.
10879 * - assertion failure.
10881 * the obvious fix would be to decompose each set_child_*_sibling()
10882 * method into proper remove_child()/add_child(), with state validation;
10883 * this may cause excessive work, though, and trigger a cascade of other
10884 * bugs in code that assumes that a change in the stacking order is an
10885 * atomic operation.
10887 * another potential fix is to just remove this check here, and let
10888 * code doing stacking order changes inside the destruction sequence
10889 * of an actor continue doing the work.
10891 * the third fix is to silently bail out early from every
10892 * set_child_*_sibling() and set_child_at_index() method, and avoid
10895 * I have a preference for the second solution, since it involves the
10896 * least amount of work, and the least amount of code duplication.
10898 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10900 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10902 g_warning ("The actor '%s' is currently being destroyed, and "
10903 "cannot be added as a child of another actor.",
10904 _clutter_actor_get_debug_name (child));
10909 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10910 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10911 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10912 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10913 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10915 old_first_child = self->priv->first_child;
10916 old_last_child = self->priv->last_child;
10918 g_object_freeze_notify (G_OBJECT (self));
10921 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10923 g_object_ref_sink (child);
10924 child->priv->parent = NULL;
10925 child->priv->next_sibling = NULL;
10926 child->priv->prev_sibling = NULL;
10928 /* delegate the actual insertion */
10929 add_func (self, child, data);
10931 g_assert (child->priv->parent == self);
10933 self->priv->n_children += 1;
10935 self->priv->age += 1;
10937 /* if push_internal() has been called then we automatically set
10938 * the flag on the actor
10940 if (self->priv->internal_child)
10941 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10943 /* clutter_actor_reparent() will emit ::parent-set for us */
10944 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10945 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10949 /* If parent is mapped or realized, we need to also be mapped or
10950 * realized once we're inside the parent.
10952 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10954 /* propagate the parent's text direction to the child */
10955 text_dir = clutter_actor_get_text_direction (self);
10956 clutter_actor_set_text_direction (child, text_dir);
10959 if (child->priv->show_on_set_parent)
10960 clutter_actor_show (child);
10962 if (CLUTTER_ACTOR_IS_MAPPED (child))
10963 clutter_actor_queue_redraw (child);
10965 /* maintain the invariant that if an actor needs layout,
10966 * its parents do as well
10968 if (child->priv->needs_width_request ||
10969 child->priv->needs_height_request ||
10970 child->priv->needs_allocation)
10972 /* we work around the short-circuiting we do
10973 * in clutter_actor_queue_relayout() since we
10974 * want to force a relayout
10976 child->priv->needs_width_request = TRUE;
10977 child->priv->needs_height_request = TRUE;
10978 child->priv->needs_allocation = TRUE;
10980 clutter_actor_queue_relayout (child->priv->parent);
10983 if (emit_actor_added)
10984 g_signal_emit_by_name (self, "actor-added", child);
10986 if (notify_first_last)
10988 if (old_first_child != self->priv->first_child)
10989 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10991 if (old_last_child != self->priv->last_child)
10992 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10995 g_object_thaw_notify (G_OBJECT (self));
10999 * clutter_actor_add_child:
11000 * @self: a #ClutterActor
11001 * @child: a #ClutterActor
11003 * Adds @child to the children of @self.
11005 * This function will acquire a reference on @child that will only
11006 * be released when calling clutter_actor_remove_child().
11008 * This function will take into consideration the #ClutterActor:depth
11009 * of @child, and will keep the list of children sorted.
11011 * This function will emit the #ClutterContainer::actor-added signal
11017 clutter_actor_add_child (ClutterActor *self,
11018 ClutterActor *child)
11020 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11021 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11022 g_return_if_fail (self != child);
11023 g_return_if_fail (child->priv->parent == NULL);
11025 clutter_actor_add_child_internal (self, child,
11026 ADD_CHILD_DEFAULT_FLAGS,
11027 insert_child_at_depth,
11032 * clutter_actor_insert_child_at_index:
11033 * @self: a #ClutterActor
11034 * @child: a #ClutterActor
11035 * @index_: the index
11037 * Inserts @child into the list of children of @self, using the
11038 * given @index_. If @index_ is greater than the number of children
11039 * in @self, or is less than 0, then the new child is added at the end.
11041 * This function will acquire a reference on @child that will only
11042 * be released when calling clutter_actor_remove_child().
11044 * This function will not take into consideration the #ClutterActor:depth
11047 * This function will emit the #ClutterContainer::actor-added signal
11053 clutter_actor_insert_child_at_index (ClutterActor *self,
11054 ClutterActor *child,
11057 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11058 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11059 g_return_if_fail (self != child);
11060 g_return_if_fail (child->priv->parent == NULL);
11062 clutter_actor_add_child_internal (self, child,
11063 ADD_CHILD_DEFAULT_FLAGS,
11064 insert_child_at_index,
11065 GINT_TO_POINTER (index_));
11069 * clutter_actor_insert_child_above:
11070 * @self: a #ClutterActor
11071 * @child: a #ClutterActor
11072 * @sibling: (allow-none): a child of @self, or %NULL
11074 * Inserts @child into the list of children of @self, above another
11075 * child of @self or, if @sibling is %NULL, above all the children
11078 * This function will acquire a reference on @child that will only
11079 * be released when calling clutter_actor_remove_child().
11081 * This function will not take into consideration the #ClutterActor:depth
11084 * This function will emit the #ClutterContainer::actor-added signal
11090 clutter_actor_insert_child_above (ClutterActor *self,
11091 ClutterActor *child,
11092 ClutterActor *sibling)
11094 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11095 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11096 g_return_if_fail (self != child);
11097 g_return_if_fail (child != sibling);
11098 g_return_if_fail (child->priv->parent == NULL);
11099 g_return_if_fail (sibling == NULL ||
11100 (CLUTTER_IS_ACTOR (sibling) &&
11101 sibling->priv->parent == self));
11103 clutter_actor_add_child_internal (self, child,
11104 ADD_CHILD_DEFAULT_FLAGS,
11105 insert_child_above,
11110 * clutter_actor_insert_child_below:
11111 * @self: a #ClutterActor
11112 * @child: a #ClutterActor
11113 * @sibling: (allow-none): a child of @self, or %NULL
11115 * Inserts @child into the list of children of @self, below another
11116 * child of @self or, if @sibling is %NULL, below all the children
11119 * This function will acquire a reference on @child that will only
11120 * be released when calling clutter_actor_remove_child().
11122 * This function will not take into consideration the #ClutterActor:depth
11125 * This function will emit the #ClutterContainer::actor-added signal
11131 clutter_actor_insert_child_below (ClutterActor *self,
11132 ClutterActor *child,
11133 ClutterActor *sibling)
11135 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11136 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11137 g_return_if_fail (self != child);
11138 g_return_if_fail (child != sibling);
11139 g_return_if_fail (child->priv->parent == NULL);
11140 g_return_if_fail (sibling == NULL ||
11141 (CLUTTER_IS_ACTOR (sibling) &&
11142 sibling->priv->parent == self));
11144 clutter_actor_add_child_internal (self, child,
11145 ADD_CHILD_DEFAULT_FLAGS,
11146 insert_child_below,
11151 * clutter_actor_set_parent:
11152 * @self: A #ClutterActor
11153 * @parent: A new #ClutterActor parent
11155 * Sets the parent of @self to @parent.
11157 * This function will result in @parent acquiring a reference on @self,
11158 * eventually by sinking its floating reference first. The reference
11159 * will be released by clutter_actor_unparent().
11161 * This function should only be called by legacy #ClutterActor<!-- -->s
11162 * implementing the #ClutterContainer interface.
11164 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11167 clutter_actor_set_parent (ClutterActor *self,
11168 ClutterActor *parent)
11170 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11171 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11172 g_return_if_fail (self != parent);
11173 g_return_if_fail (self->priv->parent == NULL);
11175 /* as this function will be called inside ClutterContainer::add
11176 * implementations or when building up a composite actor, we have
11177 * to preserve the old behaviour, and not create child meta or
11178 * emit the ::actor-added signal, to avoid recursion or double
11181 clutter_actor_add_child_internal (parent, self,
11182 ADD_CHILD_LEGACY_FLAGS,
11183 insert_child_at_depth,
11188 * clutter_actor_get_parent:
11189 * @self: A #ClutterActor
11191 * Retrieves the parent of @self.
11193 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11194 * if no parent is set
11197 clutter_actor_get_parent (ClutterActor *self)
11199 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11201 return self->priv->parent;
11205 * clutter_actor_get_paint_visibility:
11206 * @self: A #ClutterActor
11208 * Retrieves the 'paint' visibility of an actor recursively checking for non
11211 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11213 * Return Value: %TRUE if the actor is visibile and will be painted.
11218 clutter_actor_get_paint_visibility (ClutterActor *actor)
11220 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11222 return CLUTTER_ACTOR_IS_MAPPED (actor);
11226 * clutter_actor_remove_child:
11227 * @self: a #ClutterActor
11228 * @child: a #ClutterActor
11230 * Removes @child from the children of @self.
11232 * This function will release the reference added by
11233 * clutter_actor_add_child(), so if you want to keep using @child
11234 * you will have to acquire a referenced on it before calling this
11237 * This function will emit the #ClutterContainer::actor-removed
11243 clutter_actor_remove_child (ClutterActor *self,
11244 ClutterActor *child)
11246 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11247 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11248 g_return_if_fail (self != child);
11249 g_return_if_fail (child->priv->parent != NULL);
11250 g_return_if_fail (child->priv->parent == self);
11252 clutter_actor_remove_child_internal (self, child,
11253 REMOVE_CHILD_DEFAULT_FLAGS);
11257 * clutter_actor_remove_all_children:
11258 * @self: a #ClutterActor
11260 * Removes all children of @self.
11262 * This function releases the reference added by inserting a child actor
11263 * in the list of children of @self.
11265 * If the reference count of a child drops to zero, the child will be
11266 * destroyed. If you want to ensure the destruction of all the children
11267 * of @self, use clutter_actor_destroy_all_children().
11272 clutter_actor_remove_all_children (ClutterActor *self)
11274 ClutterActorIter iter;
11276 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11278 if (self->priv->n_children == 0)
11281 g_object_freeze_notify (G_OBJECT (self));
11283 clutter_actor_iter_init (&iter, self);
11284 while (clutter_actor_iter_next (&iter, NULL))
11285 clutter_actor_iter_remove (&iter);
11287 g_object_thaw_notify (G_OBJECT (self));
11290 g_assert (self->priv->first_child == NULL);
11291 g_assert (self->priv->last_child == NULL);
11292 g_assert (self->priv->n_children == 0);
11296 * clutter_actor_destroy_all_children:
11297 * @self: a #ClutterActor
11299 * Destroys all children of @self.
11301 * This function releases the reference added by inserting a child
11302 * actor in the list of children of @self, and ensures that the
11303 * #ClutterActor::destroy signal is emitted on each child of the
11306 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11307 * when its reference count drops to 0; the default handler of the
11308 * #ClutterActor::destroy signal will destroy all the children of an
11309 * actor. This function ensures that all children are destroyed, instead
11310 * of just removed from @self, unlike clutter_actor_remove_all_children()
11311 * which will merely release the reference and remove each child.
11313 * Unless you acquired an additional reference on each child of @self
11314 * prior to calling clutter_actor_remove_all_children() and want to reuse
11315 * the actors, you should use clutter_actor_destroy_all_children() in
11316 * order to make sure that children are destroyed and signal handlers
11317 * are disconnected even in cases where circular references prevent this
11318 * from automatically happening through reference counting alone.
11323 clutter_actor_destroy_all_children (ClutterActor *self)
11325 ClutterActorIter iter;
11327 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11329 if (self->priv->n_children == 0)
11332 g_object_freeze_notify (G_OBJECT (self));
11334 clutter_actor_iter_init (&iter, self);
11335 while (clutter_actor_iter_next (&iter, NULL))
11336 clutter_actor_iter_destroy (&iter);
11338 g_object_thaw_notify (G_OBJECT (self));
11341 g_assert (self->priv->first_child == NULL);
11342 g_assert (self->priv->last_child == NULL);
11343 g_assert (self->priv->n_children == 0);
11346 typedef struct _InsertBetweenData {
11347 ClutterActor *prev_sibling;
11348 ClutterActor *next_sibling;
11349 } InsertBetweenData;
11352 insert_child_between (ClutterActor *self,
11353 ClutterActor *child,
11356 InsertBetweenData *data = data_;
11357 ClutterActor *prev_sibling = data->prev_sibling;
11358 ClutterActor *next_sibling = data->next_sibling;
11360 child->priv->parent = self;
11361 child->priv->prev_sibling = prev_sibling;
11362 child->priv->next_sibling = next_sibling;
11364 if (prev_sibling != NULL)
11365 prev_sibling->priv->next_sibling = child;
11367 if (next_sibling != NULL)
11368 next_sibling->priv->prev_sibling = child;
11370 if (child->priv->prev_sibling == NULL)
11371 self->priv->first_child = child;
11373 if (child->priv->next_sibling == NULL)
11374 self->priv->last_child = child;
11378 * clutter_actor_replace_child:
11379 * @self: a #ClutterActor
11380 * @old_child: the child of @self to replace
11381 * @new_child: the #ClutterActor to replace @old_child
11383 * Replaces @old_child with @new_child in the list of children of @self.
11388 clutter_actor_replace_child (ClutterActor *self,
11389 ClutterActor *old_child,
11390 ClutterActor *new_child)
11392 ClutterActor *prev_sibling, *next_sibling;
11393 InsertBetweenData clos;
11395 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11396 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11397 g_return_if_fail (old_child->priv->parent == self);
11398 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11399 g_return_if_fail (old_child != new_child);
11400 g_return_if_fail (new_child != self);
11401 g_return_if_fail (new_child->priv->parent == NULL);
11403 prev_sibling = old_child->priv->prev_sibling;
11404 next_sibling = old_child->priv->next_sibling;
11405 clutter_actor_remove_child_internal (self, old_child,
11406 REMOVE_CHILD_DEFAULT_FLAGS);
11408 clos.prev_sibling = prev_sibling;
11409 clos.next_sibling = next_sibling;
11410 clutter_actor_add_child_internal (self, new_child,
11411 ADD_CHILD_DEFAULT_FLAGS,
11412 insert_child_between,
11417 * clutter_actor_unparent:
11418 * @self: a #ClutterActor
11420 * Removes the parent of @self.
11422 * This will cause the parent of @self to release the reference
11423 * acquired when calling clutter_actor_set_parent(), so if you
11424 * want to keep @self you will have to acquire a reference of
11425 * your own, through g_object_ref().
11427 * This function should only be called by legacy #ClutterActor<!-- -->s
11428 * implementing the #ClutterContainer interface.
11432 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11435 clutter_actor_unparent (ClutterActor *self)
11437 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11439 if (self->priv->parent == NULL)
11442 clutter_actor_remove_child_internal (self->priv->parent, self,
11443 REMOVE_CHILD_LEGACY_FLAGS);
11447 * clutter_actor_reparent:
11448 * @self: a #ClutterActor
11449 * @new_parent: the new #ClutterActor parent
11451 * Resets the parent actor of @self.
11453 * This function is logically equivalent to calling clutter_actor_unparent()
11454 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11455 * ensures the child is not finalized when unparented, and emits the
11456 * #ClutterActor::parent-set signal only once.
11458 * In reality, calling this function is less useful than it sounds, as some
11459 * application code may rely on changes in the intermediate state between
11460 * removal and addition of the actor from its old parent to the @new_parent.
11461 * Thus, it is strongly encouraged to avoid using this function in application
11466 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11467 * clutter_actor_add_child() instead; remember to take a reference on
11468 * the actor being removed before calling clutter_actor_remove_child()
11469 * to avoid the reference count dropping to zero and the actor being
11473 clutter_actor_reparent (ClutterActor *self,
11474 ClutterActor *new_parent)
11476 ClutterActorPrivate *priv;
11478 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11479 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11480 g_return_if_fail (self != new_parent);
11482 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11484 g_warning ("Cannot set a parent on a toplevel actor");
11488 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11490 g_warning ("Cannot set a parent currently being destroyed");
11496 if (priv->parent != new_parent)
11498 ClutterActor *old_parent;
11500 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11502 old_parent = priv->parent;
11504 g_object_ref (self);
11506 if (old_parent != NULL)
11508 /* go through the Container implementation if this is a regular
11509 * child and not an internal one
11511 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11513 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11515 /* this will have to call unparent() */
11516 clutter_container_remove_actor (parent, self);
11519 clutter_actor_remove_child_internal (old_parent, self,
11520 REMOVE_CHILD_LEGACY_FLAGS);
11523 /* Note, will call set_parent() */
11524 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11525 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11527 clutter_actor_add_child_internal (new_parent, self,
11528 ADD_CHILD_LEGACY_FLAGS,
11529 insert_child_at_depth,
11532 /* we emit the ::parent-set signal once */
11533 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11535 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11537 /* the IN_REPARENT flag suspends state updates */
11538 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11540 g_object_unref (self);
11545 * clutter_actor_contains:
11546 * @self: A #ClutterActor
11547 * @descendant: A #ClutterActor, possibly contained in @self
11549 * Determines if @descendant is contained inside @self (either as an
11550 * immediate child, or as a deeper descendant). If @self and
11551 * @descendant point to the same actor then it will also return %TRUE.
11553 * Return value: whether @descendent is contained within @self
11558 clutter_actor_contains (ClutterActor *self,
11559 ClutterActor *descendant)
11561 ClutterActor *actor;
11563 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11564 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11566 for (actor = descendant; actor; actor = actor->priv->parent)
11574 * clutter_actor_set_child_above_sibling:
11575 * @self: a #ClutterActor
11576 * @child: a #ClutterActor child of @self
11577 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11579 * Sets @child to be above @sibling in the list of children of @self.
11581 * If @sibling is %NULL, @child will be the new last child of @self.
11583 * This function is logically equivalent to removing @child and using
11584 * clutter_actor_insert_child_above(), but it will not emit signals
11585 * or change state on @child.
11590 clutter_actor_set_child_above_sibling (ClutterActor *self,
11591 ClutterActor *child,
11592 ClutterActor *sibling)
11594 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11595 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11596 g_return_if_fail (child->priv->parent == self);
11597 g_return_if_fail (child != sibling);
11598 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11600 if (sibling != NULL)
11601 g_return_if_fail (sibling->priv->parent == self);
11603 /* we don't want to change the state of child, or emit signals, or
11604 * regenerate ChildMeta instances here, but we still want to follow
11605 * the correct sequence of steps encoded in remove_child() and
11606 * add_child(), so that correctness is ensured, and we only go
11607 * through one known code path.
11609 g_object_ref (child);
11610 clutter_actor_remove_child_internal (self, child, 0);
11611 clutter_actor_add_child_internal (self, child,
11612 ADD_CHILD_NOTIFY_FIRST_LAST,
11613 insert_child_above,
11616 clutter_actor_queue_relayout (self);
11620 * clutter_actor_set_child_below_sibling:
11621 * @self: a #ClutterActor
11622 * @child: a #ClutterActor child of @self
11623 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11625 * Sets @child to be below @sibling in the list of children of @self.
11627 * If @sibling is %NULL, @child will be the new first child of @self.
11629 * This function is logically equivalent to removing @self and using
11630 * clutter_actor_insert_child_below(), but it will not emit signals
11631 * or change state on @child.
11636 clutter_actor_set_child_below_sibling (ClutterActor *self,
11637 ClutterActor *child,
11638 ClutterActor *sibling)
11640 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11641 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11642 g_return_if_fail (child->priv->parent == self);
11643 g_return_if_fail (child != sibling);
11644 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11646 if (sibling != NULL)
11647 g_return_if_fail (sibling->priv->parent == self);
11649 /* see the comment in set_child_above_sibling() */
11650 g_object_ref (child);
11651 clutter_actor_remove_child_internal (self, child, 0);
11652 clutter_actor_add_child_internal (self, child,
11653 ADD_CHILD_NOTIFY_FIRST_LAST,
11654 insert_child_below,
11657 clutter_actor_queue_relayout (self);
11661 * clutter_actor_set_child_at_index:
11662 * @self: a #ClutterActor
11663 * @child: a #ClutterActor child of @self
11664 * @index_: the new index for @child
11666 * Changes the index of @child in the list of children of @self.
11668 * This function is logically equivalent to removing @child and
11669 * calling clutter_actor_insert_child_at_index(), but it will not
11670 * emit signals or change state on @child.
11675 clutter_actor_set_child_at_index (ClutterActor *self,
11676 ClutterActor *child,
11679 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11680 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11681 g_return_if_fail (child->priv->parent == self);
11682 g_return_if_fail (index_ <= self->priv->n_children);
11684 g_object_ref (child);
11685 clutter_actor_remove_child_internal (self, child, 0);
11686 clutter_actor_add_child_internal (self, child,
11687 ADD_CHILD_NOTIFY_FIRST_LAST,
11688 insert_child_at_index,
11689 GINT_TO_POINTER (index_));
11691 clutter_actor_queue_relayout (self);
11695 * clutter_actor_raise:
11696 * @self: A #ClutterActor
11697 * @below: (allow-none): A #ClutterActor to raise above.
11699 * Puts @self above @below.
11701 * Both actors must have the same parent, and the parent must implement
11702 * the #ClutterContainer interface
11704 * This function calls clutter_container_raise_child() internally.
11706 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11709 clutter_actor_raise (ClutterActor *self,
11710 ClutterActor *below)
11712 ClutterActor *parent;
11714 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11716 parent = clutter_actor_get_parent (self);
11717 if (parent == NULL)
11719 g_warning ("%s: Actor '%s' is not inside a container",
11721 _clutter_actor_get_debug_name (self));
11727 if (parent != clutter_actor_get_parent (below))
11729 g_warning ("%s Actor '%s' is not in the same container as "
11732 _clutter_actor_get_debug_name (self),
11733 _clutter_actor_get_debug_name (below));
11738 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11742 * clutter_actor_lower:
11743 * @self: A #ClutterActor
11744 * @above: (allow-none): A #ClutterActor to lower below
11746 * Puts @self below @above.
11748 * Both actors must have the same parent, and the parent must implement
11749 * the #ClutterContainer interface.
11751 * This function calls clutter_container_lower_child() internally.
11753 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11756 clutter_actor_lower (ClutterActor *self,
11757 ClutterActor *above)
11759 ClutterActor *parent;
11761 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11763 parent = clutter_actor_get_parent (self);
11764 if (parent == NULL)
11766 g_warning ("%s: Actor of type %s is not inside a container",
11768 _clutter_actor_get_debug_name (self));
11774 if (parent != clutter_actor_get_parent (above))
11776 g_warning ("%s: Actor '%s' is not in the same container as "
11779 _clutter_actor_get_debug_name (self),
11780 _clutter_actor_get_debug_name (above));
11785 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11789 * clutter_actor_raise_top:
11790 * @self: A #ClutterActor
11792 * Raises @self to the top.
11794 * This function calls clutter_actor_raise() internally.
11796 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11797 * a %NULL sibling, instead.
11800 clutter_actor_raise_top (ClutterActor *self)
11802 clutter_actor_raise (self, NULL);
11806 * clutter_actor_lower_bottom:
11807 * @self: A #ClutterActor
11809 * Lowers @self to the bottom.
11811 * This function calls clutter_actor_lower() internally.
11813 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11814 * a %NULL sibling, instead.
11817 clutter_actor_lower_bottom (ClutterActor *self)
11819 clutter_actor_lower (self, NULL);
11827 * clutter_actor_event:
11828 * @actor: a #ClutterActor
11829 * @event: a #ClutterEvent
11830 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11832 * This function is used to emit an event on the main stage.
11833 * You should rarely need to use this function, except for
11834 * synthetising events.
11836 * Return value: the return value from the signal emission: %TRUE
11837 * if the actor handled the event, or %FALSE if the event was
11843 clutter_actor_event (ClutterActor *actor,
11844 ClutterEvent *event,
11847 gboolean retval = FALSE;
11848 gint signal_num = -1;
11850 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11851 g_return_val_if_fail (event != NULL, FALSE);
11853 g_object_ref (actor);
11857 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11863 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11867 switch (event->type)
11869 case CLUTTER_NOTHING:
11871 case CLUTTER_BUTTON_PRESS:
11872 signal_num = BUTTON_PRESS_EVENT;
11874 case CLUTTER_BUTTON_RELEASE:
11875 signal_num = BUTTON_RELEASE_EVENT;
11877 case CLUTTER_SCROLL:
11878 signal_num = SCROLL_EVENT;
11880 case CLUTTER_KEY_PRESS:
11881 signal_num = KEY_PRESS_EVENT;
11883 case CLUTTER_KEY_RELEASE:
11884 signal_num = KEY_RELEASE_EVENT;
11886 case CLUTTER_MOTION:
11887 signal_num = MOTION_EVENT;
11889 case CLUTTER_ENTER:
11890 signal_num = ENTER_EVENT;
11892 case CLUTTER_LEAVE:
11893 signal_num = LEAVE_EVENT;
11895 case CLUTTER_DELETE:
11896 case CLUTTER_DESTROY_NOTIFY:
11897 case CLUTTER_CLIENT_MESSAGE:
11903 if (signal_num != -1)
11904 g_signal_emit (actor, actor_signals[signal_num], 0,
11909 g_object_unref (actor);
11915 * clutter_actor_set_reactive:
11916 * @actor: a #ClutterActor
11917 * @reactive: whether the actor should be reactive to events
11919 * Sets @actor as reactive. Reactive actors will receive events.
11924 clutter_actor_set_reactive (ClutterActor *actor,
11927 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11929 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11933 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11935 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11937 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11941 * clutter_actor_get_reactive:
11942 * @actor: a #ClutterActor
11944 * Checks whether @actor is marked as reactive.
11946 * Return value: %TRUE if the actor is reactive
11951 clutter_actor_get_reactive (ClutterActor *actor)
11953 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11955 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11959 * clutter_actor_get_anchor_point:
11960 * @self: a #ClutterActor
11961 * @anchor_x: (out): return location for the X coordinate of the anchor point
11962 * @anchor_y: (out): return location for the Y coordinate of the anchor point
11964 * Gets the current anchor point of the @actor in pixels.
11969 clutter_actor_get_anchor_point (ClutterActor *self,
11973 const ClutterTransformInfo *info;
11975 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11977 info = _clutter_actor_get_transform_info_or_defaults (self);
11978 clutter_anchor_coord_get_units (self, &info->anchor,
11985 * clutter_actor_set_anchor_point:
11986 * @self: a #ClutterActor
11987 * @anchor_x: X coordinate of the anchor point
11988 * @anchor_y: Y coordinate of the anchor point
11990 * Sets an anchor point for @self. The anchor point is a point in the
11991 * coordinate space of an actor to which the actor position within its
11992 * parent is relative; the default is (0, 0), i.e. the top-left corner
11998 clutter_actor_set_anchor_point (ClutterActor *self,
12002 ClutterTransformInfo *info;
12003 ClutterActorPrivate *priv;
12004 gboolean changed = FALSE;
12005 gfloat old_anchor_x, old_anchor_y;
12008 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12010 obj = G_OBJECT (self);
12012 info = _clutter_actor_get_transform_info (self);
12014 g_object_freeze_notify (obj);
12016 clutter_anchor_coord_get_units (self, &info->anchor,
12021 if (info->anchor.is_fractional)
12022 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12024 if (old_anchor_x != anchor_x)
12026 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12030 if (old_anchor_y != anchor_y)
12032 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12036 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12040 priv->transform_valid = FALSE;
12041 clutter_actor_queue_redraw (self);
12044 g_object_thaw_notify (obj);
12048 * clutter_actor_get_anchor_point_gravity:
12049 * @self: a #ClutterActor
12051 * Retrieves the anchor position expressed as a #ClutterGravity. If
12052 * the anchor point was specified using pixels or units this will
12053 * return %CLUTTER_GRAVITY_NONE.
12055 * Return value: the #ClutterGravity used by the anchor point
12060 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12062 const ClutterTransformInfo *info;
12064 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12066 info = _clutter_actor_get_transform_info_or_defaults (self);
12068 return clutter_anchor_coord_get_gravity (&info->anchor);
12072 * clutter_actor_move_anchor_point:
12073 * @self: a #ClutterActor
12074 * @anchor_x: X coordinate of the anchor point
12075 * @anchor_y: Y coordinate of the anchor point
12077 * Sets an anchor point for the actor, and adjusts the actor postion so that
12078 * the relative position of the actor toward its parent remains the same.
12083 clutter_actor_move_anchor_point (ClutterActor *self,
12087 gfloat old_anchor_x, old_anchor_y;
12088 const ClutterTransformInfo *info;
12090 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12092 info = _clutter_actor_get_transform_info (self);
12093 clutter_anchor_coord_get_units (self, &info->anchor,
12098 g_object_freeze_notify (G_OBJECT (self));
12100 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12102 if (self->priv->position_set)
12103 clutter_actor_move_by (self,
12104 anchor_x - old_anchor_x,
12105 anchor_y - old_anchor_y);
12107 g_object_thaw_notify (G_OBJECT (self));
12111 * clutter_actor_move_anchor_point_from_gravity:
12112 * @self: a #ClutterActor
12113 * @gravity: #ClutterGravity.
12115 * Sets an anchor point on the actor based on the given gravity, adjusting the
12116 * actor postion so that its relative position within its parent remains
12119 * Since version 1.0 the anchor point will be stored as a gravity so
12120 * that if the actor changes size then the anchor point will move. For
12121 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12122 * and later double the size of the actor, the anchor point will move
12123 * to the bottom right.
12128 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12129 ClutterGravity gravity)
12131 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12132 const ClutterTransformInfo *info;
12133 ClutterActorPrivate *priv;
12135 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12138 info = _clutter_actor_get_transform_info (self);
12140 g_object_freeze_notify (G_OBJECT (self));
12142 clutter_anchor_coord_get_units (self, &info->anchor,
12146 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12147 clutter_anchor_coord_get_units (self, &info->anchor,
12152 if (priv->position_set)
12153 clutter_actor_move_by (self,
12154 new_anchor_x - old_anchor_x,
12155 new_anchor_y - old_anchor_y);
12157 g_object_thaw_notify (G_OBJECT (self));
12161 * clutter_actor_set_anchor_point_from_gravity:
12162 * @self: a #ClutterActor
12163 * @gravity: #ClutterGravity.
12165 * Sets an anchor point on the actor, based on the given gravity (this is a
12166 * convenience function wrapping clutter_actor_set_anchor_point()).
12168 * Since version 1.0 the anchor point will be stored as a gravity so
12169 * that if the actor changes size then the anchor point will move. For
12170 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12171 * and later double the size of the actor, the anchor point will move
12172 * to the bottom right.
12177 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12178 ClutterGravity gravity)
12180 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12182 if (gravity == CLUTTER_GRAVITY_NONE)
12183 clutter_actor_set_anchor_point (self, 0, 0);
12186 GObject *obj = G_OBJECT (self);
12187 ClutterTransformInfo *info;
12189 g_object_freeze_notify (obj);
12191 info = _clutter_actor_get_transform_info (self);
12192 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12194 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12195 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12196 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12198 self->priv->transform_valid = FALSE;
12200 clutter_actor_queue_redraw (self);
12202 g_object_thaw_notify (obj);
12207 clutter_container_iface_init (ClutterContainerIface *iface)
12209 /* we don't override anything, as ClutterContainer already has a default
12210 * implementation that we can use, and which calls into our own API.
12225 parse_units (ClutterActor *self,
12226 ParseDimension dimension,
12229 GValue value = { 0, };
12232 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12235 json_node_get_value (node, &value);
12237 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12239 retval = (gfloat) g_value_get_int64 (&value);
12241 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12243 retval = g_value_get_double (&value);
12245 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12247 ClutterUnits units;
12250 res = clutter_units_from_string (&units, g_value_get_string (&value));
12252 retval = clutter_units_to_pixels (&units);
12255 g_warning ("Invalid value '%s': integers, strings or floating point "
12256 "values can be used for the x, y, width and height "
12257 "properties. Valid modifiers for strings are 'px', 'mm', "
12259 g_value_get_string (&value));
12265 g_warning ("Invalid value of type '%s': integers, strings of floating "
12266 "point values can be used for the x, y, width, height "
12267 "anchor-x and anchor-y properties.",
12268 g_type_name (G_VALUE_TYPE (&value)));
12271 g_value_unset (&value);
12277 ClutterRotateAxis axis;
12286 static inline gboolean
12287 parse_rotation_array (ClutterActor *actor,
12289 RotationInfo *info)
12293 if (json_array_get_length (array) != 2)
12297 element = json_array_get_element (array, 0);
12298 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12299 info->angle = json_node_get_double (element);
12304 element = json_array_get_element (array, 1);
12305 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12307 JsonArray *center = json_node_get_array (element);
12309 if (json_array_get_length (center) != 2)
12312 switch (info->axis)
12314 case CLUTTER_X_AXIS:
12315 info->center_y = parse_units (actor, PARSE_Y,
12316 json_array_get_element (center, 0));
12317 info->center_z = parse_units (actor, PARSE_Y,
12318 json_array_get_element (center, 1));
12321 case CLUTTER_Y_AXIS:
12322 info->center_x = parse_units (actor, PARSE_X,
12323 json_array_get_element (center, 0));
12324 info->center_z = parse_units (actor, PARSE_X,
12325 json_array_get_element (center, 1));
12328 case CLUTTER_Z_AXIS:
12329 info->center_x = parse_units (actor, PARSE_X,
12330 json_array_get_element (center, 0));
12331 info->center_y = parse_units (actor, PARSE_Y,
12332 json_array_get_element (center, 1));
12341 parse_rotation (ClutterActor *actor,
12343 RotationInfo *info)
12347 gboolean retval = FALSE;
12349 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12351 g_warning ("Invalid node of type '%s' found, expecting an array",
12352 json_node_type_name (node));
12356 array = json_node_get_array (node);
12357 len = json_array_get_length (array);
12359 for (i = 0; i < len; i++)
12361 JsonNode *element = json_array_get_element (array, i);
12362 JsonObject *object;
12365 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12367 g_warning ("Invalid node of type '%s' found, expecting an object",
12368 json_node_type_name (element));
12372 object = json_node_get_object (element);
12374 if (json_object_has_member (object, "x-axis"))
12376 member = json_object_get_member (object, "x-axis");
12378 info->axis = CLUTTER_X_AXIS;
12380 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12382 info->angle = json_node_get_double (member);
12385 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12386 retval = parse_rotation_array (actor,
12387 json_node_get_array (member),
12392 else if (json_object_has_member (object, "y-axis"))
12394 member = json_object_get_member (object, "y-axis");
12396 info->axis = CLUTTER_Y_AXIS;
12398 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12400 info->angle = json_node_get_double (member);
12403 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12404 retval = parse_rotation_array (actor,
12405 json_node_get_array (member),
12410 else if (json_object_has_member (object, "z-axis"))
12412 member = json_object_get_member (object, "z-axis");
12414 info->axis = CLUTTER_Z_AXIS;
12416 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12418 info->angle = json_node_get_double (member);
12421 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12422 retval = parse_rotation_array (actor,
12423 json_node_get_array (member),
12434 parse_actor_metas (ClutterScript *script,
12435 ClutterActor *actor,
12438 GList *elements, *l;
12439 GSList *retval = NULL;
12441 if (!JSON_NODE_HOLDS_ARRAY (node))
12444 elements = json_array_get_elements (json_node_get_array (node));
12446 for (l = elements; l != NULL; l = l->next)
12448 JsonNode *element = l->data;
12449 const gchar *id_ = _clutter_script_get_id_from_node (element);
12452 if (id_ == NULL || *id_ == '\0')
12455 meta = clutter_script_get_object (script, id_);
12459 retval = g_slist_prepend (retval, meta);
12462 g_list_free (elements);
12464 return g_slist_reverse (retval);
12468 parse_behaviours (ClutterScript *script,
12469 ClutterActor *actor,
12472 GList *elements, *l;
12473 GSList *retval = NULL;
12475 if (!JSON_NODE_HOLDS_ARRAY (node))
12478 elements = json_array_get_elements (json_node_get_array (node));
12480 for (l = elements; l != NULL; l = l->next)
12482 JsonNode *element = l->data;
12483 const gchar *id_ = _clutter_script_get_id_from_node (element);
12484 GObject *behaviour;
12486 if (id_ == NULL || *id_ == '\0')
12489 behaviour = clutter_script_get_object (script, id_);
12490 if (behaviour == NULL)
12493 retval = g_slist_prepend (retval, behaviour);
12496 g_list_free (elements);
12498 return g_slist_reverse (retval);
12502 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12503 ClutterScript *script,
12508 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12509 gboolean retval = FALSE;
12511 if ((name[0] == 'x' && name[1] == '\0') ||
12512 (name[0] == 'y' && name[1] == '\0') ||
12513 (strcmp (name, "width") == 0) ||
12514 (strcmp (name, "height") == 0) ||
12515 (strcmp (name, "anchor_x") == 0) ||
12516 (strcmp (name, "anchor_y") == 0))
12518 ParseDimension dimension;
12521 if (name[0] == 'x')
12522 dimension = PARSE_X;
12523 else if (name[0] == 'y')
12524 dimension = PARSE_Y;
12525 else if (name[0] == 'w')
12526 dimension = PARSE_WIDTH;
12527 else if (name[0] == 'h')
12528 dimension = PARSE_HEIGHT;
12529 else if (name[0] == 'a' && name[7] == 'x')
12530 dimension = PARSE_ANCHOR_X;
12531 else if (name[0] == 'a' && name[7] == 'y')
12532 dimension = PARSE_ANCHOR_Y;
12536 units = parse_units (actor, dimension, node);
12538 /* convert back to pixels: all properties are pixel-based */
12539 g_value_init (value, G_TYPE_FLOAT);
12540 g_value_set_float (value, units);
12544 else if (strcmp (name, "rotation") == 0)
12546 RotationInfo *info;
12548 info = g_slice_new0 (RotationInfo);
12549 retval = parse_rotation (actor, node, info);
12553 g_value_init (value, G_TYPE_POINTER);
12554 g_value_set_pointer (value, info);
12557 g_slice_free (RotationInfo, info);
12559 else if (strcmp (name, "behaviours") == 0)
12563 #ifdef CLUTTER_ENABLE_DEBUG
12564 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12565 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12566 "and it should not be used in newly "
12567 "written ClutterScript definitions.");
12570 l = parse_behaviours (script, actor, node);
12572 g_value_init (value, G_TYPE_POINTER);
12573 g_value_set_pointer (value, l);
12577 else if (strcmp (name, "actions") == 0 ||
12578 strcmp (name, "constraints") == 0 ||
12579 strcmp (name, "effects") == 0)
12583 l = parse_actor_metas (script, actor, node);
12585 g_value_init (value, G_TYPE_POINTER);
12586 g_value_set_pointer (value, l);
12595 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12596 ClutterScript *script,
12598 const GValue *value)
12600 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12602 #ifdef CLUTTER_ENABLE_DEBUG
12603 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12605 gchar *tmp = g_strdup_value_contents (value);
12607 CLUTTER_NOTE (SCRIPT,
12608 "in ClutterActor::set_custom_property('%s') = %s",
12614 #endif /* CLUTTER_ENABLE_DEBUG */
12616 if (strcmp (name, "rotation") == 0)
12618 RotationInfo *info;
12620 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12623 info = g_value_get_pointer (value);
12625 clutter_actor_set_rotation (actor,
12626 info->axis, info->angle,
12631 g_slice_free (RotationInfo, info);
12636 if (strcmp (name, "behaviours") == 0)
12638 GSList *behaviours, *l;
12640 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12643 behaviours = g_value_get_pointer (value);
12644 for (l = behaviours; l != NULL; l = l->next)
12646 ClutterBehaviour *behaviour = l->data;
12648 clutter_behaviour_apply (behaviour, actor);
12651 g_slist_free (behaviours);
12656 if (strcmp (name, "actions") == 0 ||
12657 strcmp (name, "constraints") == 0 ||
12658 strcmp (name, "effects") == 0)
12662 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12665 metas = g_value_get_pointer (value);
12666 for (l = metas; l != NULL; l = l->next)
12668 if (name[0] == 'a')
12669 clutter_actor_add_action (actor, l->data);
12671 if (name[0] == 'c')
12672 clutter_actor_add_constraint (actor, l->data);
12674 if (name[0] == 'e')
12675 clutter_actor_add_effect (actor, l->data);
12678 g_slist_free (metas);
12683 g_object_set_property (G_OBJECT (scriptable), name, value);
12687 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12689 iface->parse_custom_node = clutter_actor_parse_custom_node;
12690 iface->set_custom_property = clutter_actor_set_custom_property;
12693 static ClutterActorMeta *
12694 get_meta_from_animation_property (ClutterActor *actor,
12698 ClutterActorPrivate *priv = actor->priv;
12699 ClutterActorMeta *meta = NULL;
12702 /* if this is not a special property, fall through */
12703 if (name[0] != '@')
12706 /* detect the properties named using the following spec:
12708 * @<section>.<meta-name>.<property-name>
12710 * where <section> can be one of the following:
12716 * and <meta-name> is the name set on a specific ActorMeta
12719 tokens = g_strsplit (name + 1, ".", -1);
12720 if (tokens == NULL || g_strv_length (tokens) != 3)
12722 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12724 g_strfreev (tokens);
12728 if (strcmp (tokens[0], "actions") == 0)
12729 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12731 if (strcmp (tokens[0], "constraints") == 0)
12732 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12734 if (strcmp (tokens[0], "effects") == 0)
12735 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12737 if (name_p != NULL)
12738 *name_p = g_strdup (tokens[2]);
12740 CLUTTER_NOTE (ANIMATION,
12741 "Looking for property '%s' of object '%s' in section '%s'",
12746 g_strfreev (tokens);
12751 static GParamSpec *
12752 clutter_actor_find_property (ClutterAnimatable *animatable,
12753 const gchar *property_name)
12755 ClutterActorMeta *meta = NULL;
12756 GObjectClass *klass = NULL;
12757 GParamSpec *pspec = NULL;
12758 gchar *p_name = NULL;
12760 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12766 klass = G_OBJECT_GET_CLASS (meta);
12768 pspec = g_object_class_find_property (klass, p_name);
12772 klass = G_OBJECT_GET_CLASS (animatable);
12774 pspec = g_object_class_find_property (klass, property_name);
12783 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12784 const gchar *property_name,
12787 ClutterActorMeta *meta = NULL;
12788 gchar *p_name = NULL;
12790 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12795 g_object_get_property (G_OBJECT (meta), p_name, initial);
12797 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12803 * clutter_actor_set_animatable_property:
12804 * @actor: a #ClutterActor
12805 * @prop_id: the paramspec id
12806 * @value: the value to set
12807 * @pspec: the paramspec
12809 * Sets values of animatable properties.
12811 * This is a variant of clutter_actor_set_property() that gets called
12812 * by the #ClutterAnimatable implementation of #ClutterActor for the
12813 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12816 * Unlike the implementation of #GObjectClass.set_property(), this
12817 * function will not update the interval if a transition involving an
12818 * animatable property is in progress - this avoids cycles with the
12819 * transition API calling the public API.
12822 clutter_actor_set_animatable_property (ClutterActor *actor,
12824 const GValue *value,
12830 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12834 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12838 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12842 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12846 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12850 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12853 case PROP_BACKGROUND_COLOR:
12854 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12858 clutter_actor_set_scale_factor_internal (actor,
12859 g_value_get_double (value),
12864 clutter_actor_set_scale_factor_internal (actor,
12865 g_value_get_double (value),
12869 case PROP_ROTATION_ANGLE_X:
12870 clutter_actor_set_rotation_angle_internal (actor,
12872 g_value_get_double (value));
12875 case PROP_ROTATION_ANGLE_Y:
12876 clutter_actor_set_rotation_angle_internal (actor,
12878 g_value_get_double (value));
12881 case PROP_ROTATION_ANGLE_Z:
12882 clutter_actor_set_rotation_angle_internal (actor,
12884 g_value_get_double (value));
12888 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12894 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12895 const gchar *property_name,
12896 const GValue *final)
12898 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12899 ClutterActorMeta *meta = NULL;
12900 gchar *p_name = NULL;
12902 meta = get_meta_from_animation_property (actor,
12906 g_object_set_property (G_OBJECT (meta), p_name, final);
12909 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12912 pspec = g_object_class_find_property (obj_class, property_name);
12914 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12916 /* XXX - I'm going to the special hell for this */
12917 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12920 g_object_set_property (G_OBJECT (animatable), property_name, final);
12927 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12929 iface->find_property = clutter_actor_find_property;
12930 iface->get_initial_state = clutter_actor_get_initial_state;
12931 iface->set_final_state = clutter_actor_set_final_state;
12935 * clutter_actor_transform_stage_point:
12936 * @self: A #ClutterActor
12937 * @x: (in): x screen coordinate of the point to unproject
12938 * @y: (in): y screen coordinate of the point to unproject
12939 * @x_out: (out): return location for the unprojected x coordinance
12940 * @y_out: (out): return location for the unprojected y coordinance
12942 * This function translates screen coordinates (@x, @y) to
12943 * coordinates relative to the actor. For example, it can be used to translate
12944 * screen events from global screen coordinates into actor-local coordinates.
12946 * The conversion can fail, notably if the transform stack results in the
12947 * actor being projected on the screen as a mere line.
12949 * The conversion should not be expected to be pixel-perfect due to the
12950 * nature of the operation. In general the error grows when the skewing
12951 * of the actor rectangle on screen increases.
12953 * <note><para>This function can be computationally intensive.</para></note>
12955 * <note><para>This function only works when the allocation is up-to-date,
12956 * i.e. inside of paint().</para></note>
12958 * Return value: %TRUE if conversion was successful.
12963 clutter_actor_transform_stage_point (ClutterActor *self,
12969 ClutterVertex v[4];
12972 int du, dv, xi, yi;
12974 float xf, yf, wf, det;
12975 ClutterActorPrivate *priv;
12977 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12981 /* This implementation is based on the quad -> quad projection algorithm
12982 * described by Paul Heckbert in:
12984 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12986 * and the sample implementation at:
12988 * http://www.cs.cmu.edu/~ph/src/texfund/
12990 * Our texture is a rectangle with origin [0, 0], so we are mapping from
12991 * quad to rectangle only, which significantly simplifies things; the
12992 * function calls have been unrolled, and most of the math is done in fixed
12996 clutter_actor_get_abs_allocation_vertices (self, v);
12998 /* Keeping these as ints simplifies the multiplication (no significant
12999 * loss of precision here).
13001 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13002 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13007 #define UX2FP(x) (x)
13008 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13010 /* First, find mapping from unit uv square to xy quadrilateral; this
13011 * equivalent to the pmap_square_quad() functions in the sample
13012 * implementation, which we can simplify, since our target is always
13015 px = v[0].x - v[1].x + v[3].x - v[2].x;
13016 py = v[0].y - v[1].y + v[3].y - v[2].y;
13020 /* affine transform */
13021 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13022 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13023 RQ[2][0] = UX2FP (v[0].x);
13024 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13025 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13026 RQ[2][1] = UX2FP (v[0].y);
13033 /* projective transform */
13034 double dx1, dx2, dy1, dy2, del;
13036 dx1 = UX2FP (v[1].x - v[3].x);
13037 dx2 = UX2FP (v[2].x - v[3].x);
13038 dy1 = UX2FP (v[1].y - v[3].y);
13039 dy2 = UX2FP (v[2].y - v[3].y);
13041 del = DET2FP (dx1, dx2, dy1, dy2);
13046 * The division here needs to be done in floating point for
13047 * precisions reasons.
13049 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13050 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13051 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13053 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13054 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13055 RQ[2][0] = UX2FP (v[0].x);
13056 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13057 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13058 RQ[2][1] = UX2FP (v[0].y);
13062 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13063 * square. Since our rectangle is based at 0,0 we only need to scale.
13073 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13076 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13077 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13078 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13079 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13080 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13081 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13082 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13083 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13084 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13087 * Check the resulting matrix is OK.
13089 det = (RQ[0][0] * ST[0][0])
13090 + (RQ[0][1] * ST[0][1])
13091 + (RQ[0][2] * ST[0][2]);
13096 * Now transform our point with the ST matrix; the notional w
13097 * coordinate is 1, hence the last part is simply added.
13102 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13103 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13104 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13122 static ClutterGeometry*
13123 clutter_geometry_copy (const ClutterGeometry *geometry)
13125 return g_slice_dup (ClutterGeometry, geometry);
13129 clutter_geometry_free (ClutterGeometry *geometry)
13131 if (G_LIKELY (geometry != NULL))
13132 g_slice_free (ClutterGeometry, geometry);
13136 * clutter_geometry_union:
13137 * @geometry_a: a #ClutterGeometry
13138 * @geometry_b: another #ClutterGeometry
13139 * @result: (out): location to store the result
13141 * Find the union of two rectangles represented as #ClutterGeometry.
13146 clutter_geometry_union (const ClutterGeometry *geometry_a,
13147 const ClutterGeometry *geometry_b,
13148 ClutterGeometry *result)
13150 /* We don't try to handle rectangles that can't be represented
13151 * as a signed integer box */
13152 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13153 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13154 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13155 geometry_b->x + (gint)geometry_b->width);
13156 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13157 geometry_b->y + (gint)geometry_b->height);
13160 result->width = x_2 - x_1;
13161 result->height = y_2 - y_1;
13165 * clutter_geometry_intersects:
13166 * @geometry0: The first geometry to test
13167 * @geometry1: The second geometry to test
13169 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13170 * they do else %FALSE.
13172 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13178 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13179 const ClutterGeometry *geometry1)
13181 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13182 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13183 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13184 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13191 clutter_geometry_progress (const GValue *a,
13196 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13197 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13198 ClutterGeometry res = { 0, };
13199 gint a_width = a_geom->width;
13200 gint b_width = b_geom->width;
13201 gint a_height = a_geom->height;
13202 gint b_height = b_geom->height;
13204 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13205 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13207 res.width = a_width + (b_width - a_width) * progress;
13208 res.height = a_height + (b_height - a_height) * progress;
13210 g_value_set_boxed (retval, &res);
13215 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13216 clutter_geometry_copy,
13217 clutter_geometry_free,
13218 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13225 * clutter_vertex_new:
13230 * Creates a new #ClutterVertex for the point in 3D space
13231 * identified by the 3 coordinates @x, @y, @z
13233 * Return value: the newly allocate #ClutterVertex. Use
13234 * clutter_vertex_free() to free the resources
13239 clutter_vertex_new (gfloat x,
13243 ClutterVertex *vertex;
13245 vertex = g_slice_new (ClutterVertex);
13254 * clutter_vertex_copy:
13255 * @vertex: a #ClutterVertex
13259 * Return value: a newly allocated copy of #ClutterVertex. Use
13260 * clutter_vertex_free() to free the allocated resources
13265 clutter_vertex_copy (const ClutterVertex *vertex)
13267 if (G_LIKELY (vertex != NULL))
13268 return g_slice_dup (ClutterVertex, vertex);
13274 * clutter_vertex_free:
13275 * @vertex: a #ClutterVertex
13277 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13282 clutter_vertex_free (ClutterVertex *vertex)
13284 if (G_UNLIKELY (vertex != NULL))
13285 g_slice_free (ClutterVertex, vertex);
13289 * clutter_vertex_equal:
13290 * @vertex_a: a #ClutterVertex
13291 * @vertex_b: a #ClutterVertex
13293 * Compares @vertex_a and @vertex_b for equality
13295 * Return value: %TRUE if the passed #ClutterVertex are equal
13300 clutter_vertex_equal (const ClutterVertex *vertex_a,
13301 const ClutterVertex *vertex_b)
13303 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13305 if (vertex_a == vertex_b)
13308 return vertex_a->x == vertex_b->x &&
13309 vertex_a->y == vertex_b->y &&
13310 vertex_a->z == vertex_b->z;
13314 clutter_vertex_progress (const GValue *a,
13319 const ClutterVertex *av = g_value_get_boxed (a);
13320 const ClutterVertex *bv = g_value_get_boxed (b);
13321 ClutterVertex res = { 0, };
13323 res.x = av->x + (bv->x - av->x) * progress;
13324 res.y = av->y + (bv->y - av->y) * progress;
13325 res.z = av->z + (bv->z - av->z) * progress;
13327 g_value_set_boxed (retval, &res);
13332 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13333 clutter_vertex_copy,
13334 clutter_vertex_free,
13335 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13338 * clutter_actor_is_rotated:
13339 * @self: a #ClutterActor
13341 * Checks whether any rotation is applied to the actor.
13343 * Return value: %TRUE if the actor is rotated.
13348 clutter_actor_is_rotated (ClutterActor *self)
13350 const ClutterTransformInfo *info;
13352 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13354 info = _clutter_actor_get_transform_info_or_defaults (self);
13356 if (info->rx_angle || info->ry_angle || info->rz_angle)
13363 * clutter_actor_is_scaled:
13364 * @self: a #ClutterActor
13366 * Checks whether the actor is scaled in either dimension.
13368 * Return value: %TRUE if the actor is scaled.
13373 clutter_actor_is_scaled (ClutterActor *self)
13375 const ClutterTransformInfo *info;
13377 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13379 info = _clutter_actor_get_transform_info_or_defaults (self);
13381 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13388 _clutter_actor_get_stage_internal (ClutterActor *actor)
13390 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13391 actor = actor->priv->parent;
13397 * clutter_actor_get_stage:
13398 * @actor: a #ClutterActor
13400 * Retrieves the #ClutterStage where @actor is contained.
13402 * Return value: (transfer none) (type Clutter.Stage): the stage
13403 * containing the actor, or %NULL
13408 clutter_actor_get_stage (ClutterActor *actor)
13410 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13412 return _clutter_actor_get_stage_internal (actor);
13416 * clutter_actor_allocate_available_size:
13417 * @self: a #ClutterActor
13418 * @x: the actor's X coordinate
13419 * @y: the actor's Y coordinate
13420 * @available_width: the maximum available width, or -1 to use the
13421 * actor's natural width
13422 * @available_height: the maximum available height, or -1 to use the
13423 * actor's natural height
13424 * @flags: flags controlling the allocation
13426 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13427 * preferred size, but limiting it to the maximum available width
13428 * and height provided.
13430 * This function will do the right thing when dealing with the
13431 * actor's request mode.
13433 * The implementation of this function is equivalent to:
13436 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13438 * clutter_actor_get_preferred_width (self, available_height,
13440 * &natural_width);
13441 * width = CLAMP (natural_width, min_width, available_width);
13443 * clutter_actor_get_preferred_height (self, width,
13445 * &natural_height);
13446 * height = CLAMP (natural_height, min_height, available_height);
13450 * clutter_actor_get_preferred_height (self, available_width,
13452 * &natural_height);
13453 * height = CLAMP (natural_height, min_height, available_height);
13455 * clutter_actor_get_preferred_width (self, height,
13457 * &natural_width);
13458 * width = CLAMP (natural_width, min_width, available_width);
13461 * box.x1 = x; box.y1 = y;
13462 * box.x2 = box.x1 + available_width;
13463 * box.y2 = box.y1 + available_height;
13464 * clutter_actor_allocate (self, &box, flags);
13467 * This function can be used by fluid layout managers to allocate
13468 * an actor's preferred size without making it bigger than the area
13469 * available for the container.
13474 clutter_actor_allocate_available_size (ClutterActor *self,
13477 gfloat available_width,
13478 gfloat available_height,
13479 ClutterAllocationFlags flags)
13481 ClutterActorPrivate *priv;
13482 gfloat width, height;
13483 gfloat min_width, min_height;
13484 gfloat natural_width, natural_height;
13485 ClutterActorBox box;
13487 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13491 width = height = 0.0;
13493 switch (priv->request_mode)
13495 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13496 clutter_actor_get_preferred_width (self, available_height,
13499 width = CLAMP (natural_width, min_width, available_width);
13501 clutter_actor_get_preferred_height (self, width,
13504 height = CLAMP (natural_height, min_height, available_height);
13507 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13508 clutter_actor_get_preferred_height (self, available_width,
13511 height = CLAMP (natural_height, min_height, available_height);
13513 clutter_actor_get_preferred_width (self, height,
13516 width = CLAMP (natural_width, min_width, available_width);
13523 box.x2 = box.x1 + width;
13524 box.y2 = box.y1 + height;
13525 clutter_actor_allocate (self, &box, flags);
13529 * clutter_actor_allocate_preferred_size:
13530 * @self: a #ClutterActor
13531 * @flags: flags controlling the allocation
13533 * Allocates the natural size of @self.
13535 * This function is a utility call for #ClutterActor implementations
13536 * that allocates the actor's preferred natural size. It can be used
13537 * by fixed layout managers (like #ClutterGroup or so called
13538 * 'composite actors') inside the ClutterActor::allocate
13539 * implementation to give each child exactly how much space it
13542 * This function is not meant to be used by applications. It is also
13543 * not meant to be used outside the implementation of the
13544 * ClutterActor::allocate virtual function.
13549 clutter_actor_allocate_preferred_size (ClutterActor *self,
13550 ClutterAllocationFlags flags)
13552 gfloat actor_x, actor_y;
13553 gfloat natural_width, natural_height;
13554 ClutterActorBox actor_box;
13556 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13558 actor_x = clutter_actor_get_x (self);
13559 actor_y = clutter_actor_get_y (self);
13561 clutter_actor_get_preferred_size (self,
13566 actor_box.x1 = actor_x;
13567 actor_box.y1 = actor_y;
13568 actor_box.x2 = actor_box.x1 + natural_width;
13569 actor_box.y2 = actor_box.y1 + natural_height;
13571 clutter_actor_allocate (self, &actor_box, flags);
13575 * clutter_actor_allocate_align_fill:
13576 * @self: a #ClutterActor
13577 * @box: a #ClutterActorBox, containing the available width and height
13578 * @x_align: the horizontal alignment, between 0 and 1
13579 * @y_align: the vertical alignment, between 0 and 1
13580 * @x_fill: whether the actor should fill horizontally
13581 * @y_fill: whether the actor should fill vertically
13582 * @flags: allocation flags to be passed to clutter_actor_allocate()
13584 * Allocates @self by taking into consideration the available allocation
13585 * area; an alignment factor on either axis; and whether the actor should
13586 * fill the allocation on either axis.
13588 * The @box should contain the available allocation width and height;
13589 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13590 * allocation will be offset by their value.
13592 * This function takes into consideration the geometry request specified by
13593 * the #ClutterActor:request-mode property, and the text direction.
13595 * This function is useful for fluid layout managers, like #ClutterBinLayout
13596 * or #ClutterTableLayout
13601 clutter_actor_allocate_align_fill (ClutterActor *self,
13602 const ClutterActorBox *box,
13607 ClutterAllocationFlags flags)
13609 ClutterActorPrivate *priv;
13610 ClutterActorBox allocation = { 0, };
13611 gfloat x_offset, y_offset;
13612 gfloat available_width, available_height;
13613 gfloat child_width, child_height;
13615 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13616 g_return_if_fail (box != NULL);
13617 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13618 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13622 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13623 clutter_actor_box_get_size (box, &available_width, &available_height);
13625 if (available_width < 0)
13626 available_width = 0;
13628 if (available_height < 0)
13629 available_height = 0;
13633 allocation.x1 = x_offset;
13634 allocation.x2 = allocation.x1 + available_width;
13639 allocation.y1 = y_offset;
13640 allocation.y2 = allocation.y1 + available_height;
13643 /* if we are filling horizontally and vertically then we're done */
13644 if (x_fill && y_fill)
13647 child_width = child_height = 0.0f;
13649 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13651 gfloat min_width, natural_width;
13652 gfloat min_height, natural_height;
13654 clutter_actor_get_preferred_width (self, available_height,
13658 child_width = CLAMP (natural_width, min_width, available_width);
13662 clutter_actor_get_preferred_height (self, child_width,
13666 child_height = CLAMP (natural_height, min_height, available_height);
13671 gfloat min_width, natural_width;
13672 gfloat min_height, natural_height;
13674 clutter_actor_get_preferred_height (self, available_width,
13678 child_height = CLAMP (natural_height, min_height, available_height);
13682 clutter_actor_get_preferred_width (self, child_height,
13686 child_width = CLAMP (natural_width, min_width, available_width);
13690 /* invert the horizontal alignment for RTL languages */
13691 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13692 x_align = 1.0 - x_align;
13696 allocation.x1 = x_offset
13697 + ((available_width - child_width) * x_align);
13698 allocation.x2 = allocation.x1 + child_width;
13703 allocation.y1 = y_offset
13704 + ((available_height - child_height) * y_align);
13705 allocation.y2 = allocation.y1 + child_height;
13709 clutter_actor_box_clamp_to_pixel (&allocation);
13710 clutter_actor_allocate (self, &allocation, flags);
13714 * clutter_actor_grab_key_focus:
13715 * @self: a #ClutterActor
13717 * Sets the key focus of the #ClutterStage including @self
13718 * to this #ClutterActor.
13723 clutter_actor_grab_key_focus (ClutterActor *self)
13725 ClutterActor *stage;
13727 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13729 stage = _clutter_actor_get_stage_internal (self);
13731 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13735 * clutter_actor_get_pango_context:
13736 * @self: a #ClutterActor
13738 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13739 * is already configured using the appropriate font map, resolution
13740 * and font options.
13742 * Unlike clutter_actor_create_pango_context(), this context is owend
13743 * by the #ClutterActor and it will be updated each time the options
13744 * stored by the #ClutterBackend change.
13746 * You can use the returned #PangoContext to create a #PangoLayout
13747 * and render text using cogl_pango_render_layout() to reuse the
13748 * glyphs cache also used by Clutter.
13750 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13751 * The returned #PangoContext is owned by the actor and should not be
13752 * unreferenced by the application code
13757 clutter_actor_get_pango_context (ClutterActor *self)
13759 ClutterActorPrivate *priv;
13761 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13765 if (priv->pango_context != NULL)
13766 return priv->pango_context;
13768 priv->pango_context = _clutter_context_get_pango_context ();
13769 g_object_ref (priv->pango_context);
13771 return priv->pango_context;
13775 * clutter_actor_create_pango_context:
13776 * @self: a #ClutterActor
13778 * Creates a #PangoContext for the given actor. The #PangoContext
13779 * is already configured using the appropriate font map, resolution
13780 * and font options.
13782 * See also clutter_actor_get_pango_context().
13784 * Return value: (transfer full): the newly created #PangoContext.
13785 * Use g_object_unref() on the returned value to deallocate its
13791 clutter_actor_create_pango_context (ClutterActor *self)
13793 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13795 return _clutter_context_create_pango_context ();
13799 * clutter_actor_create_pango_layout:
13800 * @self: a #ClutterActor
13801 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13803 * Creates a new #PangoLayout from the same #PangoContext used
13804 * by the #ClutterActor. The #PangoLayout is already configured
13805 * with the font map, resolution and font options, and the
13808 * If you want to keep around a #PangoLayout created by this
13809 * function you will have to connect to the #ClutterBackend::font-changed
13810 * and #ClutterBackend::resolution-changed signals, and call
13811 * pango_layout_context_changed() in response to them.
13813 * Return value: (transfer full): the newly created #PangoLayout.
13814 * Use g_object_unref() when done
13819 clutter_actor_create_pango_layout (ClutterActor *self,
13822 PangoContext *context;
13823 PangoLayout *layout;
13825 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13827 context = clutter_actor_get_pango_context (self);
13828 layout = pango_layout_new (context);
13831 pango_layout_set_text (layout, text, -1);
13836 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13837 * ClutterOffscreenEffect.
13840 _clutter_actor_set_opacity_override (ClutterActor *self,
13843 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13845 self->priv->opacity_override = opacity;
13849 _clutter_actor_get_opacity_override (ClutterActor *self)
13851 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13853 return self->priv->opacity_override;
13856 /* Allows you to disable applying the actors model view transform during
13857 * a paint. Used by ClutterClone. */
13859 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13862 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13864 self->priv->enable_model_view_transform = enable;
13868 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13871 ClutterActorPrivate *priv;
13873 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13877 priv->enable_paint_unmapped = enable;
13879 if (priv->enable_paint_unmapped)
13881 /* Make sure that the parents of the widget are realized first;
13882 * otherwise checks in clutter_actor_update_map_state() will
13885 clutter_actor_realize (self);
13887 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13891 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13896 clutter_anchor_coord_get_units (ClutterActor *self,
13897 const AnchorCoord *coord,
13902 if (coord->is_fractional)
13904 gfloat actor_width, actor_height;
13906 clutter_actor_get_size (self, &actor_width, &actor_height);
13909 *x = actor_width * coord->v.fraction.x;
13912 *y = actor_height * coord->v.fraction.y;
13920 *x = coord->v.units.x;
13923 *y = coord->v.units.y;
13926 *z = coord->v.units.z;
13931 clutter_anchor_coord_set_units (AnchorCoord *coord,
13936 coord->is_fractional = FALSE;
13937 coord->v.units.x = x;
13938 coord->v.units.y = y;
13939 coord->v.units.z = z;
13942 static ClutterGravity
13943 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13945 if (coord->is_fractional)
13947 if (coord->v.fraction.x == 0.0)
13949 if (coord->v.fraction.y == 0.0)
13950 return CLUTTER_GRAVITY_NORTH_WEST;
13951 else if (coord->v.fraction.y == 0.5)
13952 return CLUTTER_GRAVITY_WEST;
13953 else if (coord->v.fraction.y == 1.0)
13954 return CLUTTER_GRAVITY_SOUTH_WEST;
13956 return CLUTTER_GRAVITY_NONE;
13958 else if (coord->v.fraction.x == 0.5)
13960 if (coord->v.fraction.y == 0.0)
13961 return CLUTTER_GRAVITY_NORTH;
13962 else if (coord->v.fraction.y == 0.5)
13963 return CLUTTER_GRAVITY_CENTER;
13964 else if (coord->v.fraction.y == 1.0)
13965 return CLUTTER_GRAVITY_SOUTH;
13967 return CLUTTER_GRAVITY_NONE;
13969 else if (coord->v.fraction.x == 1.0)
13971 if (coord->v.fraction.y == 0.0)
13972 return CLUTTER_GRAVITY_NORTH_EAST;
13973 else if (coord->v.fraction.y == 0.5)
13974 return CLUTTER_GRAVITY_EAST;
13975 else if (coord->v.fraction.y == 1.0)
13976 return CLUTTER_GRAVITY_SOUTH_EAST;
13978 return CLUTTER_GRAVITY_NONE;
13981 return CLUTTER_GRAVITY_NONE;
13984 return CLUTTER_GRAVITY_NONE;
13988 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
13989 ClutterGravity gravity)
13993 case CLUTTER_GRAVITY_NORTH:
13994 coord->v.fraction.x = 0.5;
13995 coord->v.fraction.y = 0.0;
13998 case CLUTTER_GRAVITY_NORTH_EAST:
13999 coord->v.fraction.x = 1.0;
14000 coord->v.fraction.y = 0.0;
14003 case CLUTTER_GRAVITY_EAST:
14004 coord->v.fraction.x = 1.0;
14005 coord->v.fraction.y = 0.5;
14008 case CLUTTER_GRAVITY_SOUTH_EAST:
14009 coord->v.fraction.x = 1.0;
14010 coord->v.fraction.y = 1.0;
14013 case CLUTTER_GRAVITY_SOUTH:
14014 coord->v.fraction.x = 0.5;
14015 coord->v.fraction.y = 1.0;
14018 case CLUTTER_GRAVITY_SOUTH_WEST:
14019 coord->v.fraction.x = 0.0;
14020 coord->v.fraction.y = 1.0;
14023 case CLUTTER_GRAVITY_WEST:
14024 coord->v.fraction.x = 0.0;
14025 coord->v.fraction.y = 0.5;
14028 case CLUTTER_GRAVITY_NORTH_WEST:
14029 coord->v.fraction.x = 0.0;
14030 coord->v.fraction.y = 0.0;
14033 case CLUTTER_GRAVITY_CENTER:
14034 coord->v.fraction.x = 0.5;
14035 coord->v.fraction.y = 0.5;
14039 coord->v.fraction.x = 0.0;
14040 coord->v.fraction.y = 0.0;
14044 coord->is_fractional = TRUE;
14048 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14050 if (coord->is_fractional)
14051 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14053 return (coord->v.units.x == 0.0
14054 && coord->v.units.y == 0.0
14055 && coord->v.units.z == 0.0);
14059 * clutter_actor_get_flags:
14060 * @self: a #ClutterActor
14062 * Retrieves the flags set on @self
14064 * Return value: a bitwise or of #ClutterActorFlags or 0
14069 clutter_actor_get_flags (ClutterActor *self)
14071 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14073 return self->flags;
14077 * clutter_actor_set_flags:
14078 * @self: a #ClutterActor
14079 * @flags: the flags to set
14081 * Sets @flags on @self
14083 * This function will emit notifications for the changed properties
14088 clutter_actor_set_flags (ClutterActor *self,
14089 ClutterActorFlags flags)
14091 ClutterActorFlags old_flags;
14093 gboolean was_reactive_set, reactive_set;
14094 gboolean was_realized_set, realized_set;
14095 gboolean was_mapped_set, mapped_set;
14096 gboolean was_visible_set, visible_set;
14098 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14100 if (self->flags == flags)
14103 obj = G_OBJECT (self);
14104 g_object_ref (obj);
14105 g_object_freeze_notify (obj);
14107 old_flags = self->flags;
14109 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14110 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14111 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14112 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14114 self->flags |= flags;
14116 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14117 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14118 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14119 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14121 if (reactive_set != was_reactive_set)
14122 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14124 if (realized_set != was_realized_set)
14125 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14127 if (mapped_set != was_mapped_set)
14128 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14130 if (visible_set != was_visible_set)
14131 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14133 g_object_thaw_notify (obj);
14134 g_object_unref (obj);
14138 * clutter_actor_unset_flags:
14139 * @self: a #ClutterActor
14140 * @flags: the flags to unset
14142 * Unsets @flags on @self
14144 * This function will emit notifications for the changed properties
14149 clutter_actor_unset_flags (ClutterActor *self,
14150 ClutterActorFlags flags)
14152 ClutterActorFlags old_flags;
14154 gboolean was_reactive_set, reactive_set;
14155 gboolean was_realized_set, realized_set;
14156 gboolean was_mapped_set, mapped_set;
14157 gboolean was_visible_set, visible_set;
14159 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14161 obj = G_OBJECT (self);
14162 g_object_freeze_notify (obj);
14164 old_flags = self->flags;
14166 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14167 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14168 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14169 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14171 self->flags &= ~flags;
14173 if (self->flags == old_flags)
14176 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14177 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14178 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14179 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14181 if (reactive_set != was_reactive_set)
14182 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14184 if (realized_set != was_realized_set)
14185 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14187 if (mapped_set != was_mapped_set)
14188 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14190 if (visible_set != was_visible_set)
14191 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14193 g_object_thaw_notify (obj);
14197 * clutter_actor_get_transformation_matrix:
14198 * @self: a #ClutterActor
14199 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14201 * Retrieves the transformations applied to @self relative to its
14207 clutter_actor_get_transformation_matrix (ClutterActor *self,
14208 CoglMatrix *matrix)
14210 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14212 cogl_matrix_init_identity (matrix);
14214 _clutter_actor_apply_modelview_transform (self, matrix);
14218 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14219 gboolean is_in_clone_paint)
14221 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14222 self->priv->in_clone_paint = is_in_clone_paint;
14226 * clutter_actor_is_in_clone_paint:
14227 * @self: a #ClutterActor
14229 * Checks whether @self is being currently painted by a #ClutterClone
14231 * This function is useful only inside the ::paint virtual function
14232 * implementations or within handlers for the #ClutterActor::paint
14235 * This function should not be used by applications
14237 * Return value: %TRUE if the #ClutterActor is currently being painted
14238 * by a #ClutterClone, and %FALSE otherwise
14243 clutter_actor_is_in_clone_paint (ClutterActor *self)
14245 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14247 return self->priv->in_clone_paint;
14251 set_direction_recursive (ClutterActor *actor,
14252 gpointer user_data)
14254 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14256 clutter_actor_set_text_direction (actor, text_dir);
14262 * clutter_actor_set_text_direction:
14263 * @self: a #ClutterActor
14264 * @text_dir: the text direction for @self
14266 * Sets the #ClutterTextDirection for an actor
14268 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14270 * If @self implements #ClutterContainer then this function will recurse
14271 * inside all the children of @self (including the internal ones).
14273 * Composite actors not implementing #ClutterContainer, or actors requiring
14274 * special handling when the text direction changes, should connect to
14275 * the #GObject::notify signal for the #ClutterActor:text-direction property
14280 clutter_actor_set_text_direction (ClutterActor *self,
14281 ClutterTextDirection text_dir)
14283 ClutterActorPrivate *priv;
14285 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14286 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14290 if (priv->text_direction != text_dir)
14292 priv->text_direction = text_dir;
14294 /* we need to emit the notify::text-direction first, so that
14295 * the sub-classes can catch that and do specific handling of
14296 * the text direction; see clutter_text_direction_changed_cb()
14297 * inside clutter-text.c
14299 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14301 _clutter_actor_foreach_child (self, set_direction_recursive,
14302 GINT_TO_POINTER (text_dir));
14304 clutter_actor_queue_relayout (self);
14309 _clutter_actor_set_has_pointer (ClutterActor *self,
14310 gboolean has_pointer)
14312 ClutterActorPrivate *priv = self->priv;
14314 if (priv->has_pointer != has_pointer)
14316 priv->has_pointer = has_pointer;
14318 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14323 * clutter_actor_get_text_direction:
14324 * @self: a #ClutterActor
14326 * Retrieves the value set using clutter_actor_set_text_direction()
14328 * If no text direction has been previously set, the default text
14329 * direction, as returned by clutter_get_default_text_direction(), will
14330 * be returned instead
14332 * Return value: the #ClutterTextDirection for the actor
14336 ClutterTextDirection
14337 clutter_actor_get_text_direction (ClutterActor *self)
14339 ClutterActorPrivate *priv;
14341 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14342 CLUTTER_TEXT_DIRECTION_LTR);
14346 /* if no direction has been set yet use the default */
14347 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14348 priv->text_direction = clutter_get_default_text_direction ();
14350 return priv->text_direction;
14354 * clutter_actor_push_internal:
14355 * @self: a #ClutterActor
14357 * Should be used by actors implementing the #ClutterContainer and with
14358 * internal children added through clutter_actor_set_parent(), for instance:
14362 * my_actor_init (MyActor *self)
14364 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14366 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14368 * /* calling clutter_actor_set_parent() now will result in
14369 * * the internal flag being set on a child of MyActor
14372 * /* internal child - a background texture */
14373 * self->priv->background_tex = clutter_texture_new ();
14374 * clutter_actor_set_parent (self->priv->background_tex,
14375 * CLUTTER_ACTOR (self));
14377 * /* internal child - a label */
14378 * self->priv->label = clutter_text_new ();
14379 * clutter_actor_set_parent (self->priv->label,
14380 * CLUTTER_ACTOR (self));
14382 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14384 * /* calling clutter_actor_set_parent() now will not result in
14385 * * the internal flag being set on a child of MyActor
14390 * This function will be used by Clutter to toggle an "internal child"
14391 * flag whenever clutter_actor_set_parent() is called; internal children
14392 * are handled differently by Clutter, specifically when destroying their
14395 * Call clutter_actor_pop_internal() when you finished adding internal
14398 * Nested calls to clutter_actor_push_internal() are allowed, but each
14399 * one must by followed by a clutter_actor_pop_internal() call.
14403 * Deprecated: 1.10: All children of an actor are accessible through
14404 * the #ClutterActor API, and #ClutterActor implements the
14405 * #ClutterContainer interface, so this function is only useful
14406 * for legacy containers overriding the default implementation.
14409 clutter_actor_push_internal (ClutterActor *self)
14411 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14413 self->priv->internal_child += 1;
14417 * clutter_actor_pop_internal:
14418 * @self: a #ClutterActor
14420 * Disables the effects of clutter_actor_push_internal().
14424 * Deprecated: 1.10: All children of an actor are accessible through
14425 * the #ClutterActor API. This function is only useful for legacy
14426 * containers overriding the default implementation of the
14427 * #ClutterContainer interface.
14430 clutter_actor_pop_internal (ClutterActor *self)
14432 ClutterActorPrivate *priv;
14434 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14438 if (priv->internal_child == 0)
14440 g_warning ("Mismatched %s: you need to call "
14441 "clutter_actor_push_composite() at least once before "
14442 "calling this function", G_STRFUNC);
14446 priv->internal_child -= 1;
14450 * clutter_actor_has_pointer:
14451 * @self: a #ClutterActor
14453 * Checks whether an actor contains the pointer of a
14454 * #ClutterInputDevice
14456 * Return value: %TRUE if the actor contains the pointer, and
14462 clutter_actor_has_pointer (ClutterActor *self)
14464 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14466 return self->priv->has_pointer;
14469 /* XXX: This is a workaround for not being able to break the ABI of
14470 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14471 * clutter_actor_queue_clipped_redraw() for details.
14473 ClutterPaintVolume *
14474 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14476 return g_object_get_data (G_OBJECT (self),
14477 "-clutter-actor-queue-redraw-clip");
14481 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14482 ClutterPaintVolume *clip)
14484 g_object_set_data (G_OBJECT (self),
14485 "-clutter-actor-queue-redraw-clip",
14490 * clutter_actor_has_allocation:
14491 * @self: a #ClutterActor
14493 * Checks if the actor has an up-to-date allocation assigned to
14494 * it. This means that the actor should have an allocation: it's
14495 * visible and has a parent. It also means that there is no
14496 * outstanding relayout request in progress for the actor or its
14497 * children (There might be other outstanding layout requests in
14498 * progress that will cause the actor to get a new allocation
14499 * when the stage is laid out, however).
14501 * If this function returns %FALSE, then the actor will normally
14502 * be allocated before it is next drawn on the screen.
14504 * Return value: %TRUE if the actor has an up-to-date allocation
14509 clutter_actor_has_allocation (ClutterActor *self)
14511 ClutterActorPrivate *priv;
14513 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14517 return priv->parent != NULL &&
14518 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14519 !priv->needs_allocation;
14523 * clutter_actor_add_action:
14524 * @self: a #ClutterActor
14525 * @action: a #ClutterAction
14527 * Adds @action to the list of actions applied to @self
14529 * A #ClutterAction can only belong to one actor at a time
14531 * The #ClutterActor will hold a reference on @action until either
14532 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14538 clutter_actor_add_action (ClutterActor *self,
14539 ClutterAction *action)
14541 ClutterActorPrivate *priv;
14543 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14544 g_return_if_fail (CLUTTER_IS_ACTION (action));
14548 if (priv->actions == NULL)
14550 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14551 priv->actions->actor = self;
14554 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14556 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14560 * clutter_actor_add_action_with_name:
14561 * @self: a #ClutterActor
14562 * @name: the name to set on the action
14563 * @action: a #ClutterAction
14565 * A convenience function for setting the name of a #ClutterAction
14566 * while adding it to the list of actions applied to @self
14568 * This function is the logical equivalent of:
14571 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14572 * clutter_actor_add_action (self, action);
14578 clutter_actor_add_action_with_name (ClutterActor *self,
14580 ClutterAction *action)
14582 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14583 g_return_if_fail (name != NULL);
14584 g_return_if_fail (CLUTTER_IS_ACTION (action));
14586 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14587 clutter_actor_add_action (self, action);
14591 * clutter_actor_remove_action:
14592 * @self: a #ClutterActor
14593 * @action: a #ClutterAction
14595 * Removes @action from the list of actions applied to @self
14597 * The reference held by @self on the #ClutterAction will be released
14602 clutter_actor_remove_action (ClutterActor *self,
14603 ClutterAction *action)
14605 ClutterActorPrivate *priv;
14607 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14608 g_return_if_fail (CLUTTER_IS_ACTION (action));
14612 if (priv->actions == NULL)
14615 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14617 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14621 * clutter_actor_remove_action_by_name:
14622 * @self: a #ClutterActor
14623 * @name: the name of the action to remove
14625 * Removes the #ClutterAction with the given name from the list
14626 * of actions applied to @self
14631 clutter_actor_remove_action_by_name (ClutterActor *self,
14634 ClutterActorPrivate *priv;
14635 ClutterActorMeta *meta;
14637 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14638 g_return_if_fail (name != NULL);
14642 if (priv->actions == NULL)
14645 meta = _clutter_meta_group_get_meta (priv->actions, name);
14649 _clutter_meta_group_remove_meta (priv->actions, meta);
14651 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14655 * clutter_actor_get_actions:
14656 * @self: a #ClutterActor
14658 * Retrieves the list of actions applied to @self
14660 * Return value: (transfer container) (element-type Clutter.Action): a copy
14661 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14662 * owned by the #ClutterActor. Use g_list_free() to free the resources
14663 * allocated by the returned #GList
14668 clutter_actor_get_actions (ClutterActor *self)
14670 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14672 if (self->priv->actions == NULL)
14675 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14679 * clutter_actor_get_action:
14680 * @self: a #ClutterActor
14681 * @name: the name of the action to retrieve
14683 * Retrieves the #ClutterAction with the given name in the list
14684 * of actions applied to @self
14686 * Return value: (transfer none): a #ClutterAction for the given
14687 * name, or %NULL. The returned #ClutterAction is owned by the
14688 * actor and it should not be unreferenced directly
14693 clutter_actor_get_action (ClutterActor *self,
14696 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14697 g_return_val_if_fail (name != NULL, NULL);
14699 if (self->priv->actions == NULL)
14702 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14706 * clutter_actor_clear_actions:
14707 * @self: a #ClutterActor
14709 * Clears the list of actions applied to @self
14714 clutter_actor_clear_actions (ClutterActor *self)
14716 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14718 if (self->priv->actions == NULL)
14721 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14725 * clutter_actor_add_constraint:
14726 * @self: a #ClutterActor
14727 * @constraint: a #ClutterConstraint
14729 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14732 * The #ClutterActor will hold a reference on the @constraint until
14733 * either clutter_actor_remove_constraint() or
14734 * clutter_actor_clear_constraints() is called.
14739 clutter_actor_add_constraint (ClutterActor *self,
14740 ClutterConstraint *constraint)
14742 ClutterActorPrivate *priv;
14744 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14745 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14749 if (priv->constraints == NULL)
14751 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14752 priv->constraints->actor = self;
14755 _clutter_meta_group_add_meta (priv->constraints,
14756 CLUTTER_ACTOR_META (constraint));
14757 clutter_actor_queue_relayout (self);
14759 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14763 * clutter_actor_add_constraint_with_name:
14764 * @self: a #ClutterActor
14765 * @name: the name to set on the constraint
14766 * @constraint: a #ClutterConstraint
14768 * A convenience function for setting the name of a #ClutterConstraint
14769 * while adding it to the list of constraints applied to @self
14771 * This function is the logical equivalent of:
14774 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14775 * clutter_actor_add_constraint (self, constraint);
14781 clutter_actor_add_constraint_with_name (ClutterActor *self,
14783 ClutterConstraint *constraint)
14785 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14786 g_return_if_fail (name != NULL);
14787 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14789 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14790 clutter_actor_add_constraint (self, constraint);
14794 * clutter_actor_remove_constraint:
14795 * @self: a #ClutterActor
14796 * @constraint: a #ClutterConstraint
14798 * Removes @constraint from the list of constraints applied to @self
14800 * The reference held by @self on the #ClutterConstraint will be released
14805 clutter_actor_remove_constraint (ClutterActor *self,
14806 ClutterConstraint *constraint)
14808 ClutterActorPrivate *priv;
14810 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14811 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14815 if (priv->constraints == NULL)
14818 _clutter_meta_group_remove_meta (priv->constraints,
14819 CLUTTER_ACTOR_META (constraint));
14820 clutter_actor_queue_relayout (self);
14822 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14826 * clutter_actor_remove_constraint_by_name:
14827 * @self: a #ClutterActor
14828 * @name: the name of the constraint to remove
14830 * Removes the #ClutterConstraint with the given name from the list
14831 * of constraints applied to @self
14836 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14839 ClutterActorPrivate *priv;
14840 ClutterActorMeta *meta;
14842 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14843 g_return_if_fail (name != NULL);
14847 if (priv->constraints == NULL)
14850 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14854 _clutter_meta_group_remove_meta (priv->constraints, meta);
14855 clutter_actor_queue_relayout (self);
14859 * clutter_actor_get_constraints:
14860 * @self: a #ClutterActor
14862 * Retrieves the list of constraints applied to @self
14864 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14865 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14866 * owned by the #ClutterActor. Use g_list_free() to free the resources
14867 * allocated by the returned #GList
14872 clutter_actor_get_constraints (ClutterActor *self)
14874 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14876 if (self->priv->constraints == NULL)
14879 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14883 * clutter_actor_get_constraint:
14884 * @self: a #ClutterActor
14885 * @name: the name of the constraint to retrieve
14887 * Retrieves the #ClutterConstraint with the given name in the list
14888 * of constraints applied to @self
14890 * Return value: (transfer none): a #ClutterConstraint for the given
14891 * name, or %NULL. The returned #ClutterConstraint is owned by the
14892 * actor and it should not be unreferenced directly
14896 ClutterConstraint *
14897 clutter_actor_get_constraint (ClutterActor *self,
14900 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14901 g_return_val_if_fail (name != NULL, NULL);
14903 if (self->priv->constraints == NULL)
14906 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14910 * clutter_actor_clear_constraints:
14911 * @self: a #ClutterActor
14913 * Clears the list of constraints applied to @self
14918 clutter_actor_clear_constraints (ClutterActor *self)
14920 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14922 if (self->priv->constraints == NULL)
14925 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14927 clutter_actor_queue_relayout (self);
14931 * clutter_actor_set_clip_to_allocation:
14932 * @self: a #ClutterActor
14933 * @clip_set: %TRUE to apply a clip tracking the allocation
14935 * Sets whether @self should be clipped to the same size as its
14941 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14944 ClutterActorPrivate *priv;
14946 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14948 clip_set = !!clip_set;
14952 if (priv->clip_to_allocation != clip_set)
14954 priv->clip_to_allocation = clip_set;
14956 clutter_actor_queue_redraw (self);
14958 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14963 * clutter_actor_get_clip_to_allocation:
14964 * @self: a #ClutterActor
14966 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14968 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14973 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14975 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14977 return self->priv->clip_to_allocation;
14981 * clutter_actor_add_effect:
14982 * @self: a #ClutterActor
14983 * @effect: a #ClutterEffect
14985 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14987 * The #ClutterActor will hold a reference on the @effect until either
14988 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14994 clutter_actor_add_effect (ClutterActor *self,
14995 ClutterEffect *effect)
14997 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14998 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15000 _clutter_actor_add_effect_internal (self, effect);
15002 clutter_actor_queue_redraw (self);
15004 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15008 * clutter_actor_add_effect_with_name:
15009 * @self: a #ClutterActor
15010 * @name: the name to set on the effect
15011 * @effect: a #ClutterEffect
15013 * A convenience function for setting the name of a #ClutterEffect
15014 * while adding it to the list of effectss applied to @self
15016 * This function is the logical equivalent of:
15019 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15020 * clutter_actor_add_effect (self, effect);
15026 clutter_actor_add_effect_with_name (ClutterActor *self,
15028 ClutterEffect *effect)
15030 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15031 g_return_if_fail (name != NULL);
15032 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15034 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15035 clutter_actor_add_effect (self, effect);
15039 * clutter_actor_remove_effect:
15040 * @self: a #ClutterActor
15041 * @effect: a #ClutterEffect
15043 * Removes @effect from the list of effects applied to @self
15045 * The reference held by @self on the #ClutterEffect will be released
15050 clutter_actor_remove_effect (ClutterActor *self,
15051 ClutterEffect *effect)
15053 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15054 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15056 _clutter_actor_remove_effect_internal (self, effect);
15058 clutter_actor_queue_redraw (self);
15060 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15064 * clutter_actor_remove_effect_by_name:
15065 * @self: a #ClutterActor
15066 * @name: the name of the effect to remove
15068 * Removes the #ClutterEffect with the given name from the list
15069 * of effects applied to @self
15074 clutter_actor_remove_effect_by_name (ClutterActor *self,
15077 ClutterActorPrivate *priv;
15078 ClutterActorMeta *meta;
15080 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15081 g_return_if_fail (name != NULL);
15085 if (priv->effects == NULL)
15088 meta = _clutter_meta_group_get_meta (priv->effects, name);
15092 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15096 * clutter_actor_get_effects:
15097 * @self: a #ClutterActor
15099 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15101 * Return value: (transfer container) (element-type Clutter.Effect): a list
15102 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15103 * list are owned by Clutter and they should not be freed. You should
15104 * free the returned list using g_list_free() when done
15109 clutter_actor_get_effects (ClutterActor *self)
15111 ClutterActorPrivate *priv;
15113 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15117 if (priv->effects == NULL)
15120 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15124 * clutter_actor_get_effect:
15125 * @self: a #ClutterActor
15126 * @name: the name of the effect to retrieve
15128 * Retrieves the #ClutterEffect with the given name in the list
15129 * of effects applied to @self
15131 * Return value: (transfer none): a #ClutterEffect for the given
15132 * name, or %NULL. The returned #ClutterEffect is owned by the
15133 * actor and it should not be unreferenced directly
15138 clutter_actor_get_effect (ClutterActor *self,
15141 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15142 g_return_val_if_fail (name != NULL, NULL);
15144 if (self->priv->effects == NULL)
15147 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15151 * clutter_actor_clear_effects:
15152 * @self: a #ClutterActor
15154 * Clears the list of effects applied to @self
15159 clutter_actor_clear_effects (ClutterActor *self)
15161 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15163 if (self->priv->effects == NULL)
15166 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15168 clutter_actor_queue_redraw (self);
15172 * clutter_actor_has_key_focus:
15173 * @self: a #ClutterActor
15175 * Checks whether @self is the #ClutterActor that has key focus
15177 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15182 clutter_actor_has_key_focus (ClutterActor *self)
15184 ClutterActor *stage;
15186 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15188 stage = _clutter_actor_get_stage_internal (self);
15192 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15196 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15197 ClutterPaintVolume *pv)
15199 ClutterActorPrivate *priv = self->priv;
15201 /* Actors are only expected to report a valid paint volume
15202 * while they have a valid allocation. */
15203 if (G_UNLIKELY (priv->needs_allocation))
15205 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15206 "Actor needs allocation",
15207 _clutter_actor_get_debug_name (self));
15211 /* Check if there are any handlers connected to the paint
15212 * signal. If there are then all bets are off for what the paint
15213 * volume for this actor might possibly be!
15215 * XXX: It's expected that this is going to end up being quite a
15216 * costly check to have to do here, but we haven't come up with
15217 * another solution that can reliably catch paint signal handlers at
15218 * the right time to either avoid artefacts due to invalid stage
15219 * clipping or due to incorrect culling.
15221 * Previously we checked in clutter_actor_paint(), but at that time
15222 * we may already be using a stage clip that could be derived from
15223 * an invalid paint-volume. We used to try and handle that by
15224 * queuing a follow up, unclipped, redraw but still the previous
15225 * checking wasn't enough to catch invalid volumes involved in
15226 * culling (considering that containers may derive their volume from
15227 * children that haven't yet been painted)
15229 * Longer term, improved solutions could be:
15230 * - Disallow painting in the paint signal, only allow using it
15231 * for tracking when paints happen. We can add another API that
15232 * allows monkey patching the paint of arbitrary actors but in a
15233 * more controlled way and that also supports modifying the
15235 * - If we could be notified somehow when signal handlers are
15236 * connected we wouldn't have to poll for handlers like this.
15238 if (g_signal_has_handler_pending (self,
15239 actor_signals[PAINT],
15243 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15244 "Actor has \"paint\" signal handlers",
15245 _clutter_actor_get_debug_name (self));
15249 _clutter_paint_volume_init_static (pv, self);
15251 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15253 clutter_paint_volume_free (pv);
15254 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15255 "Actor failed to report a volume",
15256 _clutter_actor_get_debug_name (self));
15260 /* since effects can modify the paint volume, we allow them to actually
15261 * do this by making get_paint_volume() "context sensitive"
15263 if (priv->effects != NULL)
15265 if (priv->current_effect != NULL)
15267 const GList *effects, *l;
15269 /* if we are being called from within the paint sequence of
15270 * an actor, get the paint volume up to the current effect
15272 effects = _clutter_meta_group_peek_metas (priv->effects);
15274 l != NULL || (l != NULL && l->data != priv->current_effect);
15277 if (!_clutter_effect_get_paint_volume (l->data, pv))
15279 clutter_paint_volume_free (pv);
15280 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15281 "Effect (%s) failed to report a volume",
15282 _clutter_actor_get_debug_name (self),
15283 _clutter_actor_meta_get_debug_name (l->data));
15290 const GList *effects, *l;
15292 /* otherwise, get the cumulative volume */
15293 effects = _clutter_meta_group_peek_metas (priv->effects);
15294 for (l = effects; l != NULL; l = l->next)
15295 if (!_clutter_effect_get_paint_volume (l->data, pv))
15297 clutter_paint_volume_free (pv);
15298 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15299 "Effect (%s) failed to report a volume",
15300 _clutter_actor_get_debug_name (self),
15301 _clutter_actor_meta_get_debug_name (l->data));
15310 /* The public clutter_actor_get_paint_volume API returns a const
15311 * pointer since we return a pointer directly to the cached
15312 * PaintVolume associated with the actor and don't want the user to
15313 * inadvertently modify it, but for internal uses we sometimes need
15314 * access to the same PaintVolume but need to apply some book-keeping
15315 * modifications to it so we don't want a const pointer.
15317 static ClutterPaintVolume *
15318 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15320 ClutterActorPrivate *priv;
15324 if (priv->paint_volume_valid)
15325 clutter_paint_volume_free (&priv->paint_volume);
15327 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15329 priv->paint_volume_valid = TRUE;
15330 return &priv->paint_volume;
15334 priv->paint_volume_valid = FALSE;
15340 * clutter_actor_get_paint_volume:
15341 * @self: a #ClutterActor
15343 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15344 * when a paint volume can't be determined.
15346 * The paint volume is defined as the 3D space occupied by an actor
15347 * when being painted.
15349 * This function will call the <function>get_paint_volume()</function>
15350 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15351 * should not usually care about overriding the default implementation,
15352 * unless they are, for instance: painting outside their allocation, or
15353 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15356 * <note>2D actors overriding <function>get_paint_volume()</function>
15357 * ensure their volume has a depth of 0. (This will be true so long as
15358 * you don't call clutter_paint_volume_set_depth().)</note>
15360 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15361 * or %NULL if no volume could be determined. The returned pointer
15362 * is not guaranteed to be valid across multiple frames; if you want
15363 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15367 const ClutterPaintVolume *
15368 clutter_actor_get_paint_volume (ClutterActor *self)
15370 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15372 return _clutter_actor_get_paint_volume_mutable (self);
15376 * clutter_actor_get_transformed_paint_volume:
15377 * @self: a #ClutterActor
15378 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15379 * (or %NULL for the stage)
15381 * Retrieves the 3D paint volume of an actor like
15382 * clutter_actor_get_paint_volume() does (Please refer to the
15383 * documentation of clutter_actor_get_paint_volume() for more
15384 * details.) and it additionally transforms the paint volume into the
15385 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15386 * is passed for @relative_to_ancestor)
15388 * This can be used by containers that base their paint volume on
15389 * the volume of their children. Such containers can query the
15390 * transformed paint volume of all of its children and union them
15391 * together using clutter_paint_volume_union().
15393 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15394 * or %NULL if no volume could be determined. The returned pointer is
15395 * not guaranteed to be valid across multiple frames; if you wish to
15396 * keep it, you will have to copy it using clutter_paint_volume_copy().
15400 const ClutterPaintVolume *
15401 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15402 ClutterActor *relative_to_ancestor)
15404 const ClutterPaintVolume *volume;
15405 ClutterActor *stage;
15406 ClutterPaintVolume *transformed_volume;
15408 stage = _clutter_actor_get_stage_internal (self);
15409 if (G_UNLIKELY (stage == NULL))
15412 if (relative_to_ancestor == NULL)
15413 relative_to_ancestor = stage;
15415 volume = clutter_actor_get_paint_volume (self);
15416 if (volume == NULL)
15419 transformed_volume =
15420 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15422 _clutter_paint_volume_copy_static (volume, transformed_volume);
15424 _clutter_paint_volume_transform_relative (transformed_volume,
15425 relative_to_ancestor);
15427 return transformed_volume;
15431 * clutter_actor_get_paint_box:
15432 * @self: a #ClutterActor
15433 * @box: (out): return location for a #ClutterActorBox
15435 * Retrieves the paint volume of the passed #ClutterActor, and
15436 * transforms it into a 2D bounding box in stage coordinates.
15438 * This function is useful to determine the on screen area occupied by
15439 * the actor. The box is only an approximation and may often be
15440 * considerably larger due to the optimizations used to calculate the
15441 * box. The box is never smaller though, so it can reliably be used
15444 * There are times when a 2D paint box can't be determined, e.g.
15445 * because the actor isn't yet parented under a stage or because
15446 * the actor is unable to determine a paint volume.
15448 * Return value: %TRUE if a 2D paint box could be determined, else
15454 clutter_actor_get_paint_box (ClutterActor *self,
15455 ClutterActorBox *box)
15457 ClutterActor *stage;
15458 ClutterPaintVolume *pv;
15460 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15461 g_return_val_if_fail (box != NULL, FALSE);
15463 stage = _clutter_actor_get_stage_internal (self);
15464 if (G_UNLIKELY (!stage))
15467 pv = _clutter_actor_get_paint_volume_mutable (self);
15468 if (G_UNLIKELY (!pv))
15471 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15477 * clutter_actor_has_overlaps:
15478 * @self: A #ClutterActor
15480 * Asks the actor's implementation whether it may contain overlapping
15483 * For example; Clutter may use this to determine whether the painting
15484 * should be redirected to an offscreen buffer to correctly implement
15485 * the opacity property.
15487 * Custom actors can override the default response by implementing the
15488 * #ClutterActor <function>has_overlaps</function> virtual function. See
15489 * clutter_actor_set_offscreen_redirect() for more information.
15491 * Return value: %TRUE if the actor may have overlapping primitives, and
15497 clutter_actor_has_overlaps (ClutterActor *self)
15499 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15501 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15505 * clutter_actor_has_effects:
15506 * @self: A #ClutterActor
15508 * Returns whether the actor has any effects applied.
15510 * Return value: %TRUE if the actor has any effects,
15516 clutter_actor_has_effects (ClutterActor *self)
15518 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15520 if (self->priv->effects == NULL)
15523 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15527 * clutter_actor_has_constraints:
15528 * @self: A #ClutterActor
15530 * Returns whether the actor has any constraints applied.
15532 * Return value: %TRUE if the actor has any constraints,
15538 clutter_actor_has_constraints (ClutterActor *self)
15540 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15542 return self->priv->constraints != NULL;
15546 * clutter_actor_has_actions:
15547 * @self: A #ClutterActor
15549 * Returns whether the actor has any actions applied.
15551 * Return value: %TRUE if the actor has any actions,
15557 clutter_actor_has_actions (ClutterActor *self)
15559 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15561 return self->priv->actions != NULL;
15565 * clutter_actor_get_n_children:
15566 * @self: a #ClutterActor
15568 * Retrieves the number of children of @self.
15570 * Return value: the number of children of an actor
15575 clutter_actor_get_n_children (ClutterActor *self)
15577 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15579 return self->priv->n_children;
15583 * clutter_actor_get_child_at_index:
15584 * @self: a #ClutterActor
15585 * @index_: the position in the list of children
15587 * Retrieves the actor at the given @index_ inside the list of
15588 * children of @self.
15590 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15595 clutter_actor_get_child_at_index (ClutterActor *self,
15598 ClutterActor *iter;
15601 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15602 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15604 for (iter = self->priv->first_child, i = 0;
15605 iter != NULL && i < index_;
15606 iter = iter->priv->next_sibling, i += 1)
15613 * _clutter_actor_foreach_child:
15614 * @actor: The actor whos children you want to iterate
15615 * @callback: The function to call for each child
15616 * @user_data: Private data to pass to @callback
15618 * Calls a given @callback once for each child of the specified @actor and
15619 * passing the @user_data pointer each time.
15621 * Return value: returns %TRUE if all children were iterated, else
15622 * %FALSE if a callback broke out of iteration early.
15625 _clutter_actor_foreach_child (ClutterActor *self,
15626 ClutterForeachCallback callback,
15627 gpointer user_data)
15629 ClutterActorPrivate *priv = self->priv;
15630 ClutterActor *iter;
15633 for (cont = TRUE, iter = priv->first_child;
15634 cont && iter != NULL;
15635 iter = iter->priv->next_sibling)
15637 cont = callback (iter, user_data);
15644 /* For debugging purposes this gives us a simple way to print out
15645 * the scenegraph e.g in gdb using:
15647 * _clutter_actor_traverse (stage,
15649 * clutter_debug_print_actor_cb,
15654 static ClutterActorTraverseVisitFlags
15655 clutter_debug_print_actor_cb (ClutterActor *actor,
15659 g_print ("%*s%s:%p\n",
15661 _clutter_actor_get_debug_name (actor),
15664 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15669 _clutter_actor_traverse_breadth (ClutterActor *actor,
15670 ClutterTraverseCallback callback,
15671 gpointer user_data)
15673 GQueue *queue = g_queue_new ();
15674 ClutterActor dummy;
15675 int current_depth = 0;
15677 g_queue_push_tail (queue, actor);
15678 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15680 while ((actor = g_queue_pop_head (queue)))
15682 ClutterActorTraverseVisitFlags flags;
15684 if (actor == &dummy)
15687 g_queue_push_tail (queue, &dummy);
15691 flags = callback (actor, current_depth, user_data);
15692 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15694 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15696 ClutterActor *iter;
15698 for (iter = actor->priv->first_child;
15700 iter = iter->priv->next_sibling)
15702 g_queue_push_tail (queue, iter);
15707 g_queue_free (queue);
15710 static ClutterActorTraverseVisitFlags
15711 _clutter_actor_traverse_depth (ClutterActor *actor,
15712 ClutterTraverseCallback before_children_callback,
15713 ClutterTraverseCallback after_children_callback,
15715 gpointer user_data)
15717 ClutterActorTraverseVisitFlags flags;
15719 flags = before_children_callback (actor, current_depth, user_data);
15720 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15721 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15723 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15725 ClutterActor *iter;
15727 for (iter = actor->priv->first_child;
15729 iter = iter->priv->next_sibling)
15731 flags = _clutter_actor_traverse_depth (iter,
15732 before_children_callback,
15733 after_children_callback,
15737 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15738 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15742 if (after_children_callback)
15743 return after_children_callback (actor, current_depth, user_data);
15745 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15748 /* _clutter_actor_traverse:
15749 * @actor: The actor to start traversing the graph from
15750 * @flags: These flags may affect how the traversal is done
15751 * @before_children_callback: A function to call before visiting the
15752 * children of the current actor.
15753 * @after_children_callback: A function to call after visiting the
15754 * children of the current actor. (Ignored if
15755 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15756 * @user_data: The private data to pass to the callbacks
15758 * Traverses the scenegraph starting at the specified @actor and
15759 * descending through all its children and its children's children.
15760 * For each actor traversed @before_children_callback and
15761 * @after_children_callback are called with the specified
15762 * @user_data, before and after visiting that actor's children.
15764 * The callbacks can return flags that affect the ongoing traversal
15765 * such as by skipping over an actors children or bailing out of
15766 * any further traversing.
15769 _clutter_actor_traverse (ClutterActor *actor,
15770 ClutterActorTraverseFlags flags,
15771 ClutterTraverseCallback before_children_callback,
15772 ClutterTraverseCallback after_children_callback,
15773 gpointer user_data)
15775 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15776 _clutter_actor_traverse_breadth (actor,
15777 before_children_callback,
15779 else /* DEPTH_FIRST */
15780 _clutter_actor_traverse_depth (actor,
15781 before_children_callback,
15782 after_children_callback,
15783 0, /* start depth */
15788 on_layout_manager_changed (ClutterLayoutManager *manager,
15789 ClutterActor *self)
15791 clutter_actor_queue_relayout (self);
15795 * clutter_actor_set_layout_manager:
15796 * @self: a #ClutterActor
15797 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15799 * Sets the #ClutterLayoutManager delegate object that will be used to
15800 * lay out the children of @self.
15802 * The #ClutterActor will take a reference on the passed @manager which
15803 * will be released either when the layout manager is removed, or when
15804 * the actor is destroyed.
15809 clutter_actor_set_layout_manager (ClutterActor *self,
15810 ClutterLayoutManager *manager)
15812 ClutterActorPrivate *priv;
15814 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15815 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15819 if (priv->layout_manager != NULL)
15821 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15822 G_CALLBACK (on_layout_manager_changed),
15824 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15825 g_object_unref (priv->layout_manager);
15828 priv->layout_manager = manager;
15830 if (priv->layout_manager != NULL)
15832 g_object_ref_sink (priv->layout_manager);
15833 clutter_layout_manager_set_container (priv->layout_manager,
15834 CLUTTER_CONTAINER (self));
15835 g_signal_connect (priv->layout_manager, "layout-changed",
15836 G_CALLBACK (on_layout_manager_changed),
15840 clutter_actor_queue_relayout (self);
15842 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15846 * clutter_actor_get_layout_manager:
15847 * @self: a #ClutterActor
15849 * Retrieves the #ClutterLayoutManager used by @self.
15851 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15856 ClutterLayoutManager *
15857 clutter_actor_get_layout_manager (ClutterActor *self)
15859 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15861 return self->priv->layout_manager;
15864 static const ClutterLayoutInfo default_layout_info = {
15867 { 0, 0, 0, 0 }, /* margin */
15868 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15869 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15870 0.f, 0.f, /* min_width, natural_width */
15871 0.f, 0.f, /* natual_width, natural_height */
15875 layout_info_free (gpointer data)
15877 if (G_LIKELY (data != NULL))
15878 g_slice_free (ClutterLayoutInfo, data);
15882 * _clutter_actor_get_layout_info:
15883 * @self: a #ClutterActor
15885 * Retrieves a pointer to the ClutterLayoutInfo structure.
15887 * If the actor does not have a ClutterLayoutInfo associated to it, one
15888 * will be created and initialized to the default values.
15890 * This function should be used for setters.
15892 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15895 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15897 ClutterLayoutInfo *
15898 _clutter_actor_get_layout_info (ClutterActor *self)
15900 ClutterLayoutInfo *retval;
15902 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15903 if (retval == NULL)
15905 retval = g_slice_new (ClutterLayoutInfo);
15907 *retval = default_layout_info;
15909 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15918 * _clutter_actor_get_layout_info_or_defaults:
15919 * @self: a #ClutterActor
15921 * Retrieves the ClutterLayoutInfo structure associated to an actor.
15923 * If the actor does not have a ClutterLayoutInfo structure associated to it,
15924 * then the default structure will be returned.
15926 * This function should only be used for getters.
15928 * Return value: a const pointer to the ClutterLayoutInfo structure
15930 const ClutterLayoutInfo *
15931 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15933 const ClutterLayoutInfo *info;
15935 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15937 return &default_layout_info;
15943 * clutter_actor_set_x_align:
15944 * @self: a #ClutterActor
15945 * @x_align: the horizontal alignment policy
15947 * Sets the horizontal alignment policy of a #ClutterActor, in case the
15948 * actor received extra horizontal space.
15950 * See also the #ClutterActor:x-align property.
15955 clutter_actor_set_x_align (ClutterActor *self,
15956 ClutterActorAlign x_align)
15958 ClutterLayoutInfo *info;
15960 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15962 info = _clutter_actor_get_layout_info (self);
15964 if (info->x_align != x_align)
15966 info->x_align = x_align;
15968 clutter_actor_queue_relayout (self);
15970 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15975 * clutter_actor_get_x_align:
15976 * @self: a #ClutterActor
15978 * Retrieves the horizontal alignment policy set using
15979 * clutter_actor_set_x_align().
15981 * Return value: the horizontal alignment policy.
15986 clutter_actor_get_x_align (ClutterActor *self)
15988 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15990 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15994 * clutter_actor_set_y_align:
15995 * @self: a #ClutterActor
15996 * @y_align: the vertical alignment policy
15998 * Sets the vertical alignment policy of a #ClutterActor, in case the
15999 * actor received extra vertical space.
16001 * See also the #ClutterActor:y-align property.
16006 clutter_actor_set_y_align (ClutterActor *self,
16007 ClutterActorAlign y_align)
16009 ClutterLayoutInfo *info;
16011 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16013 info = _clutter_actor_get_layout_info (self);
16015 if (info->y_align != y_align)
16017 info->y_align = y_align;
16019 clutter_actor_queue_relayout (self);
16021 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16026 * clutter_actor_get_y_align:
16027 * @self: a #ClutterActor
16029 * Retrieves the vertical alignment policy set using
16030 * clutter_actor_set_y_align().
16032 * Return value: the vertical alignment policy.
16037 clutter_actor_get_y_align (ClutterActor *self)
16039 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16041 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16046 * clutter_margin_new:
16048 * Creates a new #ClutterMargin.
16050 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16051 * clutter_margin_free() to free the resources associated with it when
16057 clutter_margin_new (void)
16059 return g_slice_new0 (ClutterMargin);
16063 * clutter_margin_copy:
16064 * @margin_: a #ClutterMargin
16066 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16067 * the newly created structure.
16069 * Return value: (transfer full): a copy of the #ClutterMargin.
16074 clutter_margin_copy (const ClutterMargin *margin_)
16076 if (G_LIKELY (margin_ != NULL))
16077 return g_slice_dup (ClutterMargin, margin_);
16083 * clutter_margin_free:
16084 * @margin_: a #ClutterMargin
16086 * Frees the resources allocated by clutter_margin_new() and
16087 * clutter_margin_copy().
16092 clutter_margin_free (ClutterMargin *margin_)
16094 if (G_LIKELY (margin_ != NULL))
16095 g_slice_free (ClutterMargin, margin_);
16098 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16099 clutter_margin_copy,
16100 clutter_margin_free)
16103 * clutter_actor_set_margin:
16104 * @self: a #ClutterActor
16105 * @margin: a #ClutterMargin
16107 * Sets all the components of the margin of a #ClutterActor.
16112 clutter_actor_set_margin (ClutterActor *self,
16113 const ClutterMargin *margin)
16115 ClutterLayoutInfo *info;
16119 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16120 g_return_if_fail (margin != NULL);
16122 obj = G_OBJECT (self);
16125 g_object_freeze_notify (obj);
16127 info = _clutter_actor_get_layout_info (self);
16129 if (info->margin.top != margin->top)
16131 info->margin.top = margin->top;
16132 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16136 if (info->margin.right != margin->right)
16138 info->margin.right = margin->right;
16139 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16143 if (info->margin.bottom != margin->bottom)
16145 info->margin.bottom = margin->bottom;
16146 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16150 if (info->margin.left != margin->left)
16152 info->margin.left = margin->left;
16153 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16158 clutter_actor_queue_relayout (self);
16160 g_object_thaw_notify (obj);
16164 * clutter_actor_get_margin:
16165 * @self: a #ClutterActor
16166 * @margin: (out caller-allocates): return location for a #ClutterMargin
16168 * Retrieves all the components of the margin of a #ClutterActor.
16173 clutter_actor_get_margin (ClutterActor *self,
16174 ClutterMargin *margin)
16176 const ClutterLayoutInfo *info;
16178 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16179 g_return_if_fail (margin != NULL);
16181 info = _clutter_actor_get_layout_info_or_defaults (self);
16183 *margin = info->margin;
16187 * clutter_actor_set_margin_top:
16188 * @self: a #ClutterActor
16189 * @margin: the top margin
16191 * Sets the margin from the top of a #ClutterActor.
16196 clutter_actor_set_margin_top (ClutterActor *self,
16199 ClutterLayoutInfo *info;
16201 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16202 g_return_if_fail (margin >= 0.f);
16204 info = _clutter_actor_get_layout_info (self);
16206 if (info->margin.top == margin)
16209 info->margin.top = margin;
16211 clutter_actor_queue_relayout (self);
16213 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16217 * clutter_actor_get_margin_top:
16218 * @self: a #ClutterActor
16220 * Retrieves the top margin of a #ClutterActor.
16222 * Return value: the top margin
16227 clutter_actor_get_margin_top (ClutterActor *self)
16229 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16231 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16235 * clutter_actor_set_margin_bottom:
16236 * @self: a #ClutterActor
16237 * @margin: the bottom margin
16239 * Sets the margin from the bottom of a #ClutterActor.
16244 clutter_actor_set_margin_bottom (ClutterActor *self,
16247 ClutterLayoutInfo *info;
16249 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16250 g_return_if_fail (margin >= 0.f);
16252 info = _clutter_actor_get_layout_info (self);
16254 if (info->margin.bottom == margin)
16257 info->margin.bottom = margin;
16259 clutter_actor_queue_relayout (self);
16261 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16265 * clutter_actor_get_margin_bottom:
16266 * @self: a #ClutterActor
16268 * Retrieves the bottom margin of a #ClutterActor.
16270 * Return value: the bottom margin
16275 clutter_actor_get_margin_bottom (ClutterActor *self)
16277 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16279 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16283 * clutter_actor_set_margin_left:
16284 * @self: a #ClutterActor
16285 * @margin: the left margin
16287 * Sets the margin from the left of a #ClutterActor.
16292 clutter_actor_set_margin_left (ClutterActor *self,
16295 ClutterLayoutInfo *info;
16297 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16298 g_return_if_fail (margin >= 0.f);
16300 info = _clutter_actor_get_layout_info (self);
16302 if (info->margin.left == margin)
16305 info->margin.left = margin;
16307 clutter_actor_queue_relayout (self);
16309 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16313 * clutter_actor_get_margin_left:
16314 * @self: a #ClutterActor
16316 * Retrieves the left margin of a #ClutterActor.
16318 * Return value: the left margin
16323 clutter_actor_get_margin_left (ClutterActor *self)
16325 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16327 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16331 * clutter_actor_set_margin_right:
16332 * @self: a #ClutterActor
16333 * @margin: the right margin
16335 * Sets the margin from the right of a #ClutterActor.
16340 clutter_actor_set_margin_right (ClutterActor *self,
16343 ClutterLayoutInfo *info;
16345 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16346 g_return_if_fail (margin >= 0.f);
16348 info = _clutter_actor_get_layout_info (self);
16350 if (info->margin.right == margin)
16353 info->margin.right = margin;
16355 clutter_actor_queue_relayout (self);
16357 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16361 * clutter_actor_get_margin_right:
16362 * @self: a #ClutterActor
16364 * Retrieves the right margin of a #ClutterActor.
16366 * Return value: the right margin
16371 clutter_actor_get_margin_right (ClutterActor *self)
16373 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16375 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16379 clutter_actor_set_background_color_internal (ClutterActor *self,
16380 const ClutterColor *color)
16382 ClutterActorPrivate *priv = self->priv;
16385 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16388 obj = G_OBJECT (self);
16390 priv->bg_color = *color;
16391 priv->bg_color_set = TRUE;
16393 clutter_actor_queue_redraw (self);
16395 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16396 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16400 * clutter_actor_set_background_color:
16401 * @self: a #ClutterActor
16402 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16405 * Sets the background color of a #ClutterActor.
16407 * The background color will be used to cover the whole allocation of the
16408 * actor. The default background color of an actor is transparent.
16410 * To check whether an actor has a background color, you can use the
16411 * #ClutterActor:background-color-set actor property.
16413 * The #ClutterActor:background-color property is animatable.
16418 clutter_actor_set_background_color (ClutterActor *self,
16419 const ClutterColor *color)
16421 ClutterActorPrivate *priv;
16423 GParamSpec *bg_color_pspec;
16425 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16427 obj = G_OBJECT (self);
16433 priv->bg_color_set = FALSE;
16434 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16435 clutter_actor_queue_redraw (self);
16439 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16440 if (clutter_actor_get_easing_duration (self) != 0)
16442 ClutterTransition *transition;
16444 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16445 if (transition == NULL)
16447 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16450 clutter_timeline_start (CLUTTER_TIMELINE (transition));
16453 _clutter_actor_update_transition (self, bg_color_pspec, color);
16455 clutter_actor_queue_redraw (self);
16458 clutter_actor_set_background_color_internal (self, color);
16462 * clutter_actor_get_background_color:
16463 * @self: a #ClutterActor
16464 * @color: (out caller-allocates): return location for a #ClutterColor
16466 * Retrieves the color set using clutter_actor_set_background_color().
16471 clutter_actor_get_background_color (ClutterActor *self,
16472 ClutterColor *color)
16474 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16475 g_return_if_fail (color != NULL);
16477 *color = self->priv->bg_color;
16481 * clutter_actor_get_previous_sibling:
16482 * @self: a #ClutterActor
16484 * Retrieves the sibling of @self that comes before it in the list
16485 * of children of @self's parent.
16487 * The returned pointer is only valid until the scene graph changes; it
16488 * is not safe to modify the list of children of @self while iterating
16491 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16496 clutter_actor_get_previous_sibling (ClutterActor *self)
16498 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16500 return self->priv->prev_sibling;
16504 * clutter_actor_get_next_sibling:
16505 * @self: a #ClutterActor
16507 * Retrieves the sibling of @self that comes after it in the list
16508 * of children of @self's parent.
16510 * The returned pointer is only valid until the scene graph changes; it
16511 * is not safe to modify the list of children of @self while iterating
16514 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16519 clutter_actor_get_next_sibling (ClutterActor *self)
16521 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16523 return self->priv->next_sibling;
16527 * clutter_actor_get_first_child:
16528 * @self: a #ClutterActor
16530 * Retrieves the first child of @self.
16532 * The returned pointer is only valid until the scene graph changes; it
16533 * is not safe to modify the list of children of @self while iterating
16536 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16541 clutter_actor_get_first_child (ClutterActor *self)
16543 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16545 return self->priv->first_child;
16549 * clutter_actor_get_last_child:
16550 * @self: a #ClutterActor
16552 * Retrieves the last child of @self.
16554 * The returned pointer is only valid until the scene graph changes; it
16555 * is not safe to modify the list of children of @self while iterating
16558 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16563 clutter_actor_get_last_child (ClutterActor *self)
16565 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16567 return self->priv->last_child;
16570 /* easy way to have properly named fields instead of the dummy ones
16571 * we use in the public structure
16573 typedef struct _RealActorIter
16575 ClutterActor *root; /* dummy1 */
16576 ClutterActor *current; /* dummy2 */
16577 gpointer padding_1; /* dummy3 */
16578 gint age; /* dummy4 */
16579 gpointer padding_2; /* dummy5 */
16583 * clutter_actor_iter_init:
16584 * @iter: a #ClutterActorIter
16585 * @root: a #ClutterActor
16587 * Initializes a #ClutterActorIter, which can then be used to iterate
16588 * efficiently over a section of the scene graph, and associates it
16591 * Modifying the scene graph section that contains @root will invalidate
16595 * ClutterActorIter iter;
16596 * ClutterActor *child;
16598 * clutter_actor_iter_init (&iter, container);
16599 * while (clutter_actor_iter_next (&iter, &child))
16601 * /* do something with child */
16608 clutter_actor_iter_init (ClutterActorIter *iter,
16609 ClutterActor *root)
16611 RealActorIter *ri = (RealActorIter *) iter;
16613 g_return_if_fail (iter != NULL);
16614 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16617 ri->current = NULL;
16618 ri->age = root->priv->age;
16622 * clutter_actor_iter_next:
16623 * @iter: a #ClutterActorIter
16624 * @child: (out): return location for a #ClutterActor
16626 * Advances the @iter and retrieves the next child of the root #ClutterActor
16627 * that was used to initialize the #ClutterActorIterator.
16629 * If the iterator can advance, this function returns %TRUE and sets the
16632 * If the iterator cannot advance, this function returns %FALSE, and
16633 * the contents of @child are undefined.
16635 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16640 clutter_actor_iter_next (ClutterActorIter *iter,
16641 ClutterActor **child)
16643 RealActorIter *ri = (RealActorIter *) iter;
16645 g_return_val_if_fail (iter != NULL, FALSE);
16646 g_return_val_if_fail (ri->root != NULL, FALSE);
16647 #ifndef G_DISABLE_ASSERT
16648 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16651 if (ri->current == NULL)
16652 ri->current = ri->root->priv->first_child;
16654 ri->current = ri->current->priv->next_sibling;
16657 *child = ri->current;
16659 return ri->current != NULL;
16663 * clutter_actor_iter_prev:
16664 * @iter: a #ClutterActorIter
16665 * @child: (out): return location for a #ClutterActor
16667 * Advances the @iter and retrieves the previous child of the root
16668 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16670 * If the iterator can advance, this function returns %TRUE and sets the
16673 * If the iterator cannot advance, this function returns %FALSE, and
16674 * the contents of @child are undefined.
16676 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16681 clutter_actor_iter_prev (ClutterActorIter *iter,
16682 ClutterActor **child)
16684 RealActorIter *ri = (RealActorIter *) iter;
16686 g_return_val_if_fail (iter != NULL, FALSE);
16687 g_return_val_if_fail (ri->root != NULL, FALSE);
16688 #ifndef G_DISABLE_ASSERT
16689 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16692 if (ri->current == NULL)
16693 ri->current = ri->root->priv->last_child;
16695 ri->current = ri->current->priv->prev_sibling;
16698 *child = ri->current;
16700 return ri->current != NULL;
16704 * clutter_actor_iter_remove:
16705 * @iter: a #ClutterActorIter
16707 * Safely removes the #ClutterActor currently pointer to by the iterator
16710 * This function can only be called after clutter_actor_iter_next() or
16711 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16712 * than once for the same actor.
16714 * This function will call clutter_actor_remove_child() internally.
16719 clutter_actor_iter_remove (ClutterActorIter *iter)
16721 RealActorIter *ri = (RealActorIter *) iter;
16724 g_return_if_fail (iter != NULL);
16725 g_return_if_fail (ri->root != NULL);
16726 #ifndef G_DISABLE_ASSERT
16727 g_return_if_fail (ri->age == ri->root->priv->age);
16729 g_return_if_fail (ri->current != NULL);
16735 ri->current = cur->priv->prev_sibling;
16737 clutter_actor_remove_child_internal (ri->root, cur,
16738 REMOVE_CHILD_DEFAULT_FLAGS);
16745 * clutter_actor_iter_destroy:
16746 * @iter: a #ClutterActorIter
16748 * Safely destroys the #ClutterActor currently pointer to by the iterator
16751 * This function can only be called after clutter_actor_iter_next() or
16752 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16753 * than once for the same actor.
16755 * This function will call clutter_actor_destroy() internally.
16760 clutter_actor_iter_destroy (ClutterActorIter *iter)
16762 RealActorIter *ri = (RealActorIter *) iter;
16765 g_return_if_fail (iter != NULL);
16766 g_return_if_fail (ri->root != NULL);
16767 #ifndef G_DISABLE_ASSERT
16768 g_return_if_fail (ri->age == ri->root->priv->age);
16770 g_return_if_fail (ri->current != NULL);
16776 ri->current = cur->priv->prev_sibling;
16778 clutter_actor_destroy (cur);
16784 static const ClutterAnimationInfo default_animation_info = {
16785 NULL, /* transitions */
16787 NULL, /* cur_state */
16791 clutter_animation_info_free (gpointer data)
16795 ClutterAnimationInfo *info = data;
16797 if (info->transitions != NULL)
16798 g_hash_table_unref (info->transitions);
16800 if (info->states != NULL)
16801 g_array_unref (info->states);
16803 g_slice_free (ClutterAnimationInfo, info);
16807 const ClutterAnimationInfo *
16808 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16810 const ClutterAnimationInfo *res;
16811 GObject *obj = G_OBJECT (self);
16813 res = g_object_get_qdata (obj, quark_actor_animation_info);
16817 return &default_animation_info;
16820 ClutterAnimationInfo *
16821 _clutter_actor_get_animation_info (ClutterActor *self)
16823 GObject *obj = G_OBJECT (self);
16824 ClutterAnimationInfo *res;
16826 res = g_object_get_qdata (obj, quark_actor_animation_info);
16829 res = g_slice_new (ClutterAnimationInfo);
16831 *res = default_animation_info;
16833 g_object_set_qdata_full (obj, quark_actor_animation_info,
16835 clutter_animation_info_free);
16841 ClutterTransition *
16842 _clutter_actor_get_transition (ClutterActor *actor,
16845 const ClutterAnimationInfo *info;
16847 info = _clutter_actor_get_animation_info_or_defaults (actor);
16849 if (info->transitions == NULL)
16852 return g_hash_table_lookup (info->transitions, pspec->name);
16855 typedef struct _TransitionClosure
16857 ClutterActor *actor;
16858 ClutterTransition *transition;
16860 gulong completed_id;
16861 } TransitionClosure;
16864 transition_closure_free (gpointer data)
16866 if (G_LIKELY (data != NULL))
16868 TransitionClosure *clos = data;
16870 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16871 g_free (clos->name);
16873 g_slice_free (TransitionClosure, clos);
16878 on_transition_completed (ClutterTransition *transition,
16879 TransitionClosure *clos)
16881 ClutterAnimationInfo *info;
16883 info = _clutter_actor_get_animation_info (clos->actor);
16885 /* this will take care of cleaning clos for us */
16886 g_hash_table_remove (info->transitions, clos->name);
16890 _clutter_actor_update_transition (ClutterActor *actor,
16894 TransitionClosure *clos;
16895 ClutterInterval *interval;
16896 const ClutterAnimationInfo *info;
16899 GValue initial = G_VALUE_INIT;
16900 GValue final = G_VALUE_INIT;
16901 char *error = NULL;
16903 info = _clutter_actor_get_animation_info_or_defaults (actor);
16905 if (info->transitions == NULL)
16908 clos = g_hash_table_lookup (info->transitions, pspec->name);
16912 va_start (var_args, pspec);
16914 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16916 g_value_init (&initial, ptype);
16917 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16921 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16924 g_critical ("%s: %s", G_STRLOC, error);
16929 interval = clutter_transition_get_interval (clos->transition);
16930 clutter_interval_set_initial_value (interval, &initial);
16931 clutter_interval_set_final_value (interval, &final);
16933 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16936 g_value_unset (&initial);
16937 g_value_unset (&final);
16943 * _clutter_actor_create_transition:
16944 * @actor: a #ClutterActor
16945 * @pspec: the property used for the transition
16946 * @...: initial and final state
16948 * Creates a #ClutterTransition for the property represented by @pspec.
16950 * Return value: a #ClutterTransition
16952 ClutterTransition *
16953 _clutter_actor_create_transition (ClutterActor *actor,
16957 ClutterAnimationInfo *info;
16958 ClutterTransition *res = NULL;
16959 gboolean call_restore = FALSE;
16960 TransitionClosure *clos;
16963 info = _clutter_actor_get_animation_info (actor);
16965 if (info->states == NULL)
16967 clutter_actor_save_easing_state (actor);
16968 call_restore = TRUE;
16971 if (info->transitions == NULL)
16972 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16974 transition_closure_free);
16976 va_start (var_args, pspec);
16978 clos = g_hash_table_lookup (info->transitions, pspec->name);
16981 ClutterInterval *interval;
16982 GValue initial = G_VALUE_INIT;
16983 GValue final = G_VALUE_INIT;
16987 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16989 G_VALUE_COLLECT_INIT (&initial, ptype,
16994 g_critical ("%s: %s", G_STRLOC, error);
16999 G_VALUE_COLLECT_INIT (&final, ptype,
17005 g_critical ("%s: %s", G_STRLOC, error);
17006 g_value_unset (&initial);
17011 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17013 g_value_unset (&initial);
17014 g_value_unset (&final);
17016 res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17019 clutter_transition_set_interval (res, interval);
17020 clutter_transition_set_remove_on_complete (res, TRUE);
17022 clutter_actor_add_transition (actor, pspec->name, res);
17025 res = clos->transition;
17029 clutter_actor_restore_easing_state (actor);
17037 * clutter_actor_add_transition:
17038 * @self: a #ClutterActor
17039 * @name: the name of the transition to add
17040 * @transition: the #ClutterTransition to add
17042 * Adds a @transition to the #ClutterActor's list of animations.
17044 * The @name string is a per-actor unique identifier of the @transition: only
17045 * one #ClutterTransition can be associated to the specified @name.
17047 * The @transition will be given the easing duration, mode, and delay
17048 * associated to the actor's current easing state; it is possible to modify
17049 * these values after calling clutter_actor_add_transition().
17051 * This function is usually called implicitly when modifying an animatable
17057 clutter_actor_add_transition (ClutterActor *self,
17059 ClutterTransition *transition)
17061 ClutterTimeline *timeline;
17062 TransitionClosure *clos;
17063 ClutterAnimationInfo *info;
17065 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17066 g_return_if_fail (name != NULL);
17067 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17069 info = _clutter_actor_get_animation_info (self);
17071 if (info->cur_state == NULL)
17073 g_warning ("No easing state is defined for the actor '%s'; you "
17074 "must call clutter_actor_save_easing_state() before "
17075 "calling clutter_actor_add_transition().",
17076 _clutter_actor_get_debug_name (self));
17080 if (info->transitions == NULL)
17081 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17083 transition_closure_free);
17085 if (g_hash_table_lookup (info->transitions, name) != NULL)
17087 g_warning ("A transition with name '%s' already exists for "
17090 _clutter_actor_get_debug_name (self));
17094 timeline = CLUTTER_TIMELINE (transition);
17096 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17097 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17098 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17100 clos = g_slice_new (TransitionClosure);
17101 clos->actor = self;
17102 clos->transition = transition;
17103 clos->name = g_strdup (name);
17104 clos->completed_id = g_signal_connect (timeline, "completed",
17105 G_CALLBACK (on_transition_completed),
17108 g_hash_table_insert (info->transitions, clos->name, clos);
17112 * clutter_actor_remove_transition:
17113 * @self: a #ClutterActor
17114 * @name: the name of the transition to remove
17116 * Removes the transition stored inside a #ClutterActor using @name
17122 clutter_actor_remove_transition (ClutterActor *self,
17125 const ClutterAnimationInfo *info;
17127 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17128 g_return_if_fail (name != NULL);
17130 info = _clutter_actor_get_animation_info_or_defaults (self);
17132 if (info->transitions == NULL)
17135 g_hash_table_remove (info->transitions, name);
17139 * clutter_actor_remove_all_transitions:
17140 * @self: a #ClutterActor
17142 * Removes all transitions associated to @self.
17147 clutter_actor_remove_all_transitions (ClutterActor *self)
17149 const ClutterAnimationInfo *info;
17151 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17153 info = _clutter_actor_get_animation_info_or_defaults (self);
17154 if (info->transitions == NULL)
17157 g_hash_table_remove_all (info->transitions);
17161 * clutter_actor_set_easing_duration:
17162 * @self: a #ClutterActor
17163 * @msecs: the duration of the easing, or %NULL
17165 * Sets the duration of the tweening for animatable properties
17166 * of @self for the current easing state.
17168 * Calling this function will implicitly call
17169 * clutter_actor_save_easing_state() if no previous call to
17170 * that function was made.
17175 clutter_actor_set_easing_duration (ClutterActor *self,
17178 ClutterAnimationInfo *info;
17180 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17182 info = _clutter_actor_get_animation_info (self);
17184 if (info->states == NULL)
17185 clutter_actor_save_easing_state (self);
17187 if (info->cur_state->easing_duration != msecs)
17188 info->cur_state->easing_duration = msecs;
17192 * clutter_actor_get_easing_duration:
17193 * @self: a #ClutterActor
17195 * Retrieves the duration of the tweening for animatable
17196 * properties of @self for the current easing state.
17198 * Return value: the duration of the tweening, in milliseconds
17203 clutter_actor_get_easing_duration (ClutterActor *self)
17205 const ClutterAnimationInfo *info;
17207 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17209 info = _clutter_actor_get_animation_info_or_defaults (self);
17211 if (info->cur_state != NULL)
17212 return info->cur_state->easing_duration;
17218 * clutter_actor_set_easing_mode:
17219 * @self: a #ClutterActor
17220 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17222 * Sets the easing mode for the tweening of animatable properties
17225 * Calling this function will implicitly call
17226 * clutter_actor_save_easing_state() if no previous calls to
17227 * that function were made.
17232 clutter_actor_set_easing_mode (ClutterActor *self,
17233 ClutterAnimationMode mode)
17235 ClutterAnimationInfo *info;
17237 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17238 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17239 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17241 info = _clutter_actor_get_animation_info (self);
17243 if (info->states == NULL)
17244 clutter_actor_save_easing_state (self);
17246 if (info->cur_state->easing_mode != mode)
17247 info->cur_state->easing_mode = mode;
17251 * clutter_actor_get_easing_mode:
17252 * @self: a #ClutterActor
17254 * Retrieves the easing mode for the tweening of animatable properties
17255 * of @self for the current easing state.
17257 * Return value: an easing mode
17261 ClutterAnimationMode
17262 clutter_actor_get_easing_mode (ClutterActor *self)
17264 const ClutterAnimationInfo *info;
17266 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17268 info = _clutter_actor_get_animation_info_or_defaults (self);
17270 if (info->cur_state != NULL)
17271 return info->cur_state->easing_mode;
17273 return CLUTTER_EASE_OUT_CUBIC;
17277 * clutter_actor_set_easing_delay:
17278 * @self: a #ClutterActor
17279 * @msecs: the delay before the start of the tweening, in milliseconds
17281 * Sets the delay that should be applied before tweening animatable
17284 * Calling this function will implicitly call
17285 * clutter_actor_save_easing_state() if no previous calls to
17286 * that function were made.
17291 clutter_actor_set_easing_delay (ClutterActor *self,
17294 ClutterAnimationInfo *info;
17296 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17298 info = _clutter_actor_get_animation_info (self);
17300 if (info->states == NULL)
17301 clutter_actor_save_easing_state (self);
17303 if (info->cur_state->easing_delay != msecs)
17304 info->cur_state->easing_delay = msecs;
17308 * clutter_actor_get_easing_delay:
17309 * @self: a #ClutterActor
17311 * Retrieves the delay that should be applied when tweening animatable
17314 * Return value: a delay, in milliseconds
17319 clutter_actor_get_easing_delay (ClutterActor *self)
17321 const ClutterAnimationInfo *info;
17323 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17325 info = _clutter_actor_get_animation_info_or_defaults (self);
17327 if (info->cur_state != NULL)
17328 return info->cur_state->easing_delay;
17334 * clutter_actor_get_transition:
17335 * @self: a #ClutterActor
17336 * @name: the name of the transition
17338 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17339 * transition @name.
17341 * Transitions created for animatable properties use the name of the
17342 * property itself, for instance the code below:
17345 * clutter_actor_set_easing_duration (actor, 1000);
17346 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17348 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17349 * g_signal_connect (transition, "completed",
17350 * G_CALLBACK (on_transition_complete),
17354 * will call the <function>on_transition_complete</function> callback when
17355 * the transition is complete.
17357 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17358 * was found to match the passed name; the returned instance is owned
17359 * by Clutter and it should not be freed
17363 ClutterTransition *
17364 clutter_actor_get_transition (ClutterActor *self,
17367 TransitionClosure *clos;
17368 const ClutterAnimationInfo *info;
17370 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17371 g_return_val_if_fail (name != NULL, NULL);
17373 info = _clutter_actor_get_animation_info_or_defaults (self);
17375 if (info->transitions == NULL)
17378 clos = g_hash_table_lookup (info->transitions, name);
17382 return clos->transition;
17386 * clutter_actor_save_easing_state:
17387 * @self: a #ClutterActor
17389 * Saves the current easing state for animatable properties, and creates
17390 * a new state with the default values for easing mode and duration.
17395 clutter_actor_save_easing_state (ClutterActor *self)
17397 ClutterAnimationInfo *info;
17400 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17402 info = _clutter_actor_get_animation_info (self);
17404 if (info->states == NULL)
17405 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17407 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17408 new_state.easing_duration = 250;
17409 new_state.easing_delay = 0;
17411 g_array_append_val (info->states, new_state);
17413 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17417 * clutter_actor_restore_easing_state:
17418 * @self: a #ClutterActor
17420 * Restores the easing state as it was prior to a call to
17421 * clutter_actor_save_easing_state().
17426 clutter_actor_restore_easing_state (ClutterActor *self)
17428 ClutterAnimationInfo *info;
17430 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17432 info = _clutter_actor_get_animation_info (self);
17434 if (info->states == NULL)
17436 g_critical ("The function clutter_actor_restore_easing_state() has "
17437 "called without a previous call to "
17438 "clutter_actor_save_easing_state().");
17442 g_array_remove_index (info->states, info->states->len - 1);
17443 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17447 * clutter_actor_set_content:
17448 * @self: a #ClutterActor
17449 * @content: (allow-none): a #ClutterContent, or %NULL
17451 * Sets the contents of a #ClutterActor.
17456 clutter_actor_set_content (ClutterActor *self,
17457 ClutterContent *content)
17459 ClutterActorPrivate *priv;
17461 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17462 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17466 if (priv->content != NULL)
17468 _clutter_content_detached (priv->content, self);
17469 g_object_unref (priv->content);
17472 priv->content = content;
17474 if (priv->content != NULL)
17476 g_object_ref (priv->content);
17477 _clutter_content_attached (priv->content, self);
17480 /* given that the content is always painted within the allocation,
17481 * we only need to queue a redraw here
17483 clutter_actor_queue_redraw (self);
17485 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17487 /* if the content gravity is not resize-fill, and the new content has a
17488 * different preferred size than the previous one, then the content box
17489 * may have been changed. since we compute that lazily, we just notify
17490 * here, and let whomever watches :content-box do whatever they need to
17493 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17494 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17498 * clutter_actor_get_content:
17499 * @self: a #ClutterActor
17501 * Retrieves the contents of @self.
17503 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17504 * or %NULL if none was set
17509 clutter_actor_get_content (ClutterActor *self)
17511 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17513 return self->priv->content;
17517 * clutter_actor_set_content_gravity:
17518 * @self: a #ClutterActor
17519 * @gravity: the #ClutterContentGravity
17521 * Sets the gravity of the #ClutterContent used by @self.
17523 * See the description of the #ClutterActor:content-gravity property for
17524 * more information.
17529 clutter_actor_set_content_gravity (ClutterActor *self,
17530 ClutterContentGravity gravity)
17532 ClutterActorPrivate *priv;
17534 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17538 if (priv->content_gravity == gravity)
17541 priv->content_gravity = gravity;
17543 clutter_actor_queue_redraw (self);
17545 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17546 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17550 * clutter_actor_get_content_gravity:
17551 * @self: a #ClutterActor
17553 * Retrieves the content gravity as set using
17554 * clutter_actor_get_content_gravity().
17556 * Return value: the content gravity
17560 ClutterContentGravity
17561 clutter_actor_get_content_gravity (ClutterActor *self)
17563 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17564 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17566 return self->priv->content_gravity;
17570 * clutter_actor_get_content_box:
17571 * @self: a #ClutterActor
17572 * @box: (out caller-allocates): the return location for the bounding
17573 * box for the #ClutterContent
17575 * Retrieves the bounding box for the #ClutterContent of @self.
17577 * If no #ClutterContent is set for @self, or if @self has not been
17578 * allocated yet, then the result is undefined.
17580 * The content box is guaranteed to be, at most, as big as the allocation
17581 * of the #ClutterActor.
17583 * If the #ClutterContent used by the actor has a preferred size, then
17584 * it is possible to modify the content box by using the
17585 * #ClutterActor:content-gravity property.
17590 clutter_actor_get_content_box (ClutterActor *self,
17591 ClutterActorBox *box)
17593 ClutterActorPrivate *priv;
17594 gfloat content_w, content_h;
17595 gfloat alloc_w, alloc_h;
17597 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17598 g_return_if_fail (box != NULL);
17602 if (!clutter_actor_has_allocation (self))
17607 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17608 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17610 if (priv->content == NULL)
17613 /* no need to do any more work */
17614 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17617 /* if the content does not have a preferred size then there is
17618 * no point in computing the content box
17620 if (!clutter_content_get_preferred_size (priv->content,
17625 clutter_actor_box_get_size (&priv->allocation, &alloc_w, &alloc_h);
17627 switch (priv->content_gravity)
17629 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17630 box->x2 = box->x1 + MIN (content_w, alloc_w);
17631 box->y2 = box->y1 + MIN (content_h, alloc_h);
17634 case CLUTTER_CONTENT_GRAVITY_TOP:
17635 if (alloc_w > content_w)
17637 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17638 box->x2 = box->x1 + content_w;
17640 box->y2 = box->y1 + MIN (content_h, alloc_h);
17643 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17644 if (alloc_w > content_w)
17646 box->x1 += (alloc_w - content_w);
17647 box->x2 = box->x1 + content_w;
17649 box->y2 = box->y1 + MIN (content_h, alloc_h);
17652 case CLUTTER_CONTENT_GRAVITY_LEFT:
17653 box->x2 = box->x1 + MIN (content_w, alloc_w);
17654 if (alloc_h > content_h)
17656 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17657 box->y2 = box->y1 + content_h;
17661 case CLUTTER_CONTENT_GRAVITY_CENTER:
17662 if (alloc_w > content_w)
17664 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17665 box->x2 = box->x1 + content_w;
17667 if (alloc_h > content_h)
17669 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17670 box->y2 = box->y1 + content_h;
17674 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17675 if (alloc_w > content_w)
17677 box->x1 += (alloc_w - content_w);
17678 box->x2 = box->x1 + content_w;
17680 if (alloc_h > content_h)
17682 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17683 box->y2 = box->y1 + content_h;
17687 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17688 box->x2 = box->x1 + MIN (content_w, alloc_w);
17689 if (alloc_h > content_h)
17691 box->y1 += (alloc_h - content_h);
17692 box->y2 = box->y1 + content_h;
17696 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17697 if (alloc_w > content_w)
17699 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17700 box->x2 = box->x1 + content_w;
17702 if (alloc_h > content_h)
17704 box->y1 += (alloc_h - content_h);
17705 box->y2 = box->y1 + content_h;
17709 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17710 if (alloc_w > content_w)
17712 box->x1 += (alloc_w - content_w);
17713 box->x2 = box->x1 + content_w;
17715 if (alloc_h > content_h)
17717 box->y1 += (alloc_h - content_h);
17718 box->y2 = box->y1 + content_h;
17722 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17723 g_assert_not_reached ();
17726 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17727 if (content_w >= content_h && content_h > 0)
17729 double ratio = content_w / content_h;
17731 box->x2 = box->x1 + alloc_w;
17733 box->y1 += ceilf ((alloc_h - (alloc_h / ratio)) / 2.0);
17734 box->y2 = box->y1 + (alloc_h / ratio);
17736 else if (content_h > content_w && content_w > 0)
17738 double ratio = content_h / content_w;
17740 box->x1 += ceilf ((alloc_w - (alloc_w / ratio)) / 2.0);
17741 box->x2 = box->x2 + (alloc_w / ratio);
17743 box->y2 = box->x1 + alloc_h;