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-events">
119 * <title>Handling events on an actor</title>
120 * <para>A #ClutterActor can receive and handle input device events, for
121 * instance pointer events and key events, as long as its
122 * #ClutterActor:reactive property is set to %TRUE.</para>
123 * <para>Once an actor has been determined to be the source of an event,
124 * Clutter will traverse the scene graph from the top-level actor towards the
125 * event source, emitting the #ClutterActor::captured-event signal on each
126 * ancestor until it reaches the source; this phase is also called
127 * <emphasis>the capture phase</emphasis>. If the event propagation was not
128 * stopped, the graph is walked backwards, from the source actor to the
129 * top-level, and the #ClutterActor::event signal, along with other event
130 * signals if needed, is emitted; this phase is also called <emphasis>the
131 * bubble phase</emphasis>. At any point of the signal emission, signal
132 * handlers can stop the propagation through the scene graph by returning
133 * %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
134 * returning %CLUTTER_EVENT_PROPAGATE.</para>
137 * <refsect2 id="ClutterActor-subclassing">
138 * <title>Implementing an actor</title>
139 * <para>Careful consideration should be given when deciding to implement
140 * a #ClutterActor sub-class. It is generally recommended to implement a
141 * sub-class of #ClutterActor only for actors that should be used as leaf
142 * nodes of a scene graph.</para>
143 * <para>If your actor should be painted in a custom way, you should
144 * override the #ClutterActor::paint signal class handler. You can either
145 * opt to chain up to the parent class implementation or decide to fully
146 * override the default paint implementation; Clutter will set up the
147 * transformations and clip regions prior to emitting the #ClutterActor::paint
149 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
150 * #ClutterActorClass.get_preferred_height() virtual functions it is
151 * possible to change or provide the preferred size of an actor; similarly,
152 * by overriding the #ClutterActorClass.allocate() virtual function it is
153 * possible to control the layout of the children of an actor. Make sure to
154 * always chain up to the parent implementation of the
155 * #ClutterActorClass.allocate() virtual function.</para>
156 * <para>In general, it is strongly encouraged to use delegation and
157 * composition instead of direct subclassing.</para>
160 * <refsect2 id="ClutterActor-script">
161 * <title>ClutterActor custom properties for #ClutterScript</title>
162 * <para>#ClutterActor defines a custom "rotation" property which
163 * allows a short-hand description of the rotations to be applied
164 * to an actor.</para>
165 * <para>The syntax of the "rotation" property is the following:</para>
169 * { "<axis>" : [ <angle>, [ <center> ] ] }
173 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
174 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
175 * floating point value representing the rotation angle on the given axis,
177 * <para>The <emphasis>center</emphasis> array is optional, and if present
178 * it must contain the center of rotation as described by two coordinates:
179 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
181 * <para>#ClutterActor will also parse every positional and dimensional
182 * property defined as a string through clutter_units_from_string(); you
183 * should read the documentation for the #ClutterUnits parser format for
184 * the valid units and syntax.</para>
187 * <refsect2 id="ClutterActor-animating">
188 * <title>Custom animatable properties</title>
189 * <para>#ClutterActor allows accessing properties of #ClutterAction
190 * and #ClutterConstraint instances associated to an actor instance
191 * for animation purposes.</para>
192 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
193 * property it is necessary to set the #ClutterActorMeta:name property on the
194 * given action or constraint.</para>
195 * <para>The property can be accessed using the following syntax:</para>
198 * @<section>.<meta-name>.<property-name>
201 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
202 * <para>The <emphasis>section</emphasis> fragment can be one between
203 * "actions", "constraints" and "effects".</para>
204 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
205 * action or constraint, as specified by the #ClutterActorMeta:name
207 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
208 * action or constraint property to be animated.</para>
209 * <para>The example below animates a #ClutterBindConstraint applied to an
210 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
211 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
212 * its initial state is fully transparent and overlapping the actor to
213 * which is bound to. </para>
214 * <informalexample><programlisting>
215 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
216 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
217 * clutter_actor_add_constraint (rect, constraint);
219 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
220 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
221 * clutter_actor_add_constraint (rect, constraint);
223 * clutter_actor_set_reactive (rect, TRUE);
224 * clutter_actor_set_opacity (rect, 0);
226 * g_signal_connect (rect, "button-press-event",
227 * G_CALLBACK (on_button_press),
229 * </programlisting></informalexample>
230 * <para>On button press, the rectangle "slides" from behind the actor to
231 * which is bound to, using the #ClutterBindConstraint:offset property and
232 * the #ClutterActor:opacity property.</para>
233 * <informalexample><programlisting>
234 * float new_offset = clutter_actor_get_width (origin) + h_padding;
236 * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
238 * "@constraints.bind-x.offset", new_offset,
240 * </programlisting></informalexample>
243 * <refsect2 id="ClutterActor-animatable-properties">
244 * <title>Animatable properties</title>
245 * <para>Certain properties on #ClutterActor are marked as "animatable";
246 * these properties will be automatically tweened between the current
247 * value and the new value when one is set.</para>
248 * <para>For backward compatibility, animatable properties will only be
249 * tweened if the easing duration is greater than 0, or if a new easing
250 * state is set, for instance the following example:</para>
251 * <informalexample><programlisting>
252 * clutter_actor_save_easing_state (actor);
253 * clutter_actor_set_position (actor, 200, 200);
254 * clutter_actor_restore_easing_state (actor);
255 * </programlisting></informalexample>
256 * will tween the actor to the (200, 200) coordinates using the default
257 * easing mode and duration of a new easing state. The example above is
258 * equivalent to the following code:</para>
259 * <informalexample><programlisting>
260 * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
261 * clutter_actor_set_easing_duration (actor, 250);
262 * clutter_actor_set_position (actor, 200, 200);
263 * clutter_actor_restore_easing_state (actor);
264 * </programlisting></informalexample>
265 * <para>It is possible to nest easing states to tween animatable
266 * properties using different modes and durations, for instance:</para>
267 * <informalexample><programlisting>
268 * clutter_actor_save_easing_state (actor); /* outer state */
270 * /* set the duration of the animation to 2 seconds and change position */
271 * clutter_actor_set_easing_duration (actor, 2000);
272 * clutter_actor_set_position (actor, 0, 0);
274 * clutter_actor_save_easing_state (actor); /* inner state */
276 * /* set the duration of the animation to 5 seconds and change depth and opacity */
277 * clutter_actor_set_easing_duration (actor, 5000);
278 * clutter_actor_set_depth (actor, 200);
279 * clutter_actor_set_opacity (actor, 0);
281 * clutter_actor_restore_easing_state (actor);
283 * clutter_actor_restore_easing_state (actor);
284 * </programlisting></informalexample>
289 * CLUTTER_ACTOR_IS_MAPPED:
290 * @a: a #ClutterActor
292 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
294 * The mapped state is set when the actor is visible and all its parents up
295 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
297 * This check can be used to see if an actor is going to be painted, as only
298 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
300 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
301 * not be checked directly; instead, the recommended usage is to connect a
302 * handler on the #GObject::notify signal for the #ClutterActor:mapped
303 * property of #ClutterActor, and check the presence of
304 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
306 * It is also important to note that Clutter may delay the changes of
307 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
308 * limitations, or during the reparenting of an actor, to optimize
309 * unnecessary (and potentially expensive) state changes.
315 * CLUTTER_ACTOR_IS_REALIZED:
316 * @a: a #ClutterActor
318 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
320 * The realized state has an actor-dependant interpretation. If an
321 * actor wants to delay allocating resources until it is attached to a
322 * stage, it may use the realize state to do so. However it is
323 * perfectly acceptable for an actor to allocate Cogl resources before
324 * being realized because there is only one drawing context used by Clutter
325 * so any resources will work on any stage. If an actor is mapped it
326 * must also be realized, but an actor can be realized and unmapped
327 * (this is so hiding an actor temporarily doesn't do an expensive
328 * unrealize/realize).
330 * To be realized an actor must be inside a stage, and all its parents
337 * CLUTTER_ACTOR_IS_VISIBLE:
338 * @a: a #ClutterActor
340 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
341 * Equivalent to the ClutterActor::visible object property.
343 * Note that an actor is only painted onscreen if it's mapped, which
344 * means it's visible, and all its parents are visible, and one of the
345 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
351 * CLUTTER_ACTOR_IS_REACTIVE:
352 * @a: a #ClutterActor
354 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
356 * Only reactive actors will receive event-related signals.
367 #include <gobject/gvaluecollector.h>
369 #include <cogl/cogl.h>
371 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
372 #define CLUTTER_ENABLE_EXPERIMENTAL_API
374 #include "clutter-actor-private.h"
376 #include "clutter-action.h"
377 #include "clutter-actor-meta-private.h"
378 #include "clutter-animatable.h"
379 #include "clutter-color-static.h"
380 #include "clutter-color.h"
381 #include "clutter-constraint.h"
382 #include "clutter-container.h"
383 #include "clutter-debug.h"
384 #include "clutter-effect-private.h"
385 #include "clutter-enum-types.h"
386 #include "clutter-fixed-layout.h"
387 #include "clutter-flatten-effect.h"
388 #include "clutter-interval.h"
389 #include "clutter-main.h"
390 #include "clutter-marshal.h"
391 #include "clutter-paint-volume-private.h"
392 #include "clutter-private.h"
393 #include "clutter-profile.h"
394 #include "clutter-property-transition.h"
395 #include "clutter-scriptable.h"
396 #include "clutter-script-private.h"
397 #include "clutter-stage-private.h"
398 #include "clutter-timeline.h"
399 #include "clutter-transition.h"
400 #include "clutter-units.h"
402 #include "deprecated/clutter-actor.h"
403 #include "deprecated/clutter-behaviour.h"
404 #include "deprecated/clutter-container.h"
406 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
407 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
409 /* Internal enum used to control mapped state update. This is a hint
410 * which indicates when to do something other than just enforce
414 MAP_STATE_CHECK, /* just enforce invariants. */
415 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
416 * used when about to unparent.
418 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
419 * used to set mapped on toplevels.
421 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
422 * used just before unmapping parent.
426 /* 3 entries should be a good compromise, few layout managers
427 * will ask for 3 different preferred size in each allocation cycle */
428 #define N_CACHED_SIZE_REQUESTS 3
430 struct _ClutterActorPrivate
433 ClutterRequestMode request_mode;
435 /* our cached size requests for different width / height */
436 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
437 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
439 /* An age of 0 means the entry is not set */
440 guint cached_height_age;
441 guint cached_width_age;
443 /* the bounding box of the actor, relative to the parent's
446 ClutterActorBox allocation;
447 ClutterAllocationFlags allocation_flags;
449 /* clip, in actor coordinates */
450 cairo_rectangle_t clip;
452 /* the cached transformation matrix; see apply_transform() */
453 CoglMatrix transform;
456 gint opacity_override;
458 ClutterOffscreenRedirect offscreen_redirect;
460 /* This is an internal effect used to implement the
461 offscreen-redirect property */
462 ClutterEffect *flatten_effect;
465 ClutterActor *parent;
466 ClutterActor *prev_sibling;
467 ClutterActor *next_sibling;
468 ClutterActor *first_child;
469 ClutterActor *last_child;
473 /* tracks whenever the children of an actor are changed; the
474 * age is incremented by 1 whenever an actor is added or
475 * removed. the age is not incremented when the first or the
476 * last child pointers are changed, or when grandchildren of
477 * an actor are changed.
481 gchar *name; /* a non-unique name, used for debugging */
482 guint32 id; /* unique id, used for backward compatibility */
484 gint32 pick_id; /* per-stage unique id, used for picking */
486 /* a back-pointer to the Pango context that we can use
487 * to create pre-configured PangoLayout
489 PangoContext *pango_context;
491 /* the text direction configured for this child - either by
492 * application code, or by the actor's parent
494 ClutterTextDirection text_direction;
496 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
500 ClutterMetaGroup *actions;
501 ClutterMetaGroup *constraints;
502 ClutterMetaGroup *effects;
504 /* delegate object used to allocate the children of this actor */
505 ClutterLayoutManager *layout_manager;
507 /* used when painting, to update the paint volume */
508 ClutterEffect *current_effect;
510 /* This is used to store an effect which needs to be redrawn. A
511 redraw can be queued to start from a particular effect. This is
512 used by parametrised effects that can cache an image of the
513 actor. If a parameter of the effect changes then it only needs to
514 redraw the cached image, not the actual actor. The pointer is
515 only valid if is_dirty == TRUE. If the pointer is NULL then the
516 whole actor is dirty. */
517 ClutterEffect *effect_to_redraw;
519 /* This is used when painting effects to implement the
520 clutter_actor_continue_paint() function. It points to the node in
521 the list of effects that is next in the chain */
522 const GList *next_effect_to_paint;
524 ClutterPaintVolume paint_volume;
526 /* NB: This volume isn't relative to this actor, it is in eye
527 * coordinates so that it can remain valid after the actor changes.
529 ClutterPaintVolume last_paint_volume;
531 ClutterStageQueueRedrawEntry *queue_redraw_entry;
533 ClutterColor bg_color;
537 /* fixed position and sizes */
538 guint position_set : 1;
539 guint min_width_set : 1;
540 guint min_height_set : 1;
541 guint natural_width_set : 1;
542 guint natural_height_set : 1;
543 /* cached request is invalid (implies allocation is too) */
544 guint needs_width_request : 1;
545 /* cached request is invalid (implies allocation is too) */
546 guint needs_height_request : 1;
547 /* cached allocation is invalid (request has changed, probably) */
548 guint needs_allocation : 1;
549 guint show_on_set_parent : 1;
551 guint clip_to_allocation : 1;
552 guint enable_model_view_transform : 1;
553 guint enable_paint_unmapped : 1;
554 guint has_pointer : 1;
555 guint propagated_one_redraw : 1;
556 guint paint_volume_valid : 1;
557 guint last_paint_volume_valid : 1;
558 guint in_clone_paint : 1;
559 guint transform_valid : 1;
560 /* This is TRUE if anything has queued a redraw since we were last
561 painted. In this case effect_to_redraw will point to an effect
562 the redraw was queued from or it will be NULL if the redraw was
563 queued without an effect. */
565 guint bg_color_set : 1;
574 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
575 * when set they force a size request, when gotten they
576 * get the allocation if the allocation is valid, and the
584 /* Then the rest of these size-related properties are the "actual"
585 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
590 PROP_FIXED_POSITION_SET,
599 PROP_NATURAL_WIDTH_SET,
602 PROP_NATURAL_HEIGHT_SET,
606 /* Allocation properties are read-only */
613 PROP_CLIP_TO_ALLOCATION,
617 PROP_OFFSCREEN_REDIRECT,
630 PROP_ROTATION_ANGLE_X,
631 PROP_ROTATION_ANGLE_Y,
632 PROP_ROTATION_ANGLE_Z,
633 PROP_ROTATION_CENTER_X,
634 PROP_ROTATION_CENTER_Y,
635 PROP_ROTATION_CENTER_Z,
636 /* This property only makes sense for the z rotation because the
637 others would depend on the actor having a size along the
639 PROP_ROTATION_CENTER_Z_GRAVITY,
645 PROP_SHOW_ON_SET_PARENT,
663 PROP_BACKGROUND_COLOR,
664 PROP_BACKGROUND_COLOR_SET,
672 static GParamSpec *obj_props[PROP_LAST];
691 BUTTON_RELEASE_EVENT,
703 static guint actor_signals[LAST_SIGNAL] = { 0, };
705 static void clutter_container_iface_init (ClutterContainerIface *iface);
706 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
707 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
708 static void atk_implementor_iface_init (AtkImplementorIface *iface);
710 /* These setters are all static for now, maybe they should be in the
711 * public API, but they are perhaps obscure enough to leave only as
714 static void clutter_actor_set_min_width (ClutterActor *self,
716 static void clutter_actor_set_min_height (ClutterActor *self,
718 static void clutter_actor_set_natural_width (ClutterActor *self,
719 gfloat natural_width);
720 static void clutter_actor_set_natural_height (ClutterActor *self,
721 gfloat natural_height);
722 static void clutter_actor_set_min_width_set (ClutterActor *self,
723 gboolean use_min_width);
724 static void clutter_actor_set_min_height_set (ClutterActor *self,
725 gboolean use_min_height);
726 static void clutter_actor_set_natural_width_set (ClutterActor *self,
727 gboolean use_natural_width);
728 static void clutter_actor_set_natural_height_set (ClutterActor *self,
729 gboolean use_natural_height);
730 static void clutter_actor_update_map_state (ClutterActor *self,
731 MapStateChange change);
732 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
734 /* Helper routines for managing anchor coords */
735 static void clutter_anchor_coord_get_units (ClutterActor *self,
736 const AnchorCoord *coord,
740 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
745 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
746 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
747 ClutterGravity gravity);
749 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
751 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
753 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
754 ClutterActor *ancestor,
757 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
759 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
761 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
762 const ClutterColor *color);
764 static void on_layout_manager_changed (ClutterLayoutManager *manager,
767 /* Helper macro which translates by the anchor coord, applies the
768 given transformation and then translates back */
769 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
770 gfloat _tx, _ty, _tz; \
771 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
772 cogl_matrix_translate ((m), _tx, _ty, _tz); \
774 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
776 static GQuark quark_shader_data = 0;
777 static GQuark quark_actor_layout_info = 0;
778 static GQuark quark_actor_transform_info = 0;
779 static GQuark quark_actor_animation_info = 0;
781 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
783 G_TYPE_INITIALLY_UNOWNED,
784 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
785 clutter_container_iface_init)
786 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
787 clutter_scriptable_iface_init)
788 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
789 clutter_animatable_iface_init)
790 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
791 atk_implementor_iface_init));
794 * clutter_actor_get_debug_name:
795 * @actor: a #ClutterActor
797 * Retrieves a printable name of @actor for debugging messages
799 * Return value: a string with a printable name
802 _clutter_actor_get_debug_name (ClutterActor *actor)
804 return actor->priv->name != NULL ? actor->priv->name
805 : G_OBJECT_TYPE_NAME (actor);
808 #ifdef CLUTTER_ENABLE_DEBUG
809 /* XXX - this is for debugging only, remove once working (or leave
810 * in only in some debug mode). Should leave it for a little while
811 * until we're confident in the new map/realize/visible handling.
814 clutter_actor_verify_map_state (ClutterActor *self)
816 ClutterActorPrivate *priv = self->priv;
818 if (CLUTTER_ACTOR_IS_REALIZED (self))
820 /* all bets are off during reparent when we're potentially realized,
821 * but should not be according to invariants
823 if (!CLUTTER_ACTOR_IN_REPARENT (self))
825 if (priv->parent == NULL)
827 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
831 g_warning ("Realized non-toplevel actor '%s' should "
833 _clutter_actor_get_debug_name (self));
835 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
837 g_warning ("Realized actor %s has an unrealized parent %s",
838 _clutter_actor_get_debug_name (self),
839 _clutter_actor_get_debug_name (priv->parent));
844 if (CLUTTER_ACTOR_IS_MAPPED (self))
846 if (!CLUTTER_ACTOR_IS_REALIZED (self))
847 g_warning ("Actor '%s' is mapped but not realized",
848 _clutter_actor_get_debug_name (self));
850 /* remaining bets are off during reparent when we're potentially
851 * mapped, but should not be according to invariants
853 if (!CLUTTER_ACTOR_IN_REPARENT (self))
855 if (priv->parent == NULL)
857 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
859 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
860 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
862 g_warning ("Toplevel actor '%s' is mapped "
864 _clutter_actor_get_debug_name (self));
869 g_warning ("Mapped actor '%s' should have a parent",
870 _clutter_actor_get_debug_name (self));
875 ClutterActor *iter = self;
877 /* check for the enable_paint_unmapped flag on the actor
878 * and parents; if the flag is enabled at any point of this
879 * branch of the scene graph then all the later checks
884 if (iter->priv->enable_paint_unmapped)
887 iter = iter->priv->parent;
890 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
892 g_warning ("Actor '%s' should not be mapped if parent '%s'"
894 _clutter_actor_get_debug_name (self),
895 _clutter_actor_get_debug_name (priv->parent));
898 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
900 g_warning ("Actor '%s' should not be mapped if parent '%s'"
902 _clutter_actor_get_debug_name (self),
903 _clutter_actor_get_debug_name (priv->parent));
906 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
908 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
909 g_warning ("Actor '%s' is mapped but its non-toplevel "
910 "parent '%s' is not mapped",
911 _clutter_actor_get_debug_name (self),
912 _clutter_actor_get_debug_name (priv->parent));
919 #endif /* CLUTTER_ENABLE_DEBUG */
922 clutter_actor_set_mapped (ClutterActor *self,
925 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
930 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
931 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
935 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
936 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
940 /* this function updates the mapped and realized states according to
941 * invariants, in the appropriate order.
944 clutter_actor_update_map_state (ClutterActor *self,
945 MapStateChange change)
949 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
951 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
953 /* the mapped flag on top-level actors must be set by the
954 * per-backend implementation because it might be asynchronous.
956 * That is, the MAPPED flag on toplevels currently tracks the X
957 * server mapped-ness of the window, while the expected behavior
958 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
959 * This creates some weird complexity by breaking the invariant
960 * that if we're visible and all ancestors shown then we are
961 * also mapped - instead, we are mapped if all ancestors
962 * _possibly excepting_ the stage are mapped. The stage
963 * will map/unmap for example when it is minimized or
964 * moved to another workspace.
966 * So, the only invariant on the stage is that if visible it
967 * should be realized, and that it has to be visible to be
970 if (CLUTTER_ACTOR_IS_VISIBLE (self))
971 clutter_actor_realize (self);
975 case MAP_STATE_CHECK:
978 case MAP_STATE_MAKE_MAPPED:
979 g_assert (!was_mapped);
980 clutter_actor_set_mapped (self, TRUE);
983 case MAP_STATE_MAKE_UNMAPPED:
984 g_assert (was_mapped);
985 clutter_actor_set_mapped (self, FALSE);
988 case MAP_STATE_MAKE_UNREALIZED:
989 /* we only use MAKE_UNREALIZED in unparent,
990 * and unparenting a stage isn't possible.
991 * If someone wants to just unrealize a stage
992 * then clutter_actor_unrealize() doesn't
993 * go through this codepath.
995 g_warning ("Trying to force unrealize stage is not allowed");
999 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1000 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1001 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1003 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1004 "it is somehow still mapped",
1005 _clutter_actor_get_debug_name (self));
1010 ClutterActorPrivate *priv = self->priv;
1011 ClutterActor *parent = priv->parent;
1012 gboolean should_be_mapped;
1013 gboolean may_be_realized;
1014 gboolean must_be_realized;
1016 should_be_mapped = FALSE;
1017 may_be_realized = TRUE;
1018 must_be_realized = FALSE;
1020 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1022 may_be_realized = FALSE;
1026 /* Maintain invariant that if parent is mapped, and we are
1027 * visible, then we are mapped ... unless parent is a
1028 * stage, in which case we map regardless of parent's map
1029 * state but do require stage to be visible and realized.
1031 * If parent is realized, that does not force us to be
1032 * realized; but if parent is unrealized, that does force
1033 * us to be unrealized.
1035 * The reason we don't force children to realize with
1036 * parents is _clutter_actor_rerealize(); if we require that
1037 * a realized parent means children are realized, then to
1038 * unrealize an actor we would have to unrealize its
1039 * parents, which would end up meaning unrealizing and
1040 * hiding the entire stage. So we allow unrealizing a
1041 * child (as long as that child is not mapped) while that
1042 * child still has a realized parent.
1044 * Also, if we unrealize from leaf nodes to root, and
1045 * realize from root to leaf, the invariants are never
1046 * violated if we allow children to be unrealized
1047 * while parents are realized.
1049 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1050 * to force us to unmap, even though parent is still
1051 * mapped. This is because we're unmapping from leaf nodes
1054 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1055 change != MAP_STATE_MAKE_UNMAPPED)
1057 gboolean parent_is_visible_realized_toplevel;
1059 parent_is_visible_realized_toplevel =
1060 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1061 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1062 CLUTTER_ACTOR_IS_REALIZED (parent));
1064 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1065 parent_is_visible_realized_toplevel)
1067 must_be_realized = TRUE;
1068 should_be_mapped = TRUE;
1072 /* if the actor has been set to be painted even if unmapped
1073 * then we should map it and check for realization as well;
1074 * this is an override for the branch of the scene graph
1075 * which begins with this node
1077 if (priv->enable_paint_unmapped)
1079 if (priv->parent == NULL)
1080 g_warning ("Attempting to map an unparented actor '%s'",
1081 _clutter_actor_get_debug_name (self));
1083 should_be_mapped = TRUE;
1084 must_be_realized = TRUE;
1087 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1088 may_be_realized = FALSE;
1091 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1094 g_warning ("Attempting to map a child that does not "
1095 "meet the necessary invariants: the actor '%s' "
1097 _clutter_actor_get_debug_name (self));
1099 g_warning ("Attempting to map a child that does not "
1100 "meet the necessary invariants: the actor '%s' "
1101 "is parented to an unmapped actor '%s'",
1102 _clutter_actor_get_debug_name (self),
1103 _clutter_actor_get_debug_name (priv->parent));
1106 /* If in reparent, we temporarily suspend unmap and unrealize.
1108 * We want to go in the order "realize, map" and "unmap, unrealize"
1112 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1113 clutter_actor_set_mapped (self, FALSE);
1116 if (must_be_realized)
1117 clutter_actor_realize (self);
1119 /* if we must be realized then we may be, presumably */
1120 g_assert (!(must_be_realized && !may_be_realized));
1123 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1124 clutter_actor_unrealize_not_hiding (self);
1127 if (should_be_mapped)
1129 if (!must_be_realized)
1130 g_warning ("Somehow we think actor '%s' should be mapped but "
1131 "not realized, which isn't allowed",
1132 _clutter_actor_get_debug_name (self));
1134 /* realization is allowed to fail (though I don't know what
1135 * an app is supposed to do about that - shouldn't it just
1136 * be a g_error? anyway, we have to avoid mapping if this
1139 if (CLUTTER_ACTOR_IS_REALIZED (self))
1140 clutter_actor_set_mapped (self, TRUE);
1144 #ifdef CLUTTER_ENABLE_DEBUG
1145 /* check all invariants were kept */
1146 clutter_actor_verify_map_state (self);
1151 clutter_actor_real_map (ClutterActor *self)
1153 ClutterActorPrivate *priv = self->priv;
1154 ClutterActor *stage, *iter;
1156 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1158 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1159 _clutter_actor_get_debug_name (self));
1161 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1163 stage = _clutter_actor_get_stage_internal (self);
1164 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1166 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1168 _clutter_actor_get_debug_name (self));
1170 /* notify on parent mapped before potentially mapping
1171 * children, so apps see a top-down notification.
1173 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1175 for (iter = self->priv->first_child;
1177 iter = iter->priv->next_sibling)
1179 clutter_actor_map (iter);
1184 * clutter_actor_map:
1185 * @self: A #ClutterActor
1187 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1188 * and realizes its children if they are visible. Does nothing if the
1189 * actor is not visible.
1191 * Calling this function is strongly disencouraged: the default
1192 * implementation of #ClutterActorClass.map() will map all the children
1193 * of an actor when mapping its parent.
1195 * When overriding map, it is mandatory to chain up to the parent
1201 clutter_actor_map (ClutterActor *self)
1203 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1205 if (CLUTTER_ACTOR_IS_MAPPED (self))
1208 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1211 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1215 clutter_actor_real_unmap (ClutterActor *self)
1217 ClutterActorPrivate *priv = self->priv;
1220 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1222 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1223 _clutter_actor_get_debug_name (self));
1225 for (iter = self->priv->first_child;
1227 iter = iter->priv->next_sibling)
1229 clutter_actor_unmap (iter);
1232 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1234 /* clear the contents of the last paint volume, so that hiding + moving +
1235 * showing will not result in the wrong area being repainted
1237 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1238 priv->last_paint_volume_valid = TRUE;
1240 /* notify on parent mapped after potentially unmapping
1241 * children, so apps see a bottom-up notification.
1243 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1245 /* relinquish keyboard focus if we were unmapped while owning it */
1246 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1248 ClutterStage *stage;
1250 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1253 _clutter_stage_release_pick_id (stage, priv->pick_id);
1257 if (stage != NULL &&
1258 clutter_stage_get_key_focus (stage) == self)
1260 clutter_stage_set_key_focus (stage, NULL);
1266 * clutter_actor_unmap:
1267 * @self: A #ClutterActor
1269 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1270 * unmaps its children if they were mapped.
1272 * Calling this function is not encouraged: the default #ClutterActor
1273 * implementation of #ClutterActorClass.unmap() will also unmap any
1274 * eventual children by default when their parent is unmapped.
1276 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1277 * chain up to the parent implementation.
1279 * <note>It is important to note that the implementation of the
1280 * #ClutterActorClass.unmap() virtual function may be called after
1281 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1282 * implementation, but it is guaranteed to be called before the
1283 * #GObjectClass.finalize() implementation.</note>
1288 clutter_actor_unmap (ClutterActor *self)
1290 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1292 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1295 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1299 clutter_actor_real_show (ClutterActor *self)
1301 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1303 ClutterActorPrivate *priv = self->priv;
1305 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1307 /* we notify on the "visible" flag in the clutter_actor_show()
1308 * wrapper so the entire show signal emission completes first
1311 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1313 /* we queue a relayout unless the actor is inside a
1314 * container that explicitly told us not to
1316 if (priv->parent != NULL &&
1317 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1319 /* While an actor is hidden the parent may not have
1320 * allocated/requested so we need to start from scratch
1321 * and avoid the short-circuiting in
1322 * clutter_actor_queue_relayout().
1324 priv->needs_width_request = FALSE;
1325 priv->needs_height_request = FALSE;
1326 priv->needs_allocation = FALSE;
1327 clutter_actor_queue_relayout (self);
1333 set_show_on_set_parent (ClutterActor *self,
1336 ClutterActorPrivate *priv = self->priv;
1338 set_show = !!set_show;
1340 if (priv->show_on_set_parent == set_show)
1343 if (priv->parent == NULL)
1345 priv->show_on_set_parent = set_show;
1346 g_object_notify_by_pspec (G_OBJECT (self),
1347 obj_props[PROP_SHOW_ON_SET_PARENT]);
1352 * clutter_actor_show:
1353 * @self: A #ClutterActor
1355 * Flags an actor to be displayed. An actor that isn't shown will not
1356 * be rendered on the stage.
1358 * Actors are visible by default.
1360 * If this function is called on an actor without a parent, the
1361 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1365 clutter_actor_show (ClutterActor *self)
1367 ClutterActorPrivate *priv;
1369 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1371 /* simple optimization */
1372 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1374 /* we still need to set the :show-on-set-parent property, in
1375 * case show() is called on an unparented actor
1377 set_show_on_set_parent (self, TRUE);
1381 #ifdef CLUTTER_ENABLE_DEBUG
1382 clutter_actor_verify_map_state (self);
1387 g_object_freeze_notify (G_OBJECT (self));
1389 set_show_on_set_parent (self, TRUE);
1391 g_signal_emit (self, actor_signals[SHOW], 0);
1392 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1394 if (priv->parent != NULL)
1395 clutter_actor_queue_redraw (priv->parent);
1397 g_object_thaw_notify (G_OBJECT (self));
1401 * clutter_actor_show_all:
1402 * @self: a #ClutterActor
1404 * Calls clutter_actor_show() on all children of an actor (if any).
1408 * Deprecated: 1.10: Actors are visible by default
1411 clutter_actor_show_all (ClutterActor *self)
1413 ClutterActorClass *klass;
1415 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1417 klass = CLUTTER_ACTOR_GET_CLASS (self);
1418 if (klass->show_all)
1419 klass->show_all (self);
1423 clutter_actor_real_hide (ClutterActor *self)
1425 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1427 ClutterActorPrivate *priv = self->priv;
1429 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1431 /* we notify on the "visible" flag in the clutter_actor_hide()
1432 * wrapper so the entire hide signal emission completes first
1435 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1437 /* we queue a relayout unless the actor is inside a
1438 * container that explicitly told us not to
1440 if (priv->parent != NULL &&
1441 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1442 clutter_actor_queue_relayout (priv->parent);
1447 * clutter_actor_hide:
1448 * @self: A #ClutterActor
1450 * Flags an actor to be hidden. A hidden actor will not be
1451 * rendered on the stage.
1453 * Actors are visible by default.
1455 * If this function is called on an actor without a parent, the
1456 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1460 clutter_actor_hide (ClutterActor *self)
1462 ClutterActorPrivate *priv;
1464 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1466 /* simple optimization */
1467 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1469 /* we still need to set the :show-on-set-parent property, in
1470 * case hide() is called on an unparented actor
1472 set_show_on_set_parent (self, FALSE);
1476 #ifdef CLUTTER_ENABLE_DEBUG
1477 clutter_actor_verify_map_state (self);
1482 g_object_freeze_notify (G_OBJECT (self));
1484 set_show_on_set_parent (self, FALSE);
1486 g_signal_emit (self, actor_signals[HIDE], 0);
1487 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1489 if (priv->parent != NULL)
1490 clutter_actor_queue_redraw (priv->parent);
1492 g_object_thaw_notify (G_OBJECT (self));
1496 * clutter_actor_hide_all:
1497 * @self: a #ClutterActor
1499 * Calls clutter_actor_hide() on all child actors (if any).
1503 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1504 * prevent its children from being painted as well.
1507 clutter_actor_hide_all (ClutterActor *self)
1509 ClutterActorClass *klass;
1511 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1513 klass = CLUTTER_ACTOR_GET_CLASS (self);
1514 if (klass->hide_all)
1515 klass->hide_all (self);
1519 * clutter_actor_realize:
1520 * @self: A #ClutterActor
1522 * Realization informs the actor that it is attached to a stage. It
1523 * can use this to allocate resources if it wanted to delay allocation
1524 * until it would be rendered. However it is perfectly acceptable for
1525 * an actor to create resources before being realized because Clutter
1526 * only ever has a single rendering context so that actor is free to
1527 * be moved from one stage to another.
1529 * This function does nothing if the actor is already realized.
1531 * Because a realized actor must have realized parent actors, calling
1532 * clutter_actor_realize() will also realize all parents of the actor.
1534 * This function does not realize child actors, except in the special
1535 * case that realizing the stage, when the stage is visible, will
1536 * suddenly map (and thus realize) the children of the stage.
1539 clutter_actor_realize (ClutterActor *self)
1541 ClutterActorPrivate *priv;
1543 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1547 #ifdef CLUTTER_ENABLE_DEBUG
1548 clutter_actor_verify_map_state (self);
1551 if (CLUTTER_ACTOR_IS_REALIZED (self))
1554 /* To be realized, our parent actors must be realized first.
1555 * This will only succeed if we're inside a toplevel.
1557 if (priv->parent != NULL)
1558 clutter_actor_realize (priv->parent);
1560 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1562 /* toplevels can be realized at any time */
1566 /* "Fail" the realization if parent is missing or unrealized;
1567 * this should really be a g_warning() not some kind of runtime
1568 * failure; how can an app possibly recover? Instead it's a bug
1569 * in the app and the app should get an explanatory warning so
1570 * someone can fix it. But for now it's too hard to fix this
1571 * because e.g. ClutterTexture needs reworking.
1573 if (priv->parent == NULL ||
1574 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1578 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1580 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1581 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1583 g_signal_emit (self, actor_signals[REALIZE], 0);
1585 /* Stage actor is allowed to unset the realized flag again in its
1586 * default signal handler, though that is a pathological situation.
1589 /* If realization "failed" we'll have to update child state. */
1590 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1594 clutter_actor_real_unrealize (ClutterActor *self)
1596 /* we must be unmapped (implying our children are also unmapped) */
1597 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1601 * clutter_actor_unrealize:
1602 * @self: A #ClutterActor
1604 * Unrealization informs the actor that it may be being destroyed or
1605 * moved to another stage. The actor may want to destroy any
1606 * underlying graphics resources at this point. However it is
1607 * perfectly acceptable for it to retain the resources until the actor
1608 * is destroyed because Clutter only ever uses a single rendering
1609 * context and all of the graphics resources are valid on any stage.
1611 * Because mapped actors must be realized, actors may not be
1612 * unrealized if they are mapped. This function hides the actor to be
1613 * sure it isn't mapped, an application-visible side effect that you
1614 * may not be expecting.
1616 * This function should not be called by application code.
1619 clutter_actor_unrealize (ClutterActor *self)
1621 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1622 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1624 /* This function should not really be in the public API, because
1625 * there isn't a good reason to call it. ClutterActor will already
1626 * unrealize things for you when it's important to do so.
1628 * If you were using clutter_actor_unrealize() in a dispose
1629 * implementation, then don't, just chain up to ClutterActor's
1632 * If you were using clutter_actor_unrealize() to implement
1633 * unrealizing children of your container, then don't, ClutterActor
1634 * will already take care of that.
1636 * If you were using clutter_actor_unrealize() to re-realize to
1637 * create your resources in a different way, then use
1638 * _clutter_actor_rerealize() (inside Clutter) or just call your
1639 * code that recreates your resources directly (outside Clutter).
1642 #ifdef CLUTTER_ENABLE_DEBUG
1643 clutter_actor_verify_map_state (self);
1646 clutter_actor_hide (self);
1648 clutter_actor_unrealize_not_hiding (self);
1651 static ClutterActorTraverseVisitFlags
1652 unrealize_actor_before_children_cb (ClutterActor *self,
1656 /* If an actor is already unrealized we know its children have also
1657 * already been unrealized... */
1658 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1659 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1661 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1663 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1666 static ClutterActorTraverseVisitFlags
1667 unrealize_actor_after_children_cb (ClutterActor *self,
1671 /* We want to unset the realized flag only _after_
1672 * child actors are unrealized, to maintain invariants.
1674 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1675 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1676 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1680 * clutter_actor_unrealize_not_hiding:
1681 * @self: A #ClutterActor
1683 * Unrealization informs the actor that it may be being destroyed or
1684 * moved to another stage. The actor may want to destroy any
1685 * underlying graphics resources at this point. However it is
1686 * perfectly acceptable for it to retain the resources until the actor
1687 * is destroyed because Clutter only ever uses a single rendering
1688 * context and all of the graphics resources are valid on any stage.
1690 * Because mapped actors must be realized, actors may not be
1691 * unrealized if they are mapped. You must hide the actor or one of
1692 * its parents before attempting to unrealize.
1694 * This function is separate from clutter_actor_unrealize() because it
1695 * does not automatically hide the actor.
1696 * Actors need not be hidden to be unrealized, they just need to
1697 * be unmapped. In fact we don't want to mess up the application's
1698 * setting of the "visible" flag, so hiding is very undesirable.
1700 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1701 * backward compatibility.
1704 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1706 _clutter_actor_traverse (self,
1707 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1708 unrealize_actor_before_children_cb,
1709 unrealize_actor_after_children_cb,
1714 * _clutter_actor_rerealize:
1715 * @self: A #ClutterActor
1716 * @callback: Function to call while unrealized
1717 * @data: data for callback
1719 * If an actor is already unrealized, this just calls the callback.
1721 * If it is realized, it unrealizes temporarily, calls the callback,
1722 * and then re-realizes the actor.
1724 * As a side effect, leaves all children of the actor unrealized if
1725 * the actor was realized but not showing. This is because when we
1726 * unrealize the actor temporarily we must unrealize its children
1727 * (e.g. children of a stage can't be realized if stage window is
1728 * gone). And we aren't clever enough to save the realization state of
1729 * all children. In most cases this should not matter, because
1730 * the children will automatically realize when they next become mapped.
1733 _clutter_actor_rerealize (ClutterActor *self,
1734 ClutterCallback callback,
1737 gboolean was_mapped;
1738 gboolean was_showing;
1739 gboolean was_realized;
1741 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1743 #ifdef CLUTTER_ENABLE_DEBUG
1744 clutter_actor_verify_map_state (self);
1747 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1748 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1749 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1751 /* Must be unmapped to unrealize. Note we only have to hide this
1752 * actor if it was mapped (if all parents were showing). If actor
1753 * is merely visible (but not mapped), then that's fine, we can
1757 clutter_actor_hide (self);
1759 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1761 /* unrealize self and all children */
1762 clutter_actor_unrealize_not_hiding (self);
1764 if (callback != NULL)
1766 (* callback) (self, data);
1770 clutter_actor_show (self); /* will realize only if mapping implies it */
1771 else if (was_realized)
1772 clutter_actor_realize (self); /* realize self and all parents */
1776 clutter_actor_real_pick (ClutterActor *self,
1777 const ClutterColor *color)
1779 /* the default implementation is just to paint a rectangle
1780 * with the same size of the actor using the passed color
1782 if (clutter_actor_should_pick_paint (self))
1784 ClutterActorBox box = { 0, };
1785 float width, height;
1787 clutter_actor_get_allocation_box (self, &box);
1789 width = box.x2 - box.x1;
1790 height = box.y2 - box.y1;
1792 cogl_set_source_color4ub (color->red,
1797 cogl_rectangle (0, 0, width, height);
1800 /* XXX - this thoroughly sucks, but we need to maintain compatibility
1801 * with existing container classes that override the pick() virtual
1802 * and chain up to the default implementation - otherwise we'll end up
1803 * painting our children twice.
1805 * this has to go away for 2.0; hopefully along the pick() itself.
1807 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1811 for (iter = self->priv->first_child;
1813 iter = iter->priv->next_sibling)
1814 clutter_actor_paint (iter);
1819 * clutter_actor_should_pick_paint:
1820 * @self: A #ClutterActor
1822 * Should be called inside the implementation of the
1823 * #ClutterActor::pick virtual function in order to check whether
1824 * the actor should paint itself in pick mode or not.
1826 * This function should never be called directly by applications.
1828 * Return value: %TRUE if the actor should paint its silhouette,
1832 clutter_actor_should_pick_paint (ClutterActor *self)
1834 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1836 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1837 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1838 CLUTTER_ACTOR_IS_REACTIVE (self)))
1845 clutter_actor_real_get_preferred_width (ClutterActor *self,
1847 gfloat *min_width_p,
1848 gfloat *natural_width_p)
1850 ClutterActorPrivate *priv = self->priv;
1852 if (priv->n_children != 0 &&
1853 priv->layout_manager != NULL)
1855 ClutterContainer *container = CLUTTER_CONTAINER (self);
1857 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1858 "for the preferred width",
1859 G_OBJECT_TYPE_NAME (priv->layout_manager),
1860 priv->layout_manager);
1862 clutter_layout_manager_get_preferred_width (priv->layout_manager,
1871 /* Default implementation is always 0x0, usually an actor
1872 * using this default is relying on someone to set the
1875 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1880 if (natural_width_p)
1881 *natural_width_p = 0;
1885 clutter_actor_real_get_preferred_height (ClutterActor *self,
1887 gfloat *min_height_p,
1888 gfloat *natural_height_p)
1890 ClutterActorPrivate *priv = self->priv;
1892 if (priv->n_children != 0 &&
1893 priv->layout_manager != NULL)
1895 ClutterContainer *container = CLUTTER_CONTAINER (self);
1897 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1898 "for the preferred height",
1899 G_OBJECT_TYPE_NAME (priv->layout_manager),
1900 priv->layout_manager);
1902 clutter_layout_manager_get_preferred_height (priv->layout_manager,
1910 /* Default implementation is always 0x0, usually an actor
1911 * using this default is relying on someone to set the
1914 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1919 if (natural_height_p)
1920 *natural_height_p = 0;
1924 clutter_actor_store_old_geometry (ClutterActor *self,
1925 ClutterActorBox *box)
1927 *box = self->priv->allocation;
1931 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
1932 const ClutterActorBox *old)
1934 ClutterActorPrivate *priv = self->priv;
1935 GObject *obj = G_OBJECT (self);
1937 g_object_freeze_notify (obj);
1939 /* to avoid excessive requisition or allocation cycles we
1940 * use the cached values.
1942 * - if we don't have an allocation we assume that we need
1944 * - if we don't have a width or a height request we notify
1946 * - if we have a valid allocation then we check the old
1947 * bounding box with the current allocation and we notify
1950 if (priv->needs_allocation)
1952 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1953 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1954 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1955 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1957 else if (priv->needs_width_request || priv->needs_height_request)
1959 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1960 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1965 gfloat widthu, heightu;
1967 xu = priv->allocation.x1;
1968 yu = priv->allocation.y1;
1969 widthu = priv->allocation.x2 - priv->allocation.x1;
1970 heightu = priv->allocation.y2 - priv->allocation.y1;
1973 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1976 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1978 if (widthu != (old->x2 - old->x1))
1979 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1981 if (heightu != (old->y2 - old->y1))
1982 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1985 g_object_thaw_notify (obj);
1989 * clutter_actor_set_allocation_internal:
1990 * @self: a #ClutterActor
1991 * @box: a #ClutterActorBox
1992 * @flags: allocation flags
1994 * Stores the allocation of @self.
1996 * This function only performs basic storage and property notification.
1998 * This function should be called by clutter_actor_set_allocation()
1999 * and by the default implementation of #ClutterActorClass.allocate().
2001 * Return value: %TRUE if the allocation of the #ClutterActor has been
2002 * changed, and %FALSE otherwise
2004 static inline gboolean
2005 clutter_actor_set_allocation_internal (ClutterActor *self,
2006 const ClutterActorBox *box,
2007 ClutterAllocationFlags flags)
2009 ClutterActorPrivate *priv = self->priv;
2011 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2012 gboolean flags_changed;
2014 ClutterActorBox old_alloc = { 0, };
2016 obj = G_OBJECT (self);
2018 g_object_freeze_notify (obj);
2020 clutter_actor_store_old_geometry (self, &old_alloc);
2022 x1_changed = priv->allocation.x1 != box->x1;
2023 y1_changed = priv->allocation.y1 != box->y1;
2024 x2_changed = priv->allocation.x2 != box->x2;
2025 y2_changed = priv->allocation.y2 != box->y2;
2027 flags_changed = priv->allocation_flags != flags;
2029 priv->allocation = *box;
2030 priv->allocation_flags = flags;
2032 /* allocation is authoritative */
2033 priv->needs_width_request = FALSE;
2034 priv->needs_height_request = FALSE;
2035 priv->needs_allocation = FALSE;
2037 if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2039 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2040 _clutter_actor_get_debug_name (self));
2042 priv->transform_valid = FALSE;
2044 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2051 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2053 g_object_thaw_notify (obj);
2058 static void clutter_actor_real_allocate (ClutterActor *self,
2059 const ClutterActorBox *box,
2060 ClutterAllocationFlags flags);
2063 clutter_actor_maybe_layout_children (ClutterActor *self,
2064 const ClutterActorBox *allocation,
2065 ClutterAllocationFlags flags)
2067 ClutterActorPrivate *priv = self->priv;
2069 /* this is going to be a bit hard to follow, so let's put an explanation
2072 * we want ClutterActor to have a default layout manager if the actor was
2073 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2075 * we also want any subclass of ClutterActor that does not override the
2076 * ::allocate() virtual function to delegate to a layout manager.
2078 * finally, we want to allow people subclassing ClutterActor and overriding
2079 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2081 * on the other hand, we want existing actor subclasses overriding the
2082 * ::allocate() virtual function and chaining up to the parent's
2083 * implementation to continue working without allocating their children
2084 * twice, or without entering an allocation loop.
2086 * for the first two points, we check if the class of the actor is
2087 * overridding the ::allocate() virtual function; if it isn't, then we
2088 * follow through with checking whether we have children and a layout
2089 * manager, and eventually calling clutter_layout_manager_allocate().
2091 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2092 * allocation flags that we got passed, and if it is present, we continue
2093 * with the check above.
2095 * if neither of these two checks yields a positive result, we just
2096 * assume that the ::allocate() virtual function that resulted in this
2097 * function being called will also allocate the children of the actor.
2100 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2103 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2109 if (priv->n_children != 0 &&
2110 priv->layout_manager != NULL)
2112 ClutterContainer *container = CLUTTER_CONTAINER (self);
2113 ClutterAllocationFlags children_flags;
2114 ClutterActorBox children_box;
2116 /* normalize the box passed to the layout manager */
2117 children_box.x1 = children_box.y1 = 0.f;
2118 children_box.x2 = (allocation->x2 - allocation->x1);
2119 children_box.y2 = (allocation->y2 - allocation->y1);
2121 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2122 * the actor's children, since it refers only to the current
2123 * actor's allocation.
2125 children_flags = flags;
2126 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2128 CLUTTER_NOTE (LAYOUT,
2129 "Allocating %d children of %s "
2130 "at { %.2f, %.2f - %.2f x %.2f } "
2133 _clutter_actor_get_debug_name (self),
2136 (allocation->x2 - allocation->x1),
2137 (allocation->y2 - allocation->y1),
2138 G_OBJECT_TYPE_NAME (priv->layout_manager));
2140 clutter_layout_manager_allocate (priv->layout_manager,
2148 clutter_actor_real_allocate (ClutterActor *self,
2149 const ClutterActorBox *box,
2150 ClutterAllocationFlags flags)
2152 ClutterActorPrivate *priv = self->priv;
2155 g_object_freeze_notify (G_OBJECT (self));
2157 changed = clutter_actor_set_allocation_internal (self, box, flags);
2159 /* we allocate our children before we notify changes in our geometry,
2160 * so that people connecting to properties will be able to get valid
2161 * data out of the sub-tree of the scene graph that has this actor at
2164 clutter_actor_maybe_layout_children (self, box, flags);
2168 ClutterActorBox signal_box = priv->allocation;
2169 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2171 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2176 g_object_thaw_notify (G_OBJECT (self));
2180 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2181 ClutterActor *origin)
2183 /* no point in queuing a redraw on a destroyed actor */
2184 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2187 /* NB: We can't bail out early here if the actor is hidden in case
2188 * the actor bas been cloned. In this case the clone will need to
2189 * receive the signal so it can queue its own redraw.
2192 /* calls klass->queue_redraw in default handler */
2193 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2197 clutter_actor_real_queue_redraw (ClutterActor *self,
2198 ClutterActor *origin)
2200 ClutterActor *parent;
2202 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2203 _clutter_actor_get_debug_name (self),
2204 origin != NULL ? _clutter_actor_get_debug_name (origin)
2207 /* no point in queuing a redraw on a destroyed actor */
2208 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2211 /* If the queue redraw is coming from a child then the actor has
2212 become dirty and any queued effect is no longer valid */
2215 self->priv->is_dirty = TRUE;
2216 self->priv->effect_to_redraw = NULL;
2219 /* If the actor isn't visible, we still had to emit the signal
2220 * to allow for a ClutterClone, but the appearance of the parent
2221 * won't change so we don't have to propagate up the hierarchy.
2223 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2226 /* Although we could determine here that a full stage redraw
2227 * has already been queued and immediately bail out, we actually
2228 * guarantee that we will propagate a queue-redraw signal to our
2229 * parent at least once so that it's possible to implement a
2230 * container that tracks which of its children have queued a
2233 if (self->priv->propagated_one_redraw)
2235 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2236 if (stage != NULL &&
2237 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2241 self->priv->propagated_one_redraw = TRUE;
2243 /* notify parents, if they are all visible eventually we'll
2244 * queue redraw on the stage, which queues the redraw idle.
2246 parent = clutter_actor_get_parent (self);
2249 /* this will go up recursively */
2250 _clutter_actor_signal_queue_redraw (parent, origin);
2255 clutter_actor_real_queue_relayout (ClutterActor *self)
2257 ClutterActorPrivate *priv = self->priv;
2259 /* no point in queueing a redraw on a destroyed actor */
2260 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2263 priv->needs_width_request = TRUE;
2264 priv->needs_height_request = TRUE;
2265 priv->needs_allocation = TRUE;
2267 /* reset the cached size requests */
2268 memset (priv->width_requests, 0,
2269 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2270 memset (priv->height_requests, 0,
2271 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2273 /* We need to go all the way up the hierarchy */
2274 if (priv->parent != NULL)
2275 _clutter_actor_queue_only_relayout (priv->parent);
2279 * clutter_actor_apply_relative_transform_to_point:
2280 * @self: A #ClutterActor
2281 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2282 * default #ClutterStage
2283 * @point: A point as #ClutterVertex
2284 * @vertex: (out caller-allocates): The translated #ClutterVertex
2286 * Transforms @point in coordinates relative to the actor into
2287 * ancestor-relative coordinates using the relevant transform
2288 * stack (i.e. scale, rotation, etc).
2290 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2291 * this case, the coordinates returned will be the coordinates on
2292 * the stage before the projection is applied. This is different from
2293 * the behaviour of clutter_actor_apply_transform_to_point().
2298 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2299 ClutterActor *ancestor,
2300 const ClutterVertex *point,
2301 ClutterVertex *vertex)
2306 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2307 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2308 g_return_if_fail (point != NULL);
2309 g_return_if_fail (vertex != NULL);
2314 if (ancestor == NULL)
2315 ancestor = _clutter_actor_get_stage_internal (self);
2317 if (ancestor == NULL)
2323 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2324 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2328 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2329 const ClutterVertex *vertices_in,
2330 ClutterVertex *vertices_out,
2333 ClutterActor *stage;
2334 CoglMatrix modelview;
2335 CoglMatrix projection;
2338 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2340 stage = _clutter_actor_get_stage_internal (self);
2342 /* We really can't do anything meaningful in this case so don't try
2343 * to do any transform */
2347 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2348 * that gets us to stage coordinates, we want to go all the way to eye
2350 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2352 /* Fetch the projection and viewport */
2353 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2354 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2360 _clutter_util_fully_transform_vertices (&modelview,
2371 * clutter_actor_apply_transform_to_point:
2372 * @self: A #ClutterActor
2373 * @point: A point as #ClutterVertex
2374 * @vertex: (out caller-allocates): The translated #ClutterVertex
2376 * Transforms @point in coordinates relative to the actor
2377 * into screen-relative coordinates with the current actor
2378 * transformation (i.e. scale, rotation, etc)
2383 clutter_actor_apply_transform_to_point (ClutterActor *self,
2384 const ClutterVertex *point,
2385 ClutterVertex *vertex)
2387 g_return_if_fail (point != NULL);
2388 g_return_if_fail (vertex != NULL);
2389 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2393 * _clutter_actor_get_relative_transformation_matrix:
2394 * @self: The actor whose coordinate space you want to transform from.
2395 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2396 * or %NULL if you want to transform all the way to eye coordinates.
2397 * @matrix: A #CoglMatrix to store the transformation
2399 * This gets a transformation @matrix that will transform coordinates from the
2400 * coordinate space of @self into the coordinate space of @ancestor.
2402 * For example if you need a matrix that can transform the local actor
2403 * coordinates of @self into stage coordinates you would pass the actor's stage
2404 * pointer as the @ancestor.
2406 * If you pass %NULL then the transformation will take you all the way through
2407 * to eye coordinates. This can be useful if you want to extract the entire
2408 * modelview transform that Clutter applies before applying the projection
2409 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2410 * using cogl_set_modelview_matrix() for example then you would want a matrix
2411 * that transforms into eye coordinates.
2413 * <note><para>This function explicitly initializes the given @matrix. If you just
2414 * want clutter to multiply a relative transformation with an existing matrix
2415 * you can use clutter_actor_apply_relative_transformation_matrix()
2416 * instead.</para></note>
2419 /* XXX: We should consider caching the stage relative modelview along with
2420 * the actor itself */
2422 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2423 ClutterActor *ancestor,
2426 cogl_matrix_init_identity (matrix);
2428 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2431 /* Project the given @box into stage window coordinates, writing the
2432 * transformed vertices to @verts[]. */
2434 _clutter_actor_transform_and_project_box (ClutterActor *self,
2435 const ClutterActorBox *box,
2436 ClutterVertex verts[])
2438 ClutterVertex box_vertices[4];
2440 box_vertices[0].x = box->x1;
2441 box_vertices[0].y = box->y1;
2442 box_vertices[0].z = 0;
2443 box_vertices[1].x = box->x2;
2444 box_vertices[1].y = box->y1;
2445 box_vertices[1].z = 0;
2446 box_vertices[2].x = box->x1;
2447 box_vertices[2].y = box->y2;
2448 box_vertices[2].z = 0;
2449 box_vertices[3].x = box->x2;
2450 box_vertices[3].y = box->y2;
2451 box_vertices[3].z = 0;
2454 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2458 * clutter_actor_get_allocation_vertices:
2459 * @self: A #ClutterActor
2460 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2461 * against, or %NULL to use the #ClutterStage
2462 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2463 * location for an array of 4 #ClutterVertex in which to store the result
2465 * Calculates the transformed coordinates of the four corners of the
2466 * actor in the plane of @ancestor. The returned vertices relate to
2467 * the #ClutterActorBox coordinates as follows:
2469 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2470 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2471 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2472 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2475 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2476 * this case, the coordinates returned will be the coordinates on
2477 * the stage before the projection is applied. This is different from
2478 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2483 clutter_actor_get_allocation_vertices (ClutterActor *self,
2484 ClutterActor *ancestor,
2485 ClutterVertex verts[])
2487 ClutterActorPrivate *priv;
2488 ClutterActorBox box;
2489 ClutterVertex vertices[4];
2490 CoglMatrix modelview;
2492 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2493 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2495 if (ancestor == NULL)
2496 ancestor = _clutter_actor_get_stage_internal (self);
2498 /* Fallback to a NOP transform if the actor isn't parented under a
2500 if (ancestor == NULL)
2505 /* if the actor needs to be allocated we force a relayout, so that
2506 * we will have valid values to use in the transformations */
2507 if (priv->needs_allocation)
2509 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2511 _clutter_stage_maybe_relayout (stage);
2514 box.x1 = box.y1 = 0;
2515 /* The result isn't really meaningful in this case but at
2516 * least try to do something *vaguely* reasonable... */
2517 clutter_actor_get_size (self, &box.x2, &box.y2);
2521 clutter_actor_get_allocation_box (self, &box);
2523 vertices[0].x = box.x1;
2524 vertices[0].y = box.y1;
2526 vertices[1].x = box.x2;
2527 vertices[1].y = box.y1;
2529 vertices[2].x = box.x1;
2530 vertices[2].y = box.y2;
2532 vertices[3].x = box.x2;
2533 vertices[3].y = box.y2;
2536 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2539 cogl_matrix_transform_points (&modelview,
2541 sizeof (ClutterVertex),
2543 sizeof (ClutterVertex),
2549 * clutter_actor_get_abs_allocation_vertices:
2550 * @self: A #ClutterActor
2551 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2552 * of 4 #ClutterVertex where to store the result.
2554 * Calculates the transformed screen coordinates of the four corners of
2555 * the actor; the returned vertices relate to the #ClutterActorBox
2556 * coordinates as follows:
2558 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2559 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2560 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2561 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2567 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2568 ClutterVertex verts[])
2570 ClutterActorPrivate *priv;
2571 ClutterActorBox actor_space_allocation;
2573 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2577 /* if the actor needs to be allocated we force a relayout, so that
2578 * the actor allocation box will be valid for
2579 * _clutter_actor_transform_and_project_box()
2581 if (priv->needs_allocation)
2583 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2584 /* There's nothing meaningful we can do now */
2588 _clutter_stage_maybe_relayout (stage);
2591 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2592 * own coordinate space... */
2593 actor_space_allocation.x1 = 0;
2594 actor_space_allocation.y1 = 0;
2595 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2596 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2597 _clutter_actor_transform_and_project_box (self,
2598 &actor_space_allocation,
2603 clutter_actor_real_apply_transform (ClutterActor *self,
2606 ClutterActorPrivate *priv = self->priv;
2608 if (!priv->transform_valid)
2610 CoglMatrix *transform = &priv->transform;
2611 const ClutterTransformInfo *info;
2613 info = _clutter_actor_get_transform_info_or_defaults (self);
2615 cogl_matrix_init_identity (transform);
2617 cogl_matrix_translate (transform,
2618 priv->allocation.x1,
2619 priv->allocation.y1,
2623 cogl_matrix_translate (transform, 0, 0, info->depth);
2626 * because the rotation involves translations, we must scale
2627 * before applying the rotations (if we apply the scale after
2628 * the rotations, the translations included in the rotation are
2629 * not scaled and so the entire object will move on the screen
2630 * as a result of rotating it).
2632 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2634 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2635 &info->scale_center,
2636 cogl_matrix_scale (transform,
2643 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2645 cogl_matrix_rotate (transform,
2650 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2652 cogl_matrix_rotate (transform,
2657 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2659 cogl_matrix_rotate (transform,
2663 if (!clutter_anchor_coord_is_zero (&info->anchor))
2667 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2668 cogl_matrix_translate (transform, -x, -y, -z);
2671 priv->transform_valid = TRUE;
2674 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2677 /* Applies the transforms associated with this actor to the given
2680 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2683 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2687 * clutter_actor_apply_relative_transformation_matrix:
2688 * @self: The actor whose coordinate space you want to transform from.
2689 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2690 * or %NULL if you want to transform all the way to eye coordinates.
2691 * @matrix: A #CoglMatrix to apply the transformation too.
2693 * This multiplies a transform with @matrix that will transform coordinates
2694 * from the coordinate space of @self into the coordinate space of @ancestor.
2696 * For example if you need a matrix that can transform the local actor
2697 * coordinates of @self into stage coordinates you would pass the actor's stage
2698 * pointer as the @ancestor.
2700 * If you pass %NULL then the transformation will take you all the way through
2701 * to eye coordinates. This can be useful if you want to extract the entire
2702 * modelview transform that Clutter applies before applying the projection
2703 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2704 * using cogl_set_modelview_matrix() for example then you would want a matrix
2705 * that transforms into eye coordinates.
2707 * <note>This function doesn't initialize the given @matrix, it simply
2708 * multiplies the requested transformation matrix with the existing contents of
2709 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2710 * before calling this function, or you can use
2711 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2714 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2715 ClutterActor *ancestor,
2718 ClutterActor *parent;
2720 /* Note we terminate before ever calling stage->apply_transform()
2721 * since that would conceptually be relative to the underlying
2722 * window OpenGL coordinates so we'd need a special @ancestor
2723 * value to represent the fake parent of the stage. */
2724 if (self == ancestor)
2727 parent = clutter_actor_get_parent (self);
2730 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2733 _clutter_actor_apply_modelview_transform (self, matrix);
2737 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2738 ClutterPaintVolume *pv,
2740 const CoglColor *color)
2742 static CoglPipeline *outline = NULL;
2743 CoglPrimitive *prim;
2744 ClutterVertex line_ends[12 * 2];
2747 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2748 /* XXX: at some point we'll query this from the stage but we can't
2749 * do that until the osx backend uses Cogl natively. */
2750 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2752 if (outline == NULL)
2753 outline = cogl_pipeline_new (ctx);
2755 _clutter_paint_volume_complete (pv);
2757 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2760 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2761 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2762 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2763 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2768 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2769 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2770 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2771 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2773 /* Lines connecting front face to back face */
2774 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2775 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2776 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2777 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2780 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2782 (CoglVertexP3 *)line_ends);
2784 cogl_pipeline_set_color (outline, color);
2785 cogl_framebuffer_draw_primitive (fb, outline, prim);
2786 cogl_object_unref (prim);
2790 PangoLayout *layout;
2791 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2792 pango_layout_set_text (layout, label, -1);
2793 cogl_pango_render_layout (layout,
2798 g_object_unref (layout);
2803 _clutter_actor_draw_paint_volume (ClutterActor *self)
2805 ClutterPaintVolume *pv;
2808 pv = _clutter_actor_get_paint_volume_mutable (self);
2811 gfloat width, height;
2812 ClutterPaintVolume fake_pv;
2814 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2815 _clutter_paint_volume_init_static (&fake_pv, stage);
2817 clutter_actor_get_size (self, &width, &height);
2818 clutter_paint_volume_set_width (&fake_pv, width);
2819 clutter_paint_volume_set_height (&fake_pv, height);
2821 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2822 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2823 _clutter_actor_get_debug_name (self),
2826 clutter_paint_volume_free (&fake_pv);
2830 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2831 _clutter_actor_draw_paint_volume_full (self, pv,
2832 _clutter_actor_get_debug_name (self),
2838 _clutter_actor_paint_cull_result (ClutterActor *self,
2840 ClutterCullResult result)
2842 ClutterPaintVolume *pv;
2847 if (result == CLUTTER_CULL_RESULT_IN)
2848 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2849 else if (result == CLUTTER_CULL_RESULT_OUT)
2850 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2852 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2855 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2857 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2858 _clutter_actor_draw_paint_volume_full (self, pv,
2859 _clutter_actor_get_debug_name (self),
2863 PangoLayout *layout;
2865 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2866 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2867 cogl_set_source_color (&color);
2869 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2870 pango_layout_set_text (layout, label, -1);
2871 cogl_pango_render_layout (layout,
2877 g_object_unref (layout);
2881 static int clone_paint_level = 0;
2884 _clutter_actor_push_clone_paint (void)
2886 clone_paint_level++;
2890 _clutter_actor_pop_clone_paint (void)
2892 clone_paint_level--;
2896 in_clone_paint (void)
2898 return clone_paint_level > 0;
2901 /* Returns TRUE if the actor can be ignored */
2902 /* FIXME: we should return a ClutterCullResult, and
2903 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2904 * means there's no point in trying to cull descendants of the current
2907 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2909 ClutterActorPrivate *priv = self->priv;
2910 ClutterActor *stage;
2911 const ClutterPlane *stage_clip;
2913 if (!priv->last_paint_volume_valid)
2915 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2916 "->last_paint_volume_valid == FALSE",
2917 _clutter_actor_get_debug_name (self));
2921 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2924 stage = _clutter_actor_get_stage_internal (self);
2925 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2926 if (G_UNLIKELY (!stage_clip))
2928 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2929 "No stage clip set",
2930 _clutter_actor_get_debug_name (self));
2934 if (cogl_get_draw_framebuffer () !=
2935 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2937 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2938 "Current framebuffer doesn't correspond to stage",
2939 _clutter_actor_get_debug_name (self));
2944 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2949 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2951 ClutterActorPrivate *priv = self->priv;
2952 const ClutterPaintVolume *pv;
2954 if (priv->last_paint_volume_valid)
2956 clutter_paint_volume_free (&priv->last_paint_volume);
2957 priv->last_paint_volume_valid = FALSE;
2960 pv = clutter_actor_get_paint_volume (self);
2963 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2964 "Actor failed to report a paint volume",
2965 _clutter_actor_get_debug_name (self));
2969 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2971 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2972 NULL); /* eye coordinates */
2974 priv->last_paint_volume_valid = TRUE;
2977 static inline gboolean
2978 actor_has_shader_data (ClutterActor *self)
2980 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2984 _clutter_actor_get_pick_id (ClutterActor *self)
2986 if (self->priv->pick_id < 0)
2989 return self->priv->pick_id;
2992 /* This is the same as clutter_actor_add_effect except that it doesn't
2993 queue a redraw and it doesn't notify on the effect property */
2995 _clutter_actor_add_effect_internal (ClutterActor *self,
2996 ClutterEffect *effect)
2998 ClutterActorPrivate *priv = self->priv;
3000 if (priv->effects == NULL)
3002 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3003 priv->effects->actor = self;
3006 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3009 /* This is the same as clutter_actor_remove_effect except that it doesn't
3010 queue a redraw and it doesn't notify on the effect property */
3012 _clutter_actor_remove_effect_internal (ClutterActor *self,
3013 ClutterEffect *effect)
3015 ClutterActorPrivate *priv = self->priv;
3017 if (priv->effects == NULL)
3020 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3024 needs_flatten_effect (ClutterActor *self)
3026 ClutterActorPrivate *priv = self->priv;
3028 if (G_UNLIKELY (clutter_paint_debug_flags &
3029 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3032 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3034 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3036 if (clutter_actor_get_paint_opacity (self) < 255 &&
3037 clutter_actor_has_overlaps (self))
3045 add_or_remove_flatten_effect (ClutterActor *self)
3047 ClutterActorPrivate *priv = self->priv;
3049 /* Add or remove the flatten effect depending on the
3050 offscreen-redirect property. */
3051 if (needs_flatten_effect (self))
3053 if (priv->flatten_effect == NULL)
3055 ClutterActorMeta *actor_meta;
3058 priv->flatten_effect = _clutter_flatten_effect_new ();
3059 /* Keep a reference to the effect so that we can queue
3061 g_object_ref_sink (priv->flatten_effect);
3063 /* Set the priority of the effect to high so that it will
3064 always be applied to the actor first. It uses an internal
3065 priority so that it won't be visible to applications */
3066 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3067 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3068 _clutter_actor_meta_set_priority (actor_meta, priority);
3070 /* This will add the effect without queueing a redraw */
3071 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3076 if (priv->flatten_effect != NULL)
3078 /* Destroy the effect so that it will lose its fbo cache of
3080 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3081 g_object_unref (priv->flatten_effect);
3082 priv->flatten_effect = NULL;
3088 clutter_actor_real_paint (ClutterActor *actor)
3090 ClutterActorPrivate *priv = actor->priv;
3093 /* paint the background color, if set */
3094 if (priv->bg_color_set)
3096 float width, height;
3099 clutter_actor_box_get_size (&priv->allocation, &width, &height);
3101 real_alpha = clutter_actor_get_paint_opacity_internal (actor)
3102 * priv->bg_color.alpha
3105 cogl_set_source_color4ub (priv->bg_color.red,
3106 priv->bg_color.green,
3107 priv->bg_color.blue,
3110 cogl_rectangle (0, 0, width, height);
3113 for (iter = priv->first_child;
3115 iter = iter->priv->next_sibling)
3117 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3118 _clutter_actor_get_debug_name (iter),
3119 _clutter_actor_get_debug_name (actor),
3120 iter->priv->allocation.x1,
3121 iter->priv->allocation.y1,
3122 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3123 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3125 clutter_actor_paint (iter);
3130 * clutter_actor_paint:
3131 * @self: A #ClutterActor
3133 * Renders the actor to display.
3135 * This function should not be called directly by applications.
3136 * Call clutter_actor_queue_redraw() to queue paints, instead.
3138 * This function is context-aware, and will either cause a
3139 * regular paint or a pick paint.
3141 * This function will emit the #ClutterActor::paint signal or
3142 * the #ClutterActor::pick signal, depending on the context.
3144 * This function does not paint the actor if the actor is set to 0,
3145 * unless it is performing a pick paint.
3148 clutter_actor_paint (ClutterActor *self)
3150 ClutterActorPrivate *priv;
3151 ClutterPickMode pick_mode;
3152 gboolean clip_set = FALSE;
3153 gboolean shader_applied = FALSE;
3155 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3156 "Actor real-paint counter",
3157 "Increments each time any actor is painted",
3158 0 /* no application private data */);
3159 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3160 "Actor pick-paint counter",
3161 "Increments each time any actor is painted "
3163 0 /* no application private data */);
3165 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3167 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3172 pick_mode = _clutter_context_get_pick_mode ();
3174 if (pick_mode == CLUTTER_PICK_NONE)
3175 priv->propagated_one_redraw = FALSE;
3177 /* It's an important optimization that we consider painting of
3178 * actors with 0 opacity to be a NOP... */
3179 if (pick_mode == CLUTTER_PICK_NONE &&
3180 /* ignore top-levels, since they might be transparent */
3181 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3182 /* Use the override opacity if its been set */
3183 ((priv->opacity_override >= 0) ?
3184 priv->opacity_override : priv->opacity) == 0)
3187 /* if we aren't paintable (not in a toplevel with all
3188 * parents paintable) then do nothing.
3190 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3193 /* mark that we are in the paint process */
3194 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3198 if (priv->enable_model_view_transform)
3202 /* XXX: It could be better to cache the modelview with the actor
3203 * instead of progressively building up the transformations on
3204 * the matrix stack every time we paint. */
3205 cogl_get_modelview_matrix (&matrix);
3206 _clutter_actor_apply_modelview_transform (self, &matrix);
3208 #ifdef CLUTTER_ENABLE_DEBUG
3209 /* Catch when out-of-band transforms have been made by actors not as part
3210 * of an apply_transform vfunc... */
3211 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3213 CoglMatrix expected_matrix;
3215 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3218 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3220 GString *buf = g_string_sized_new (1024);
3221 ClutterActor *parent;
3224 while (parent != NULL)
3226 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3228 if (parent->priv->parent != NULL)
3229 g_string_append (buf, "->");
3231 parent = parent->priv->parent;
3234 g_warning ("Unexpected transform found when painting actor "
3235 "\"%s\". This will be caused by one of the actor's "
3236 "ancestors (%s) using the Cogl API directly to transform "
3237 "children instead of using ::apply_transform().",
3238 _clutter_actor_get_debug_name (self),
3241 g_string_free (buf, TRUE);
3244 #endif /* CLUTTER_ENABLE_DEBUG */
3246 cogl_set_modelview_matrix (&matrix);
3251 cogl_clip_push_rectangle (priv->clip.x,
3253 priv->clip.x + priv->clip.width,
3254 priv->clip.y + priv->clip.height);
3257 else if (priv->clip_to_allocation)
3259 gfloat width, height;
3261 width = priv->allocation.x2 - priv->allocation.x1;
3262 height = priv->allocation.y2 - priv->allocation.y1;
3264 cogl_clip_push_rectangle (0, 0, width, height);
3268 if (pick_mode == CLUTTER_PICK_NONE)
3270 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3272 /* We check whether we need to add the flatten effect before
3273 each paint so that we can avoid having a mechanism for
3274 applications to notify when the value of the
3275 has_overlaps virtual changes. */
3276 add_or_remove_flatten_effect (self);
3279 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3281 /* We save the current paint volume so that the next time the
3282 * actor queues a redraw we can constrain the redraw to just
3283 * cover the union of the new bounding box and the old.
3285 * We also fetch the current paint volume to perform culling so
3286 * we can avoid painting actors outside the current clip region.
3288 * If we are painting inside a clone, we should neither update
3289 * the paint volume or use it to cull painting, since the paint
3290 * box represents the location of the source actor on the
3293 * XXX: We are starting to do a lot of vertex transforms on
3294 * the CPU in a typical paint, so at some point we should
3295 * audit these and consider caching some things.
3297 * NB: We don't perform culling while picking at this point because
3298 * clutter-stage.c doesn't setup the clipping planes appropriately.
3300 * NB: We don't want to update the last-paint-volume during picking
3301 * because the last-paint-volume is used to determine the old screen
3302 * space location of an actor that has moved so we can know the
3303 * minimal region to redraw to clear an old view of the actor. If we
3304 * update this during picking then by the time we come around to
3305 * paint then the last-paint-volume would likely represent the new
3306 * actor position not the old.
3308 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3311 /* annoyingly gcc warns if uninitialized even though
3312 * the initialization is redundant :-( */
3313 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3315 if (G_LIKELY ((clutter_paint_debug_flags &
3316 (CLUTTER_DEBUG_DISABLE_CULLING |
3317 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3318 (CLUTTER_DEBUG_DISABLE_CULLING |
3319 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3320 _clutter_actor_update_last_paint_volume (self);
3322 success = cull_actor (self, &result);
3324 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3325 _clutter_actor_paint_cull_result (self, success, result);
3326 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3330 if (priv->effects == NULL)
3332 if (pick_mode == CLUTTER_PICK_NONE &&
3333 actor_has_shader_data (self))
3335 _clutter_actor_shader_pre_paint (self, FALSE);
3336 shader_applied = TRUE;
3339 priv->next_effect_to_paint = NULL;
3342 priv->next_effect_to_paint =
3343 _clutter_meta_group_peek_metas (priv->effects);
3345 clutter_actor_continue_paint (self);
3348 _clutter_actor_shader_post_paint (self);
3350 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3351 pick_mode == CLUTTER_PICK_NONE))
3352 _clutter_actor_draw_paint_volume (self);
3355 /* If we make it here then the actor has run through a complete
3356 paint run including all the effects so it's no longer dirty */
3357 if (pick_mode == CLUTTER_PICK_NONE)
3358 priv->is_dirty = FALSE;
3365 /* paint sequence complete */
3366 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3370 * clutter_actor_continue_paint:
3371 * @self: A #ClutterActor
3373 * Run the next stage of the paint sequence. This function should only
3374 * be called within the implementation of the ‘run’ virtual of a
3375 * #ClutterEffect. It will cause the run method of the next effect to
3376 * be applied, or it will paint the actual actor if the current effect
3377 * is the last effect in the chain.
3382 clutter_actor_continue_paint (ClutterActor *self)
3384 ClutterActorPrivate *priv;
3386 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3387 /* This should only be called from with in the ‘run’ implementation
3388 of a ClutterEffect */
3389 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3393 /* Skip any effects that are disabled */
3394 while (priv->next_effect_to_paint &&
3395 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3396 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3398 /* If this has come from the last effect then we'll just paint the
3400 if (priv->next_effect_to_paint == NULL)
3402 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3404 g_signal_emit (self, actor_signals[PAINT], 0);
3408 ClutterColor col = { 0, };
3410 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3412 /* Actor will then paint silhouette of itself in supplied
3413 * color. See clutter_stage_get_actor_at_pos() for where
3414 * picking is enabled.
3416 g_signal_emit (self, actor_signals[PICK], 0, &col);
3421 ClutterEffect *old_current_effect;
3422 ClutterEffectPaintFlags run_flags = 0;
3424 /* Cache the current effect so that we can put it back before
3426 old_current_effect = priv->current_effect;
3428 priv->current_effect = priv->next_effect_to_paint->data;
3429 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3431 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3435 /* If there's an effect queued with this redraw then all
3436 effects up to that one will be considered dirty. It
3437 is expected the queued effect will paint the cached
3438 image and not call clutter_actor_continue_paint again
3439 (although it should work ok if it does) */
3440 if (priv->effect_to_redraw == NULL ||
3441 priv->current_effect != priv->effect_to_redraw)
3442 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3445 _clutter_effect_paint (priv->current_effect, run_flags);
3449 /* We can't determine when an actor has been modified since
3450 its last pick so lets just assume it has always been
3452 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3454 _clutter_effect_pick (priv->current_effect, run_flags);
3457 priv->current_effect = old_current_effect;
3461 static ClutterActorTraverseVisitFlags
3462 invalidate_queue_redraw_entry (ClutterActor *self,
3466 ClutterActorPrivate *priv = self->priv;
3468 if (priv->queue_redraw_entry != NULL)
3470 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3471 priv->queue_redraw_entry = NULL;
3474 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3478 remove_child (ClutterActor *self,
3479 ClutterActor *child)
3481 ClutterActor *prev_sibling, *next_sibling;
3483 prev_sibling = child->priv->prev_sibling;
3484 next_sibling = child->priv->next_sibling;
3486 if (prev_sibling != NULL)
3487 prev_sibling->priv->next_sibling = next_sibling;
3489 if (next_sibling != NULL)
3490 next_sibling->priv->prev_sibling = prev_sibling;
3492 if (self->priv->first_child == child)
3493 self->priv->first_child = next_sibling;
3495 if (self->priv->last_child == child)
3496 self->priv->last_child = prev_sibling;
3498 child->priv->parent = NULL;
3499 child->priv->prev_sibling = NULL;
3500 child->priv->next_sibling = NULL;
3504 REMOVE_CHILD_DESTROY_META = 1 << 0,
3505 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3506 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3507 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3508 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3509 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3511 /* default flags for public API */
3512 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3513 REMOVE_CHILD_EMIT_PARENT_SET |
3514 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3515 REMOVE_CHILD_CHECK_STATE |
3516 REMOVE_CHILD_FLUSH_QUEUE |
3517 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3519 /* flags for legacy/deprecated API */
3520 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3521 REMOVE_CHILD_FLUSH_QUEUE |
3522 REMOVE_CHILD_EMIT_PARENT_SET |
3523 REMOVE_CHILD_NOTIFY_FIRST_LAST
3524 } ClutterActorRemoveChildFlags;
3527 * clutter_actor_remove_child_internal:
3528 * @self: a #ClutterActor
3529 * @child: the child of @self that has to be removed
3530 * @flags: control the removal operations
3532 * Removes @child from the list of children of @self.
3535 clutter_actor_remove_child_internal (ClutterActor *self,
3536 ClutterActor *child,
3537 ClutterActorRemoveChildFlags flags)
3539 ClutterActor *old_first, *old_last;
3540 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3541 gboolean flush_queue;
3542 gboolean notify_first_last;
3543 gboolean was_mapped;
3545 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3546 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3547 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3548 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3549 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3550 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3552 g_object_freeze_notify (G_OBJECT (self));
3555 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3559 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3561 /* we need to unrealize *before* we set parent_actor to NULL,
3562 * because in an unrealize method actors are dissociating from the
3563 * stage, which means they need to be able to
3564 * clutter_actor_get_stage().
3566 * yhis should unmap and unrealize, unless we're reparenting.
3568 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3575 /* We take this opportunity to invalidate any queue redraw entry
3576 * associated with the actor and descendants since we won't be able to
3577 * determine the appropriate stage after this.
3579 * we do this after we updated the mapped state because actors might
3580 * end up queueing redraws inside their mapped/unmapped virtual
3581 * functions, and if we invalidate the redraw entry we could end up
3582 * with an inconsistent state and weird memory corruption. see
3585 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3586 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3588 _clutter_actor_traverse (child,
3590 invalidate_queue_redraw_entry,
3595 old_first = self->priv->first_child;
3596 old_last = self->priv->last_child;
3598 remove_child (self, child);
3600 self->priv->n_children -= 1;
3602 self->priv->age += 1;
3604 /* clutter_actor_reparent() will emit ::parent-set for us */
3605 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3606 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3608 /* if the child was mapped then we need to relayout ourselves to account
3609 * for the removed child
3612 clutter_actor_queue_relayout (self);
3614 /* we need to emit the signal before dropping the reference */
3615 if (emit_actor_removed)
3616 g_signal_emit_by_name (self, "actor-removed", child);
3618 if (notify_first_last)
3620 if (old_first != self->priv->first_child)
3621 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3623 if (old_last != self->priv->last_child)
3624 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3627 g_object_thaw_notify (G_OBJECT (self));
3629 /* remove the reference we acquired in clutter_actor_add_child() */
3630 g_object_unref (child);
3633 static const ClutterTransformInfo default_transform_info = {
3634 0.0, { 0, }, /* rotation-x */
3635 0.0, { 0, }, /* rotation-y */
3636 0.0, { 0, }, /* rotation-z */
3638 1.0, 1.0, { 0, }, /* scale */
3640 { 0, }, /* anchor */
3646 * _clutter_actor_get_transform_info_or_defaults:
3647 * @self: a #ClutterActor
3649 * Retrieves the ClutterTransformInfo structure associated to an actor.
3651 * If the actor does not have a ClutterTransformInfo structure associated
3652 * to it, then the default structure will be returned.
3654 * This function should only be used for getters.
3656 * Return value: a const pointer to the ClutterTransformInfo structure
3658 const ClutterTransformInfo *
3659 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3661 ClutterTransformInfo *info;
3663 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3667 return &default_transform_info;
3671 clutter_transform_info_free (gpointer data)
3674 g_slice_free (ClutterTransformInfo, data);
3678 * _clutter_actor_get_transform_info:
3679 * @self: a #ClutterActor
3681 * Retrieves a pointer to the ClutterTransformInfo structure.
3683 * If the actor does not have a ClutterTransformInfo associated to it, one
3684 * will be created and initialized to the default values.
3686 * This function should be used for setters.
3688 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3691 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3694 ClutterTransformInfo *
3695 _clutter_actor_get_transform_info (ClutterActor *self)
3697 ClutterTransformInfo *info;
3699 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3702 info = g_slice_new (ClutterTransformInfo);
3704 *info = default_transform_info;
3706 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3708 clutter_transform_info_free);
3715 * clutter_actor_set_rotation_angle_internal:
3716 * @self: a #ClutterActor
3717 * @axis: the axis of the angle to change
3718 * @angle: the angle of rotation
3720 * Sets the rotation angle on the given axis without affecting the
3721 * rotation center point.
3724 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3725 ClutterRotateAxis axis,
3728 GObject *obj = G_OBJECT (self);
3729 ClutterTransformInfo *info;
3731 info = _clutter_actor_get_transform_info (self);
3733 g_object_freeze_notify (obj);
3737 case CLUTTER_X_AXIS:
3738 info->rx_angle = angle;
3739 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3742 case CLUTTER_Y_AXIS:
3743 info->ry_angle = angle;
3744 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3747 case CLUTTER_Z_AXIS:
3748 info->rz_angle = angle;
3749 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3753 self->priv->transform_valid = FALSE;
3755 g_object_thaw_notify (obj);
3757 clutter_actor_queue_redraw (self);
3761 clutter_actor_set_rotation_angle (ClutterActor *self,
3762 ClutterRotateAxis axis,
3765 ClutterTransformInfo *info;
3767 info = _clutter_actor_get_transform_info (self);
3769 if (clutter_actor_get_easing_duration (self) != 0)
3771 ClutterTransition *transition;
3772 GParamSpec *pspec = NULL;
3773 double *cur_angle_p = NULL;
3777 case CLUTTER_X_AXIS:
3778 cur_angle_p = &info->rx_angle;
3779 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3782 case CLUTTER_Y_AXIS:
3783 cur_angle_p = &info->ry_angle;
3784 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3787 case CLUTTER_Z_AXIS:
3788 cur_angle_p = &info->rz_angle;
3789 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3793 g_assert (pspec != NULL);
3794 g_assert (cur_angle_p != NULL);
3796 transition = _clutter_actor_get_transition (self, pspec);
3797 if (transition == NULL)
3799 transition = _clutter_actor_create_transition (self, pspec,
3802 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3805 _clutter_actor_update_transition (self, pspec, angle);
3807 self->priv->transform_valid = FALSE;
3808 clutter_actor_queue_redraw (self);
3811 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3815 * clutter_actor_set_rotation_center_internal:
3816 * @self: a #ClutterActor
3817 * @axis: the axis of the center to change
3818 * @center: the coordinates of the rotation center
3820 * Sets the rotation center on the given axis without affecting the
3824 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3825 ClutterRotateAxis axis,
3826 const ClutterVertex *center)
3828 GObject *obj = G_OBJECT (self);
3829 ClutterTransformInfo *info;
3830 ClutterVertex v = { 0, 0, 0 };
3832 info = _clutter_actor_get_transform_info (self);
3837 g_object_freeze_notify (obj);
3841 case CLUTTER_X_AXIS:
3842 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3843 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3846 case CLUTTER_Y_AXIS:
3847 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3848 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3851 case CLUTTER_Z_AXIS:
3852 /* if the previously set rotation center was fractional, then
3853 * setting explicit coordinates will have to notify the
3854 * :rotation-center-z-gravity property as well
3856 if (info->rz_center.is_fractional)
3857 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3859 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3860 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3864 self->priv->transform_valid = FALSE;
3866 g_object_thaw_notify (obj);
3868 clutter_actor_queue_redraw (self);
3872 clutter_actor_animate_scale_factor (ClutterActor *self,
3877 ClutterTransition *transition;
3879 transition = _clutter_actor_get_transition (self, pspec);
3880 if (transition == NULL)
3882 transition = _clutter_actor_create_transition (self, pspec,
3885 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3888 _clutter_actor_update_transition (self, pspec, new_factor);
3891 self->priv->transform_valid = FALSE;
3892 clutter_actor_queue_redraw (self);
3896 clutter_actor_set_scale_factor_internal (ClutterActor *self,
3900 GObject *obj = G_OBJECT (self);
3901 ClutterTransformInfo *info;
3903 info = _clutter_actor_get_transform_info (self);
3905 if (pspec == obj_props[PROP_SCALE_X])
3906 info->scale_x = factor;
3908 info->scale_y = factor;
3910 self->priv->transform_valid = FALSE;
3911 clutter_actor_queue_redraw (self);
3912 g_object_notify_by_pspec (obj, pspec);
3916 clutter_actor_set_scale_factor (ClutterActor *self,
3917 ClutterRotateAxis axis,
3920 GObject *obj = G_OBJECT (self);
3921 ClutterTransformInfo *info;
3924 info = _clutter_actor_get_transform_info (self);
3926 g_object_freeze_notify (obj);
3930 case CLUTTER_X_AXIS:
3931 pspec = obj_props[PROP_SCALE_X];
3933 if (clutter_actor_get_easing_duration (self) != 0)
3934 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
3936 clutter_actor_set_scale_factor_internal (self, factor, pspec);
3939 case CLUTTER_Y_AXIS:
3940 pspec = obj_props[PROP_SCALE_Y];
3942 if (clutter_actor_get_easing_duration (self) != 0)
3943 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
3945 clutter_actor_set_scale_factor_internal (self, factor, pspec);
3949 g_assert_not_reached ();
3952 g_object_thaw_notify (obj);
3956 clutter_actor_set_scale_center (ClutterActor *self,
3957 ClutterRotateAxis axis,
3960 GObject *obj = G_OBJECT (self);
3961 ClutterTransformInfo *info;
3962 gfloat center_x, center_y;
3964 info = _clutter_actor_get_transform_info (self);
3966 g_object_freeze_notify (obj);
3968 /* get the current scale center coordinates */
3969 clutter_anchor_coord_get_units (self, &info->scale_center,
3974 /* we need to notify this too, because setting explicit coordinates will
3975 * change the gravity as a side effect
3977 if (info->scale_center.is_fractional)
3978 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
3982 case CLUTTER_X_AXIS:
3983 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
3984 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
3987 case CLUTTER_Y_AXIS:
3988 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
3989 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
3993 g_assert_not_reached ();
3996 self->priv->transform_valid = FALSE;
3998 clutter_actor_queue_redraw (self);
4000 g_object_thaw_notify (obj);
4004 clutter_actor_set_anchor_coord (ClutterActor *self,
4005 ClutterRotateAxis axis,
4008 GObject *obj = G_OBJECT (self);
4009 ClutterTransformInfo *info;
4010 gfloat anchor_x, anchor_y;
4012 info = _clutter_actor_get_transform_info (self);
4014 g_object_freeze_notify (obj);
4016 clutter_anchor_coord_get_units (self, &info->anchor,
4021 if (info->anchor.is_fractional)
4022 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4026 case CLUTTER_X_AXIS:
4027 clutter_anchor_coord_set_units (&info->anchor,
4031 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4034 case CLUTTER_Y_AXIS:
4035 clutter_anchor_coord_set_units (&info->anchor,
4039 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4043 g_assert_not_reached ();
4046 self->priv->transform_valid = FALSE;
4048 clutter_actor_queue_redraw (self);
4050 g_object_thaw_notify (obj);
4054 clutter_actor_set_property (GObject *object,
4056 const GValue *value,
4059 ClutterActor *actor = CLUTTER_ACTOR (object);
4060 ClutterActorPrivate *priv = actor->priv;
4065 clutter_actor_set_x (actor, g_value_get_float (value));
4069 clutter_actor_set_y (actor, g_value_get_float (value));
4073 clutter_actor_set_width (actor, g_value_get_float (value));
4077 clutter_actor_set_height (actor, g_value_get_float (value));
4081 clutter_actor_set_x (actor, g_value_get_float (value));
4085 clutter_actor_set_y (actor, g_value_get_float (value));
4088 case PROP_FIXED_POSITION_SET:
4089 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4092 case PROP_MIN_WIDTH:
4093 clutter_actor_set_min_width (actor, g_value_get_float (value));
4096 case PROP_MIN_HEIGHT:
4097 clutter_actor_set_min_height (actor, g_value_get_float (value));
4100 case PROP_NATURAL_WIDTH:
4101 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4104 case PROP_NATURAL_HEIGHT:
4105 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4108 case PROP_MIN_WIDTH_SET:
4109 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4112 case PROP_MIN_HEIGHT_SET:
4113 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4116 case PROP_NATURAL_WIDTH_SET:
4117 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4120 case PROP_NATURAL_HEIGHT_SET:
4121 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4124 case PROP_REQUEST_MODE:
4125 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4129 clutter_actor_set_depth (actor, g_value_get_float (value));
4133 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4136 case PROP_OFFSCREEN_REDIRECT:
4137 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4141 clutter_actor_set_name (actor, g_value_get_string (value));
4145 if (g_value_get_boolean (value) == TRUE)
4146 clutter_actor_show (actor);
4148 clutter_actor_hide (actor);
4152 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4153 g_value_get_double (value));
4157 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4158 g_value_get_double (value));
4161 case PROP_SCALE_CENTER_X:
4162 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4163 g_value_get_float (value));
4166 case PROP_SCALE_CENTER_Y:
4167 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4168 g_value_get_float (value));
4171 case PROP_SCALE_GRAVITY:
4173 const ClutterTransformInfo *info;
4174 ClutterGravity gravity;
4176 info = _clutter_actor_get_transform_info_or_defaults (actor);
4177 gravity = g_value_get_enum (value);
4179 clutter_actor_set_scale_with_gravity (actor,
4188 const ClutterGeometry *geom = g_value_get_boxed (value);
4190 clutter_actor_set_clip (actor,
4192 geom->width, geom->height);
4196 case PROP_CLIP_TO_ALLOCATION:
4197 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4201 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4204 case PROP_ROTATION_ANGLE_X:
4205 clutter_actor_set_rotation_angle (actor,
4207 g_value_get_double (value));
4210 case PROP_ROTATION_ANGLE_Y:
4211 clutter_actor_set_rotation_angle (actor,
4213 g_value_get_double (value));
4216 case PROP_ROTATION_ANGLE_Z:
4217 clutter_actor_set_rotation_angle (actor,
4219 g_value_get_double (value));
4222 case PROP_ROTATION_CENTER_X:
4223 clutter_actor_set_rotation_center_internal (actor,
4225 g_value_get_boxed (value));
4228 case PROP_ROTATION_CENTER_Y:
4229 clutter_actor_set_rotation_center_internal (actor,
4231 g_value_get_boxed (value));
4234 case PROP_ROTATION_CENTER_Z:
4235 clutter_actor_set_rotation_center_internal (actor,
4237 g_value_get_boxed (value));
4240 case PROP_ROTATION_CENTER_Z_GRAVITY:
4242 const ClutterTransformInfo *info;
4244 info = _clutter_actor_get_transform_info_or_defaults (actor);
4245 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4246 g_value_get_enum (value));
4251 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4252 g_value_get_float (value));
4256 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4257 g_value_get_float (value));
4260 case PROP_ANCHOR_GRAVITY:
4261 clutter_actor_set_anchor_point_from_gravity (actor,
4262 g_value_get_enum (value));
4265 case PROP_SHOW_ON_SET_PARENT:
4266 priv->show_on_set_parent = g_value_get_boolean (value);
4269 case PROP_TEXT_DIRECTION:
4270 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4274 clutter_actor_add_action (actor, g_value_get_object (value));
4277 case PROP_CONSTRAINTS:
4278 clutter_actor_add_constraint (actor, g_value_get_object (value));
4282 clutter_actor_add_effect (actor, g_value_get_object (value));
4285 case PROP_LAYOUT_MANAGER:
4286 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4290 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4294 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4297 case PROP_MARGIN_TOP:
4298 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4301 case PROP_MARGIN_BOTTOM:
4302 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4305 case PROP_MARGIN_LEFT:
4306 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4309 case PROP_MARGIN_RIGHT:
4310 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4313 case PROP_BACKGROUND_COLOR:
4314 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4318 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4324 clutter_actor_get_property (GObject *object,
4329 ClutterActor *actor = CLUTTER_ACTOR (object);
4330 ClutterActorPrivate *priv = actor->priv;
4335 g_value_set_float (value, clutter_actor_get_x (actor));
4339 g_value_set_float (value, clutter_actor_get_y (actor));
4343 g_value_set_float (value, clutter_actor_get_width (actor));
4347 g_value_set_float (value, clutter_actor_get_height (actor));
4352 const ClutterLayoutInfo *info;
4354 info = _clutter_actor_get_layout_info_or_defaults (actor);
4355 g_value_set_float (value, info->fixed_x);
4361 const ClutterLayoutInfo *info;
4363 info = _clutter_actor_get_layout_info_or_defaults (actor);
4364 g_value_set_float (value, info->fixed_y);
4368 case PROP_FIXED_POSITION_SET:
4369 g_value_set_boolean (value, priv->position_set);
4372 case PROP_MIN_WIDTH:
4374 const ClutterLayoutInfo *info;
4376 info = _clutter_actor_get_layout_info_or_defaults (actor);
4377 g_value_set_float (value, info->min_width);
4381 case PROP_MIN_HEIGHT:
4383 const ClutterLayoutInfo *info;
4385 info = _clutter_actor_get_layout_info_or_defaults (actor);
4386 g_value_set_float (value, info->min_height);
4390 case PROP_NATURAL_WIDTH:
4392 const ClutterLayoutInfo *info;
4394 info = _clutter_actor_get_layout_info_or_defaults (actor);
4395 g_value_set_float (value, info->natural_width);
4399 case PROP_NATURAL_HEIGHT:
4401 const ClutterLayoutInfo *info;
4403 info = _clutter_actor_get_layout_info_or_defaults (actor);
4404 g_value_set_float (value, info->natural_height);
4408 case PROP_MIN_WIDTH_SET:
4409 g_value_set_boolean (value, priv->min_width_set);
4412 case PROP_MIN_HEIGHT_SET:
4413 g_value_set_boolean (value, priv->min_height_set);
4416 case PROP_NATURAL_WIDTH_SET:
4417 g_value_set_boolean (value, priv->natural_width_set);
4420 case PROP_NATURAL_HEIGHT_SET:
4421 g_value_set_boolean (value, priv->natural_height_set);
4424 case PROP_REQUEST_MODE:
4425 g_value_set_enum (value, priv->request_mode);
4428 case PROP_ALLOCATION:
4429 g_value_set_boxed (value, &priv->allocation);
4433 g_value_set_float (value, clutter_actor_get_depth (actor));
4437 g_value_set_uint (value, priv->opacity);
4440 case PROP_OFFSCREEN_REDIRECT:
4441 g_value_set_enum (value, priv->offscreen_redirect);
4445 g_value_set_string (value, priv->name);
4449 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4453 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4457 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4461 g_value_set_boolean (value, priv->has_clip);
4466 ClutterGeometry clip;
4468 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4469 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4470 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4471 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4473 g_value_set_boxed (value, &clip);
4477 case PROP_CLIP_TO_ALLOCATION:
4478 g_value_set_boolean (value, priv->clip_to_allocation);
4483 const ClutterTransformInfo *info;
4485 info = _clutter_actor_get_transform_info_or_defaults (actor);
4486 g_value_set_double (value, info->scale_x);
4492 const ClutterTransformInfo *info;
4494 info = _clutter_actor_get_transform_info_or_defaults (actor);
4495 g_value_set_double (value, info->scale_y);
4499 case PROP_SCALE_CENTER_X:
4503 clutter_actor_get_scale_center (actor, ¢er, NULL);
4505 g_value_set_float (value, center);
4509 case PROP_SCALE_CENTER_Y:
4513 clutter_actor_get_scale_center (actor, NULL, ¢er);
4515 g_value_set_float (value, center);
4519 case PROP_SCALE_GRAVITY:
4520 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4524 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4527 case PROP_ROTATION_ANGLE_X:
4529 const ClutterTransformInfo *info;
4531 info = _clutter_actor_get_transform_info_or_defaults (actor);
4532 g_value_set_double (value, info->rx_angle);
4536 case PROP_ROTATION_ANGLE_Y:
4538 const ClutterTransformInfo *info;
4540 info = _clutter_actor_get_transform_info_or_defaults (actor);
4541 g_value_set_double (value, info->ry_angle);
4545 case PROP_ROTATION_ANGLE_Z:
4547 const ClutterTransformInfo *info;
4549 info = _clutter_actor_get_transform_info_or_defaults (actor);
4550 g_value_set_double (value, info->rz_angle);
4554 case PROP_ROTATION_CENTER_X:
4556 ClutterVertex center;
4558 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4563 g_value_set_boxed (value, ¢er);
4567 case PROP_ROTATION_CENTER_Y:
4569 ClutterVertex center;
4571 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4576 g_value_set_boxed (value, ¢er);
4580 case PROP_ROTATION_CENTER_Z:
4582 ClutterVertex center;
4584 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4589 g_value_set_boxed (value, ¢er);
4593 case PROP_ROTATION_CENTER_Z_GRAVITY:
4594 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4599 const ClutterTransformInfo *info;
4602 info = _clutter_actor_get_transform_info_or_defaults (actor);
4603 clutter_anchor_coord_get_units (actor, &info->anchor,
4607 g_value_set_float (value, anchor_x);
4613 const ClutterTransformInfo *info;
4616 info = _clutter_actor_get_transform_info_or_defaults (actor);
4617 clutter_anchor_coord_get_units (actor, &info->anchor,
4621 g_value_set_float (value, anchor_y);
4625 case PROP_ANCHOR_GRAVITY:
4626 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4629 case PROP_SHOW_ON_SET_PARENT:
4630 g_value_set_boolean (value, priv->show_on_set_parent);
4633 case PROP_TEXT_DIRECTION:
4634 g_value_set_enum (value, priv->text_direction);
4637 case PROP_HAS_POINTER:
4638 g_value_set_boolean (value, priv->has_pointer);
4641 case PROP_LAYOUT_MANAGER:
4642 g_value_set_object (value, priv->layout_manager);
4647 const ClutterLayoutInfo *info;
4649 info = _clutter_actor_get_layout_info_or_defaults (actor);
4650 g_value_set_enum (value, info->x_align);
4656 const ClutterLayoutInfo *info;
4658 info = _clutter_actor_get_layout_info_or_defaults (actor);
4659 g_value_set_enum (value, info->y_align);
4663 case PROP_MARGIN_TOP:
4665 const ClutterLayoutInfo *info;
4667 info = _clutter_actor_get_layout_info_or_defaults (actor);
4668 g_value_set_float (value, info->margin.top);
4672 case PROP_MARGIN_BOTTOM:
4674 const ClutterLayoutInfo *info;
4676 info = _clutter_actor_get_layout_info_or_defaults (actor);
4677 g_value_set_float (value, info->margin.bottom);
4681 case PROP_MARGIN_LEFT:
4683 const ClutterLayoutInfo *info;
4685 info = _clutter_actor_get_layout_info_or_defaults (actor);
4686 g_value_set_float (value, info->margin.left);
4690 case PROP_MARGIN_RIGHT:
4692 const ClutterLayoutInfo *info;
4694 info = _clutter_actor_get_layout_info_or_defaults (actor);
4695 g_value_set_float (value, info->margin.right);
4699 case PROP_BACKGROUND_COLOR_SET:
4700 g_value_set_boolean (value, priv->bg_color_set);
4703 case PROP_BACKGROUND_COLOR:
4704 g_value_set_boxed (value, &priv->bg_color);
4707 case PROP_FIRST_CHILD:
4708 g_value_set_object (value, priv->first_child);
4711 case PROP_LAST_CHILD:
4712 g_value_set_object (value, priv->last_child);
4716 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4722 clutter_actor_dispose (GObject *object)
4724 ClutterActor *self = CLUTTER_ACTOR (object);
4725 ClutterActorPrivate *priv = self->priv;
4727 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4729 g_type_name (G_OBJECT_TYPE (self)),
4732 g_signal_emit (self, actor_signals[DESTROY], 0);
4734 /* avoid recursing when called from clutter_actor_destroy() */
4735 if (priv->parent != NULL)
4737 ClutterActor *parent = priv->parent;
4739 /* go through the Container implementation unless this
4740 * is an internal child and has been marked as such.
4742 * removing the actor from its parent will reset the
4743 * realized and mapped states.
4745 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4746 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4748 clutter_actor_remove_child_internal (parent, self,
4749 REMOVE_CHILD_LEGACY_FLAGS);
4752 /* parent must be gone at this point */
4753 g_assert (priv->parent == NULL);
4755 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4757 /* can't be mapped or realized with no parent */
4758 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4759 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4762 g_clear_object (&priv->pango_context);
4763 g_clear_object (&priv->actions);
4764 g_clear_object (&priv->constraints);
4765 g_clear_object (&priv->effects);
4766 g_clear_object (&priv->flatten_effect);
4768 if (priv->layout_manager != NULL)
4770 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4771 g_object_unref (priv->layout_manager);
4772 priv->layout_manager = NULL;
4775 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4779 clutter_actor_finalize (GObject *object)
4781 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4783 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4784 priv->name != NULL ? priv->name : "<none>",
4786 g_type_name (G_OBJECT_TYPE (object)));
4788 _clutter_context_release_id (priv->id);
4790 g_free (priv->name);
4792 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4797 * clutter_actor_get_accessible:
4798 * @self: a #ClutterActor
4800 * Returns the accessible object that describes the actor to an
4801 * assistive technology.
4803 * If no class-specific #AtkObject implementation is available for the
4804 * actor instance in question, it will inherit an #AtkObject
4805 * implementation from the first ancestor class for which such an
4806 * implementation is defined.
4808 * The documentation of the <ulink
4809 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4810 * library contains more information about accessible objects and
4813 * Returns: (transfer none): the #AtkObject associated with @actor
4816 clutter_actor_get_accessible (ClutterActor *self)
4818 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4820 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4824 clutter_actor_real_get_accessible (ClutterActor *actor)
4826 return atk_gobject_accessible_for_object (G_OBJECT (actor));
4830 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4832 AtkObject *accessible;
4834 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4835 if (accessible != NULL)
4836 g_object_ref (accessible);
4842 atk_implementor_iface_init (AtkImplementorIface *iface)
4844 iface->ref_accessible = _clutter_actor_ref_accessible;
4848 clutter_actor_update_default_paint_volume (ClutterActor *self,
4849 ClutterPaintVolume *volume)
4851 ClutterActorPrivate *priv = self->priv;
4852 gboolean res = FALSE;
4854 /* we start from the allocation */
4855 clutter_paint_volume_set_width (volume,
4856 priv->allocation.x2 - priv->allocation.x1);
4857 clutter_paint_volume_set_height (volume,
4858 priv->allocation.y2 - priv->allocation.y1);
4860 /* if the actor has a clip set then we have a pretty definite
4861 * size for the paint volume: the actor cannot possibly paint
4862 * outside the clip region.
4864 if (priv->clip_to_allocation)
4866 /* the allocation has already been set, so we just flip the
4873 ClutterActor *child;
4875 if (priv->has_clip &&
4876 priv->clip.width >= 0 &&
4877 priv->clip.height >= 0)
4879 ClutterVertex origin;
4881 origin.x = priv->clip.x;
4882 origin.y = priv->clip.y;
4885 clutter_paint_volume_set_origin (volume, &origin);
4886 clutter_paint_volume_set_width (volume, priv->clip.width);
4887 clutter_paint_volume_set_height (volume, priv->clip.height);
4892 /* if we don't have children we just bail out here... */
4893 if (priv->n_children == 0)
4896 /* ...but if we have children then we ask for their paint volume in
4897 * our coordinates. if any of our children replies that it doesn't
4898 * have a paint volume, we bail out
4900 for (child = priv->first_child;
4902 child = child->priv->next_sibling)
4904 const ClutterPaintVolume *child_volume;
4906 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4907 if (child_volume == NULL)
4913 clutter_paint_volume_union (volume, child_volume);
4923 clutter_actor_real_get_paint_volume (ClutterActor *self,
4924 ClutterPaintVolume *volume)
4926 ClutterActorClass *klass;
4929 klass = CLUTTER_ACTOR_GET_CLASS (self);
4931 /* XXX - this thoroughly sucks, but we don't want to penalize users
4932 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4933 * redraw. This should go away in 2.0.
4935 if (klass->paint == clutter_actor_real_paint &&
4936 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4942 /* this is the default return value: we cannot know if a class
4943 * is going to paint outside its allocation, so we take the
4944 * conservative approach.
4949 if (clutter_actor_update_default_paint_volume (self, volume))
4956 * clutter_actor_get_default_paint_volume:
4957 * @self: a #ClutterActor
4959 * Retrieves the default paint volume for @self.
4961 * This function provides the same #ClutterPaintVolume that would be
4962 * computed by the default implementation inside #ClutterActor of the
4963 * #ClutterActorClass.get_paint_volume() virtual function.
4965 * This function should only be used by #ClutterActor subclasses that
4966 * cannot chain up to the parent implementation when computing their
4969 * Return value: (transfer none): a pointer to the default
4970 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
4971 * the actor could not compute a valid paint volume. The returned value
4972 * is not guaranteed to be stable across multiple frames, so if you
4973 * want to retain it, you will need to copy it using
4974 * clutter_paint_volume_copy().
4978 const ClutterPaintVolume *
4979 clutter_actor_get_default_paint_volume (ClutterActor *self)
4981 ClutterPaintVolume volume;
4982 ClutterPaintVolume *res;
4984 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4987 _clutter_paint_volume_init_static (&volume, self);
4988 if (clutter_actor_update_default_paint_volume (self, &volume))
4990 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
4994 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
4995 _clutter_paint_volume_copy_static (&volume, res);
4999 clutter_paint_volume_free (&volume);
5005 clutter_actor_real_has_overlaps (ClutterActor *self)
5007 /* By default we'll assume that all actors need an offscreen redirect to get
5008 * the correct opacity. Actors such as ClutterTexture that would never need
5009 * an offscreen redirect can override this to return FALSE. */
5014 clutter_actor_real_destroy (ClutterActor *actor)
5016 ClutterActorIter iter;
5018 clutter_actor_iter_init (&iter, actor);
5019 while (clutter_actor_iter_next (&iter, NULL))
5020 clutter_actor_iter_destroy (&iter);
5024 clutter_actor_constructor (GType gtype,
5026 GObjectConstructParam *props)
5028 GObjectClass *gobject_class;
5032 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5033 retval = gobject_class->constructor (gtype, n_props, props);
5034 self = CLUTTER_ACTOR (retval);
5036 if (self->priv->layout_manager == NULL)
5038 ClutterLayoutManager *default_layout;
5040 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5042 default_layout = clutter_fixed_layout_new ();
5043 clutter_actor_set_layout_manager (self, default_layout);
5050 clutter_actor_class_init (ClutterActorClass *klass)
5052 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5054 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5055 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5056 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5057 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5059 object_class->constructor = clutter_actor_constructor;
5060 object_class->set_property = clutter_actor_set_property;
5061 object_class->get_property = clutter_actor_get_property;
5062 object_class->dispose = clutter_actor_dispose;
5063 object_class->finalize = clutter_actor_finalize;
5065 klass->show = clutter_actor_real_show;
5066 klass->show_all = clutter_actor_show;
5067 klass->hide = clutter_actor_real_hide;
5068 klass->hide_all = clutter_actor_hide;
5069 klass->map = clutter_actor_real_map;
5070 klass->unmap = clutter_actor_real_unmap;
5071 klass->unrealize = clutter_actor_real_unrealize;
5072 klass->pick = clutter_actor_real_pick;
5073 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5074 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5075 klass->allocate = clutter_actor_real_allocate;
5076 klass->queue_redraw = clutter_actor_real_queue_redraw;
5077 klass->queue_relayout = clutter_actor_real_queue_relayout;
5078 klass->apply_transform = clutter_actor_real_apply_transform;
5079 klass->get_accessible = clutter_actor_real_get_accessible;
5080 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5081 klass->has_overlaps = clutter_actor_real_has_overlaps;
5082 klass->paint = clutter_actor_real_paint;
5083 klass->destroy = clutter_actor_real_destroy;
5085 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5090 * X coordinate of the actor in pixels. If written, forces a fixed
5091 * position for the actor. If read, returns the fixed position if any,
5092 * otherwise the allocation if available, otherwise 0.
5094 * The #ClutterActor:x property is animatable.
5097 g_param_spec_float ("x",
5099 P_("X coordinate of the actor"),
5100 -G_MAXFLOAT, G_MAXFLOAT,
5103 G_PARAM_STATIC_STRINGS |
5104 CLUTTER_PARAM_ANIMATABLE);
5109 * Y coordinate of the actor in pixels. If written, forces a fixed
5110 * position for the actor. If read, returns the fixed position if
5111 * any, otherwise the allocation if available, otherwise 0.
5113 * The #ClutterActor:y property is animatable.
5116 g_param_spec_float ("y",
5118 P_("Y coordinate of the actor"),
5119 -G_MAXFLOAT, G_MAXFLOAT,
5122 G_PARAM_STATIC_STRINGS |
5123 CLUTTER_PARAM_ANIMATABLE);
5126 * ClutterActor:width:
5128 * Width of the actor (in pixels). If written, forces the minimum and
5129 * natural size request of the actor to the given width. If read, returns
5130 * the allocated width if available, otherwise the width request.
5132 * The #ClutterActor:width property is animatable.
5134 obj_props[PROP_WIDTH] =
5135 g_param_spec_float ("width",
5137 P_("Width of the actor"),
5141 G_PARAM_STATIC_STRINGS |
5142 CLUTTER_PARAM_ANIMATABLE);
5145 * ClutterActor:height:
5147 * Height of the actor (in pixels). If written, forces the minimum and
5148 * natural size request of the actor to the given height. If read, returns
5149 * the allocated height if available, otherwise the height request.
5151 * The #ClutterActor:height property is animatable.
5153 obj_props[PROP_HEIGHT] =
5154 g_param_spec_float ("height",
5156 P_("Height of the actor"),
5160 G_PARAM_STATIC_STRINGS |
5161 CLUTTER_PARAM_ANIMATABLE);
5164 * ClutterActor:fixed-x:
5166 * The fixed X position of the actor in pixels.
5168 * Writing this property sets #ClutterActor:fixed-position-set
5169 * property as well, as a side effect
5173 obj_props[PROP_FIXED_X] =
5174 g_param_spec_float ("fixed-x",
5176 P_("Forced X position of the actor"),
5177 -G_MAXFLOAT, G_MAXFLOAT,
5179 CLUTTER_PARAM_READWRITE);
5182 * ClutterActor:fixed-y:
5184 * The fixed Y position of the actor in pixels.
5186 * Writing this property sets the #ClutterActor:fixed-position-set
5187 * property as well, as a side effect
5191 obj_props[PROP_FIXED_Y] =
5192 g_param_spec_float ("fixed-y",
5194 P_("Forced Y position of the actor"),
5195 -G_MAXFLOAT, G_MAXFLOAT,
5197 CLUTTER_PARAM_READWRITE);
5200 * ClutterActor:fixed-position-set:
5202 * This flag controls whether the #ClutterActor:fixed-x and
5203 * #ClutterActor:fixed-y properties are used
5207 obj_props[PROP_FIXED_POSITION_SET] =
5208 g_param_spec_boolean ("fixed-position-set",
5209 P_("Fixed position set"),
5210 P_("Whether to use fixed positioning for the actor"),
5212 CLUTTER_PARAM_READWRITE);
5215 * ClutterActor:min-width:
5217 * A forced minimum width request for the actor, in pixels
5219 * Writing this property sets the #ClutterActor:min-width-set property
5220 * as well, as a side effect.
5222 *This property overrides the usual width request of the actor.
5226 obj_props[PROP_MIN_WIDTH] =
5227 g_param_spec_float ("min-width",
5229 P_("Forced minimum width request for the actor"),
5232 CLUTTER_PARAM_READWRITE);
5235 * ClutterActor:min-height:
5237 * A forced minimum height request for the actor, in pixels
5239 * Writing this property sets the #ClutterActor:min-height-set property
5240 * as well, as a side effect. This property overrides the usual height
5241 * request of the actor.
5245 obj_props[PROP_MIN_HEIGHT] =
5246 g_param_spec_float ("min-height",
5248 P_("Forced minimum height request for the actor"),
5251 CLUTTER_PARAM_READWRITE);
5254 * ClutterActor:natural-width:
5256 * A forced natural width request for the actor, in pixels
5258 * Writing this property sets the #ClutterActor:natural-width-set
5259 * property as well, as a side effect. This property overrides the
5260 * usual width request of the actor
5264 obj_props[PROP_NATURAL_WIDTH] =
5265 g_param_spec_float ("natural-width",
5266 P_("Natural Width"),
5267 P_("Forced natural width request for the actor"),
5270 CLUTTER_PARAM_READWRITE);
5273 * ClutterActor:natural-height:
5275 * A forced natural height request for the actor, in pixels
5277 * Writing this property sets the #ClutterActor:natural-height-set
5278 * property as well, as a side effect. This property overrides the
5279 * usual height request of the actor
5283 obj_props[PROP_NATURAL_HEIGHT] =
5284 g_param_spec_float ("natural-height",
5285 P_("Natural Height"),
5286 P_("Forced natural height request for the actor"),
5289 CLUTTER_PARAM_READWRITE);
5292 * ClutterActor:min-width-set:
5294 * This flag controls whether the #ClutterActor:min-width property
5299 obj_props[PROP_MIN_WIDTH_SET] =
5300 g_param_spec_boolean ("min-width-set",
5301 P_("Minimum width set"),
5302 P_("Whether to use the min-width property"),
5304 CLUTTER_PARAM_READWRITE);
5307 * ClutterActor:min-height-set:
5309 * This flag controls whether the #ClutterActor:min-height property
5314 obj_props[PROP_MIN_HEIGHT_SET] =
5315 g_param_spec_boolean ("min-height-set",
5316 P_("Minimum height set"),
5317 P_("Whether to use the min-height property"),
5319 CLUTTER_PARAM_READWRITE);
5322 * ClutterActor:natural-width-set:
5324 * This flag controls whether the #ClutterActor:natural-width property
5329 obj_props[PROP_NATURAL_WIDTH_SET] =
5330 g_param_spec_boolean ("natural-width-set",
5331 P_("Natural width set"),
5332 P_("Whether to use the natural-width property"),
5334 CLUTTER_PARAM_READWRITE);
5337 * ClutterActor:natural-height-set:
5339 * This flag controls whether the #ClutterActor:natural-height property
5344 obj_props[PROP_NATURAL_HEIGHT_SET] =
5345 g_param_spec_boolean ("natural-height-set",
5346 P_("Natural height set"),
5347 P_("Whether to use the natural-height property"),
5349 CLUTTER_PARAM_READWRITE);
5352 * ClutterActor:allocation:
5354 * The allocation for the actor, in pixels
5356 * This is property is read-only, but you might monitor it to know when an
5357 * actor moves or resizes
5361 obj_props[PROP_ALLOCATION] =
5362 g_param_spec_boxed ("allocation",
5364 P_("The actor's allocation"),
5365 CLUTTER_TYPE_ACTOR_BOX,
5366 CLUTTER_PARAM_READABLE);
5369 * ClutterActor:request-mode:
5371 * Request mode for the #ClutterActor. The request mode determines the
5372 * type of geometry management used by the actor, either height for width
5373 * (the default) or width for height.
5375 * For actors implementing height for width, the parent container should get
5376 * the preferred width first, and then the preferred height for that width.
5378 * For actors implementing width for height, the parent container should get
5379 * the preferred height first, and then the preferred width for that height.
5384 * ClutterRequestMode mode;
5385 * gfloat natural_width, min_width;
5386 * gfloat natural_height, min_height;
5388 * mode = clutter_actor_get_request_mode (child);
5389 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5391 * clutter_actor_get_preferred_width (child, -1,
5393 * &natural_width);
5394 * clutter_actor_get_preferred_height (child, natural_width,
5396 * &natural_height);
5400 * clutter_actor_get_preferred_height (child, -1,
5402 * &natural_height);
5403 * clutter_actor_get_preferred_width (child, natural_height,
5405 * &natural_width);
5409 * will retrieve the minimum and natural width and height depending on the
5410 * preferred request mode of the #ClutterActor "child".
5412 * The clutter_actor_get_preferred_size() function will implement this
5417 obj_props[PROP_REQUEST_MODE] =
5418 g_param_spec_enum ("request-mode",
5420 P_("The actor's request mode"),
5421 CLUTTER_TYPE_REQUEST_MODE,
5422 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5423 CLUTTER_PARAM_READWRITE);
5426 * ClutterActor:depth:
5428 * The position of the actor on the Z axis.
5430 * The #ClutterActor:depth property is relative to the parent's
5433 * The #ClutterActor:depth property is animatable.
5437 obj_props[PROP_DEPTH] =
5438 g_param_spec_float ("depth",
5440 P_("Position on the Z axis"),
5441 -G_MAXFLOAT, G_MAXFLOAT,
5444 G_PARAM_STATIC_STRINGS |
5445 CLUTTER_PARAM_ANIMATABLE);
5448 * ClutterActor:opacity:
5450 * Opacity of an actor, between 0 (fully transparent) and
5451 * 255 (fully opaque)
5453 * The #ClutterActor:opacity property is animatable.
5455 obj_props[PROP_OPACITY] =
5456 g_param_spec_uint ("opacity",
5458 P_("Opacity of an actor"),
5462 G_PARAM_STATIC_STRINGS |
5463 CLUTTER_PARAM_ANIMATABLE);
5466 * ClutterActor:offscreen-redirect:
5468 * Determines the conditions in which the actor will be redirected
5469 * to an offscreen framebuffer while being painted. For example this
5470 * can be used to cache an actor in a framebuffer or for improved
5471 * handling of transparent actors. See
5472 * clutter_actor_set_offscreen_redirect() for details.
5476 obj_props[PROP_OFFSCREEN_REDIRECT] =
5477 g_param_spec_flags ("offscreen-redirect",
5478 P_("Offscreen redirect"),
5479 P_("Flags controlling when to flatten the actor into a single image"),
5480 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5482 CLUTTER_PARAM_READWRITE);
5485 * ClutterActor:visible:
5487 * Whether the actor is set to be visible or not
5489 * See also #ClutterActor:mapped
5491 obj_props[PROP_VISIBLE] =
5492 g_param_spec_boolean ("visible",
5494 P_("Whether the actor is visible or not"),
5496 CLUTTER_PARAM_READWRITE);
5499 * ClutterActor:mapped:
5501 * Whether the actor is mapped (will be painted when the stage
5502 * to which it belongs is mapped)
5506 obj_props[PROP_MAPPED] =
5507 g_param_spec_boolean ("mapped",
5509 P_("Whether the actor will be painted"),
5511 CLUTTER_PARAM_READABLE);
5514 * ClutterActor:realized:
5516 * Whether the actor has been realized
5520 obj_props[PROP_REALIZED] =
5521 g_param_spec_boolean ("realized",
5523 P_("Whether the actor has been realized"),
5525 CLUTTER_PARAM_READABLE);
5528 * ClutterActor:reactive:
5530 * Whether the actor is reactive to events or not
5532 * Only reactive actors will emit event-related signals
5536 obj_props[PROP_REACTIVE] =
5537 g_param_spec_boolean ("reactive",
5539 P_("Whether the actor is reactive to events"),
5541 CLUTTER_PARAM_READWRITE);
5544 * ClutterActor:has-clip:
5546 * Whether the actor has the #ClutterActor:clip property set or not
5548 obj_props[PROP_HAS_CLIP] =
5549 g_param_spec_boolean ("has-clip",
5551 P_("Whether the actor has a clip set"),
5553 CLUTTER_PARAM_READABLE);
5556 * ClutterActor:clip:
5558 * The clip region for the actor, in actor-relative coordinates
5560 * Every part of the actor outside the clip region will not be
5563 obj_props[PROP_CLIP] =
5564 g_param_spec_boxed ("clip",
5566 P_("The clip region for the actor"),
5567 CLUTTER_TYPE_GEOMETRY,
5568 CLUTTER_PARAM_READWRITE);
5571 * ClutterActor:name:
5573 * The name of the actor
5577 obj_props[PROP_NAME] =
5578 g_param_spec_string ("name",
5580 P_("Name of the actor"),
5582 CLUTTER_PARAM_READWRITE);
5585 * ClutterActor:scale-x:
5587 * The horizontal scale of the actor.
5589 * The #ClutterActor:scale-x property is animatable.
5593 obj_props[PROP_SCALE_X] =
5594 g_param_spec_double ("scale-x",
5596 P_("Scale factor on the X axis"),
5600 G_PARAM_STATIC_STRINGS |
5601 CLUTTER_PARAM_ANIMATABLE);
5604 * ClutterActor:scale-y:
5606 * The vertical scale of the actor.
5608 * The #ClutterActor:scale-y property is animatable.
5612 obj_props[PROP_SCALE_Y] =
5613 g_param_spec_double ("scale-y",
5615 P_("Scale factor on the Y axis"),
5619 G_PARAM_STATIC_STRINGS |
5620 CLUTTER_PARAM_ANIMATABLE);
5623 * ClutterActor:scale-center-x:
5625 * The horizontal center point for scaling
5629 obj_props[PROP_SCALE_CENTER_X] =
5630 g_param_spec_float ("scale-center-x",
5631 P_("Scale Center X"),
5632 P_("Horizontal scale center"),
5633 -G_MAXFLOAT, G_MAXFLOAT,
5635 CLUTTER_PARAM_READWRITE);
5638 * ClutterActor:scale-center-y:
5640 * The vertical center point for scaling
5644 obj_props[PROP_SCALE_CENTER_Y] =
5645 g_param_spec_float ("scale-center-y",
5646 P_("Scale Center Y"),
5647 P_("Vertical scale center"),
5648 -G_MAXFLOAT, G_MAXFLOAT,
5650 CLUTTER_PARAM_READWRITE);
5653 * ClutterActor:scale-gravity:
5655 * The center point for scaling expressed as a #ClutterGravity
5659 obj_props[PROP_SCALE_GRAVITY] =
5660 g_param_spec_enum ("scale-gravity",
5661 P_("Scale Gravity"),
5662 P_("The center of scaling"),
5663 CLUTTER_TYPE_GRAVITY,
5664 CLUTTER_GRAVITY_NONE,
5665 CLUTTER_PARAM_READWRITE);
5668 * ClutterActor:rotation-angle-x:
5670 * The rotation angle on the X axis.
5672 * The #ClutterActor:rotation-angle-x property is animatable.
5676 obj_props[PROP_ROTATION_ANGLE_X] =
5677 g_param_spec_double ("rotation-angle-x",
5678 P_("Rotation Angle X"),
5679 P_("The rotation angle on the X axis"),
5680 -G_MAXDOUBLE, G_MAXDOUBLE,
5683 G_PARAM_STATIC_STRINGS |
5684 CLUTTER_PARAM_ANIMATABLE);
5687 * ClutterActor:rotation-angle-y:
5689 * The rotation angle on the Y axis
5691 * The #ClutterActor:rotation-angle-y property is animatable.
5695 obj_props[PROP_ROTATION_ANGLE_Y] =
5696 g_param_spec_double ("rotation-angle-y",
5697 P_("Rotation Angle Y"),
5698 P_("The rotation angle on the Y axis"),
5699 -G_MAXDOUBLE, G_MAXDOUBLE,
5702 G_PARAM_STATIC_STRINGS |
5703 CLUTTER_PARAM_ANIMATABLE);
5706 * ClutterActor:rotation-angle-z:
5708 * The rotation angle on the Z axis
5710 * The #ClutterActor:rotation-angle-z property is animatable.
5714 obj_props[PROP_ROTATION_ANGLE_Z] =
5715 g_param_spec_double ("rotation-angle-z",
5716 P_("Rotation Angle Z"),
5717 P_("The rotation angle on the Z axis"),
5718 -G_MAXDOUBLE, G_MAXDOUBLE,
5721 G_PARAM_STATIC_STRINGS |
5722 CLUTTER_PARAM_ANIMATABLE);
5725 * ClutterActor:rotation-center-x:
5727 * The rotation center on the X axis.
5731 obj_props[PROP_ROTATION_CENTER_X] =
5732 g_param_spec_boxed ("rotation-center-x",
5733 P_("Rotation Center X"),
5734 P_("The rotation center on the X axis"),
5735 CLUTTER_TYPE_VERTEX,
5736 CLUTTER_PARAM_READWRITE);
5739 * ClutterActor:rotation-center-y:
5741 * The rotation center on the Y axis.
5745 obj_props[PROP_ROTATION_CENTER_Y] =
5746 g_param_spec_boxed ("rotation-center-y",
5747 P_("Rotation Center Y"),
5748 P_("The rotation center on the Y axis"),
5749 CLUTTER_TYPE_VERTEX,
5750 CLUTTER_PARAM_READWRITE);
5753 * ClutterActor:rotation-center-z:
5755 * The rotation center on the Z axis.
5759 obj_props[PROP_ROTATION_CENTER_Z] =
5760 g_param_spec_boxed ("rotation-center-z",
5761 P_("Rotation Center Z"),
5762 P_("The rotation center on the Z axis"),
5763 CLUTTER_TYPE_VERTEX,
5764 CLUTTER_PARAM_READWRITE);
5767 * ClutterActor:rotation-center-z-gravity:
5769 * The rotation center on the Z axis expressed as a #ClutterGravity.
5773 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5774 g_param_spec_enum ("rotation-center-z-gravity",
5775 P_("Rotation Center Z Gravity"),
5776 P_("Center point for rotation around the Z axis"),
5777 CLUTTER_TYPE_GRAVITY,
5778 CLUTTER_GRAVITY_NONE,
5779 CLUTTER_PARAM_READWRITE);
5782 * ClutterActor:anchor-x:
5784 * The X coordinate of an actor's anchor point, relative to
5785 * the actor coordinate space, in pixels
5789 obj_props[PROP_ANCHOR_X] =
5790 g_param_spec_float ("anchor-x",
5792 P_("X coordinate of the anchor point"),
5793 -G_MAXFLOAT, G_MAXFLOAT,
5795 CLUTTER_PARAM_READWRITE);
5798 * ClutterActor:anchor-y:
5800 * The Y coordinate of an actor's anchor point, relative to
5801 * the actor coordinate space, in pixels
5805 obj_props[PROP_ANCHOR_Y] =
5806 g_param_spec_float ("anchor-y",
5808 P_("Y coordinate of the anchor point"),
5809 -G_MAXFLOAT, G_MAXFLOAT,
5811 CLUTTER_PARAM_READWRITE);
5814 * ClutterActor:anchor-gravity:
5816 * The anchor point expressed as a #ClutterGravity
5820 obj_props[PROP_ANCHOR_GRAVITY] =
5821 g_param_spec_enum ("anchor-gravity",
5822 P_("Anchor Gravity"),
5823 P_("The anchor point as a ClutterGravity"),
5824 CLUTTER_TYPE_GRAVITY,
5825 CLUTTER_GRAVITY_NONE,
5826 CLUTTER_PARAM_READWRITE);
5829 * ClutterActor:show-on-set-parent:
5831 * If %TRUE, the actor is automatically shown when parented.
5833 * Calling clutter_actor_hide() on an actor which has not been
5834 * parented will set this property to %FALSE as a side effect.
5838 obj_props[PROP_SHOW_ON_SET_PARENT] =
5839 g_param_spec_boolean ("show-on-set-parent",
5840 P_("Show on set parent"),
5841 P_("Whether the actor is shown when parented"),
5843 CLUTTER_PARAM_READWRITE);
5846 * ClutterActor:clip-to-allocation:
5848 * Whether the clip region should track the allocated area
5851 * This property is ignored if a clip area has been explicitly
5852 * set using clutter_actor_set_clip().
5856 obj_props[PROP_CLIP_TO_ALLOCATION] =
5857 g_param_spec_boolean ("clip-to-allocation",
5858 P_("Clip to Allocation"),
5859 P_("Sets the clip region to track the actor's allocation"),
5861 CLUTTER_PARAM_READWRITE);
5864 * ClutterActor:text-direction:
5866 * The direction of the text inside a #ClutterActor.
5870 obj_props[PROP_TEXT_DIRECTION] =
5871 g_param_spec_enum ("text-direction",
5872 P_("Text Direction"),
5873 P_("Direction of the text"),
5874 CLUTTER_TYPE_TEXT_DIRECTION,
5875 CLUTTER_TEXT_DIRECTION_LTR,
5876 CLUTTER_PARAM_READWRITE);
5879 * ClutterActor:has-pointer:
5881 * Whether the actor contains the pointer of a #ClutterInputDevice
5886 obj_props[PROP_HAS_POINTER] =
5887 g_param_spec_boolean ("has-pointer",
5889 P_("Whether the actor contains the pointer of an input device"),
5891 CLUTTER_PARAM_READABLE);
5894 * ClutterActor:actions:
5896 * Adds a #ClutterAction to the actor
5900 obj_props[PROP_ACTIONS] =
5901 g_param_spec_object ("actions",
5903 P_("Adds an action to the actor"),
5904 CLUTTER_TYPE_ACTION,
5905 CLUTTER_PARAM_WRITABLE);
5908 * ClutterActor:constraints:
5910 * Adds a #ClutterConstraint to the actor
5914 obj_props[PROP_CONSTRAINTS] =
5915 g_param_spec_object ("constraints",
5917 P_("Adds a constraint to the actor"),
5918 CLUTTER_TYPE_CONSTRAINT,
5919 CLUTTER_PARAM_WRITABLE);
5922 * ClutterActor:effect:
5924 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5928 obj_props[PROP_EFFECT] =
5929 g_param_spec_object ("effect",
5931 P_("Add an effect to be applied on the actor"),
5932 CLUTTER_TYPE_EFFECT,
5933 CLUTTER_PARAM_WRITABLE);
5936 * ClutterActor:layout-manager:
5938 * A delegate object for controlling the layout of the children of
5943 obj_props[PROP_LAYOUT_MANAGER] =
5944 g_param_spec_object ("layout-manager",
5945 P_("Layout Manager"),
5946 P_("The object controlling the layout of an actor's children"),
5947 CLUTTER_TYPE_LAYOUT_MANAGER,
5948 CLUTTER_PARAM_READWRITE);
5952 * ClutterActor:x-align:
5954 * The alignment of an actor on the X axis, if the actor has been given
5955 * extra space for its allocation.
5959 obj_props[PROP_X_ALIGN] =
5960 g_param_spec_enum ("x-align",
5962 P_("The alignment of the actor on the X axis within its allocation"),
5963 CLUTTER_TYPE_ACTOR_ALIGN,
5964 CLUTTER_ACTOR_ALIGN_FILL,
5965 CLUTTER_PARAM_READWRITE);
5968 * ClutterActor:y-align:
5970 * The alignment of an actor on the Y axis, if the actor has been given
5971 * extra space for its allocation.
5975 obj_props[PROP_Y_ALIGN] =
5976 g_param_spec_enum ("y-align",
5978 P_("The alignment of the actor on the Y axis within its allocation"),
5979 CLUTTER_TYPE_ACTOR_ALIGN,
5980 CLUTTER_ACTOR_ALIGN_FILL,
5981 CLUTTER_PARAM_READWRITE);
5984 * ClutterActor:margin-top:
5986 * The margin (in pixels) from the top of the actor.
5988 * This property adds a margin to the actor's preferred size; the margin
5989 * will be automatically taken into account when allocating the actor.
5993 obj_props[PROP_MARGIN_TOP] =
5994 g_param_spec_float ("margin-top",
5996 P_("Extra space at the top"),
5999 CLUTTER_PARAM_READWRITE);
6002 * ClutterActor:margin-bottom:
6004 * The margin (in pixels) from the bottom of the actor.
6006 * This property adds a margin to the actor's preferred size; the margin
6007 * will be automatically taken into account when allocating the actor.
6011 obj_props[PROP_MARGIN_BOTTOM] =
6012 g_param_spec_float ("margin-bottom",
6013 P_("Margin Bottom"),
6014 P_("Extra space at the bottom"),
6017 CLUTTER_PARAM_READWRITE);
6020 * ClutterActor:margin-left:
6022 * The margin (in pixels) from the left of the actor.
6024 * This property adds a margin to the actor's preferred size; the margin
6025 * will be automatically taken into account when allocating the actor.
6029 obj_props[PROP_MARGIN_LEFT] =
6030 g_param_spec_float ("margin-left",
6032 P_("Extra space at the left"),
6035 CLUTTER_PARAM_READWRITE);
6038 * ClutterActor:margin-right:
6040 * The margin (in pixels) from the right of the actor.
6042 * This property adds a margin to the actor's preferred size; the margin
6043 * will be automatically taken into account when allocating the actor.
6047 obj_props[PROP_MARGIN_RIGHT] =
6048 g_param_spec_float ("margin-right",
6050 P_("Extra space at the right"),
6053 CLUTTER_PARAM_READWRITE);
6056 * ClutterActor:background-color-set:
6058 * Whether the #ClutterActor:background-color property has been set.
6062 obj_props[PROP_BACKGROUND_COLOR_SET] =
6063 g_param_spec_boolean ("background-color-set",
6064 P_("Background Color Set"),
6065 P_("Whether the background color is set"),
6067 CLUTTER_PARAM_READABLE);
6070 * ClutterActor:background-color:
6072 * Paints a solid fill of the actor's allocation using the specified
6075 * The #ClutterActor:background-color property is animatable.
6079 obj_props[PROP_BACKGROUND_COLOR] =
6080 clutter_param_spec_color ("background-color",
6081 P_("Background color"),
6082 P_("The actor's background color"),
6083 CLUTTER_COLOR_Transparent,
6085 G_PARAM_STATIC_STRINGS |
6086 CLUTTER_PARAM_ANIMATABLE);
6089 * ClutterActor:first-child:
6091 * The actor's first child.
6095 obj_props[PROP_FIRST_CHILD] =
6096 g_param_spec_object ("first-child",
6098 P_("The actor's first child"),
6100 CLUTTER_PARAM_READABLE);
6103 * ClutterActor:last-child:
6105 * The actor's last child.
6109 obj_props[PROP_LAST_CHILD] =
6110 g_param_spec_object ("last-child",
6112 P_("The actor's last child"),
6114 CLUTTER_PARAM_READABLE);
6116 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6119 * ClutterActor::destroy:
6120 * @actor: the #ClutterActor which emitted the signal
6122 * The ::destroy signal notifies that all references held on the
6123 * actor which emitted it should be released.
6125 * The ::destroy signal should be used by all holders of a reference
6128 * This signal might result in the finalization of the #ClutterActor
6129 * if all references are released.
6131 * Composite actors and actors implementing the #ClutterContainer
6132 * interface should override the default implementation of the
6133 * class handler of this signal and call clutter_actor_destroy() on
6134 * their children. When overriding the default class handler, it is
6135 * required to chain up to the parent's implementation.
6139 actor_signals[DESTROY] =
6140 g_signal_new (I_("destroy"),
6141 G_TYPE_FROM_CLASS (object_class),
6142 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6143 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6145 _clutter_marshal_VOID__VOID,
6148 * ClutterActor::show:
6149 * @actor: the object which received the signal
6151 * The ::show signal is emitted when an actor is visible and
6152 * rendered on the stage.
6156 actor_signals[SHOW] =
6157 g_signal_new (I_("show"),
6158 G_TYPE_FROM_CLASS (object_class),
6160 G_STRUCT_OFFSET (ClutterActorClass, show),
6162 _clutter_marshal_VOID__VOID,
6165 * ClutterActor::hide:
6166 * @actor: the object which received the signal
6168 * The ::hide signal is emitted when an actor is no longer rendered
6173 actor_signals[HIDE] =
6174 g_signal_new (I_("hide"),
6175 G_TYPE_FROM_CLASS (object_class),
6177 G_STRUCT_OFFSET (ClutterActorClass, hide),
6179 _clutter_marshal_VOID__VOID,
6182 * ClutterActor::parent-set:
6183 * @actor: the object which received the signal
6184 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6186 * This signal is emitted when the parent of the actor changes.
6190 actor_signals[PARENT_SET] =
6191 g_signal_new (I_("parent-set"),
6192 G_TYPE_FROM_CLASS (object_class),
6194 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6196 _clutter_marshal_VOID__OBJECT,
6198 CLUTTER_TYPE_ACTOR);
6201 * ClutterActor::queue-redraw:
6202 * @actor: the actor we're bubbling the redraw request through
6203 * @origin: the actor which initiated the redraw request
6205 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6206 * is called on @origin.
6208 * The default implementation for #ClutterActor chains up to the
6209 * parent actor and queues a redraw on the parent, thus "bubbling"
6210 * the redraw queue up through the actor graph. The default
6211 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6212 * in a main loop idle handler.
6214 * Note that the @origin actor may be the stage, or a container; it
6215 * does not have to be a leaf node in the actor graph.
6217 * Toolkits embedding a #ClutterStage which require a redraw and
6218 * relayout cycle can stop the emission of this signal using the
6219 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6224 * on_redraw_complete (gpointer data)
6226 * ClutterStage *stage = data;
6228 * /* execute the Clutter drawing pipeline */
6229 * clutter_stage_ensure_redraw (stage);
6233 * on_stage_queue_redraw (ClutterStage *stage)
6235 * /* this prevents the default handler to run */
6236 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6238 * /* queue a redraw with the host toolkit and call
6239 * * a function when the redraw has been completed
6241 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6245 * <note><para>This signal is emitted before the Clutter paint
6246 * pipeline is executed. If you want to know when the pipeline has
6247 * been completed you should connect to the ::paint signal on the
6248 * Stage with g_signal_connect_after().</para></note>
6252 actor_signals[QUEUE_REDRAW] =
6253 g_signal_new (I_("queue-redraw"),
6254 G_TYPE_FROM_CLASS (object_class),
6256 G_SIGNAL_NO_RECURSE |
6258 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6260 _clutter_marshal_VOID__OBJECT,
6262 CLUTTER_TYPE_ACTOR);
6265 * ClutterActor::queue-relayout
6266 * @actor: the actor being queued for relayout
6268 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6269 * is called on an actor.
6271 * The default implementation for #ClutterActor chains up to the
6272 * parent actor and queues a relayout on the parent, thus "bubbling"
6273 * the relayout queue up through the actor graph.
6275 * The main purpose of this signal is to allow relayout to be propagated
6276 * properly in the procense of #ClutterClone actors. Applications will
6277 * not normally need to connect to this signal.
6281 actor_signals[QUEUE_RELAYOUT] =
6282 g_signal_new (I_("queue-relayout"),
6283 G_TYPE_FROM_CLASS (object_class),
6285 G_SIGNAL_NO_RECURSE |
6287 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6289 _clutter_marshal_VOID__VOID,
6293 * ClutterActor::event:
6294 * @actor: the actor which received the event
6295 * @event: a #ClutterEvent
6297 * The ::event signal is emitted each time an event is received
6298 * by the @actor. This signal will be emitted on every actor,
6299 * following the hierarchy chain, until it reaches the top-level
6300 * container (the #ClutterStage).
6302 * Return value: %TRUE if the event has been handled by the actor,
6303 * or %FALSE to continue the emission.
6307 actor_signals[EVENT] =
6308 g_signal_new (I_("event"),
6309 G_TYPE_FROM_CLASS (object_class),
6311 G_STRUCT_OFFSET (ClutterActorClass, event),
6312 _clutter_boolean_handled_accumulator, NULL,
6313 _clutter_marshal_BOOLEAN__BOXED,
6315 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6317 * ClutterActor::button-press-event:
6318 * @actor: the actor which received the event
6319 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6321 * The ::button-press-event signal is emitted each time a mouse button
6322 * is pressed on @actor.
6324 * Return value: %TRUE if the event has been handled by the actor,
6325 * or %FALSE to continue the emission.
6329 actor_signals[BUTTON_PRESS_EVENT] =
6330 g_signal_new (I_("button-press-event"),
6331 G_TYPE_FROM_CLASS (object_class),
6333 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6334 _clutter_boolean_handled_accumulator, NULL,
6335 _clutter_marshal_BOOLEAN__BOXED,
6337 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6339 * ClutterActor::button-release-event:
6340 * @actor: the actor which received the event
6341 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6343 * The ::button-release-event signal is emitted each time a mouse button
6344 * is released on @actor.
6346 * Return value: %TRUE if the event has been handled by the actor,
6347 * or %FALSE to continue the emission.
6351 actor_signals[BUTTON_RELEASE_EVENT] =
6352 g_signal_new (I_("button-release-event"),
6353 G_TYPE_FROM_CLASS (object_class),
6355 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6356 _clutter_boolean_handled_accumulator, NULL,
6357 _clutter_marshal_BOOLEAN__BOXED,
6359 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6361 * ClutterActor::scroll-event:
6362 * @actor: the actor which received the event
6363 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6365 * The ::scroll-event signal is emitted each time the mouse is
6366 * scrolled on @actor
6368 * Return value: %TRUE if the event has been handled by the actor,
6369 * or %FALSE to continue the emission.
6373 actor_signals[SCROLL_EVENT] =
6374 g_signal_new (I_("scroll-event"),
6375 G_TYPE_FROM_CLASS (object_class),
6377 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6378 _clutter_boolean_handled_accumulator, NULL,
6379 _clutter_marshal_BOOLEAN__BOXED,
6381 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6383 * ClutterActor::key-press-event:
6384 * @actor: the actor which received the event
6385 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6387 * The ::key-press-event signal is emitted each time a keyboard button
6388 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6390 * Return value: %TRUE if the event has been handled by the actor,
6391 * or %FALSE to continue the emission.
6395 actor_signals[KEY_PRESS_EVENT] =
6396 g_signal_new (I_("key-press-event"),
6397 G_TYPE_FROM_CLASS (object_class),
6399 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6400 _clutter_boolean_handled_accumulator, NULL,
6401 _clutter_marshal_BOOLEAN__BOXED,
6403 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6405 * ClutterActor::key-release-event:
6406 * @actor: the actor which received the event
6407 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6409 * The ::key-release-event signal is emitted each time a keyboard button
6410 * is released while @actor has key focus (see
6411 * clutter_stage_set_key_focus()).
6413 * Return value: %TRUE if the event has been handled by the actor,
6414 * or %FALSE to continue the emission.
6418 actor_signals[KEY_RELEASE_EVENT] =
6419 g_signal_new (I_("key-release-event"),
6420 G_TYPE_FROM_CLASS (object_class),
6422 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6423 _clutter_boolean_handled_accumulator, NULL,
6424 _clutter_marshal_BOOLEAN__BOXED,
6426 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6428 * ClutterActor::motion-event:
6429 * @actor: the actor which received the event
6430 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6432 * The ::motion-event signal is emitted each time the mouse pointer is
6433 * moved over @actor.
6435 * Return value: %TRUE if the event has been handled by the actor,
6436 * or %FALSE to continue the emission.
6440 actor_signals[MOTION_EVENT] =
6441 g_signal_new (I_("motion-event"),
6442 G_TYPE_FROM_CLASS (object_class),
6444 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6445 _clutter_boolean_handled_accumulator, NULL,
6446 _clutter_marshal_BOOLEAN__BOXED,
6448 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6451 * ClutterActor::key-focus-in:
6452 * @actor: the actor which now has key focus
6454 * The ::key-focus-in signal is emitted when @actor receives key focus.
6458 actor_signals[KEY_FOCUS_IN] =
6459 g_signal_new (I_("key-focus-in"),
6460 G_TYPE_FROM_CLASS (object_class),
6462 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6464 _clutter_marshal_VOID__VOID,
6468 * ClutterActor::key-focus-out:
6469 * @actor: the actor which now has key focus
6471 * The ::key-focus-out signal is emitted when @actor loses key focus.
6475 actor_signals[KEY_FOCUS_OUT] =
6476 g_signal_new (I_("key-focus-out"),
6477 G_TYPE_FROM_CLASS (object_class),
6479 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6481 _clutter_marshal_VOID__VOID,
6485 * ClutterActor::enter-event:
6486 * @actor: the actor which the pointer has entered.
6487 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6489 * The ::enter-event signal is emitted when the pointer enters the @actor
6491 * Return value: %TRUE if the event has been handled by the actor,
6492 * or %FALSE to continue the emission.
6496 actor_signals[ENTER_EVENT] =
6497 g_signal_new (I_("enter-event"),
6498 G_TYPE_FROM_CLASS (object_class),
6500 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6501 _clutter_boolean_handled_accumulator, NULL,
6502 _clutter_marshal_BOOLEAN__BOXED,
6504 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6507 * ClutterActor::leave-event:
6508 * @actor: the actor which the pointer has left
6509 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6511 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6513 * Return value: %TRUE if the event has been handled by the actor,
6514 * or %FALSE to continue the emission.
6518 actor_signals[LEAVE_EVENT] =
6519 g_signal_new (I_("leave-event"),
6520 G_TYPE_FROM_CLASS (object_class),
6522 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6523 _clutter_boolean_handled_accumulator, NULL,
6524 _clutter_marshal_BOOLEAN__BOXED,
6526 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6529 * ClutterActor::captured-event:
6530 * @actor: the actor which received the signal
6531 * @event: a #ClutterEvent
6533 * The ::captured-event signal is emitted when an event is captured
6534 * by Clutter. This signal will be emitted starting from the top-level
6535 * container (the #ClutterStage) to the actor which received the event
6536 * going down the hierarchy. This signal can be used to intercept every
6537 * event before the specialized events (like
6538 * ClutterActor::button-press-event or ::key-released-event) are
6541 * Return value: %TRUE if the event has been handled by the actor,
6542 * or %FALSE to continue the emission.
6546 actor_signals[CAPTURED_EVENT] =
6547 g_signal_new (I_("captured-event"),
6548 G_TYPE_FROM_CLASS (object_class),
6550 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6551 _clutter_boolean_handled_accumulator, NULL,
6552 _clutter_marshal_BOOLEAN__BOXED,
6554 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6557 * ClutterActor::paint:
6558 * @actor: the #ClutterActor that received the signal
6560 * The ::paint signal is emitted each time an actor is being painted.
6562 * Subclasses of #ClutterActor should override the class signal handler
6563 * and paint themselves in that function.
6565 * It is possible to connect a handler to the ::paint signal in order
6566 * to set up some custom aspect of a paint.
6570 actor_signals[PAINT] =
6571 g_signal_new (I_("paint"),
6572 G_TYPE_FROM_CLASS (object_class),
6574 G_SIGNAL_NO_RECURSE |
6576 G_STRUCT_OFFSET (ClutterActorClass, paint),
6578 _clutter_marshal_VOID__VOID,
6581 * ClutterActor::realize:
6582 * @actor: the #ClutterActor that received the signal
6584 * The ::realize signal is emitted each time an actor is being
6589 actor_signals[REALIZE] =
6590 g_signal_new (I_("realize"),
6591 G_TYPE_FROM_CLASS (object_class),
6593 G_STRUCT_OFFSET (ClutterActorClass, realize),
6595 _clutter_marshal_VOID__VOID,
6598 * ClutterActor::unrealize:
6599 * @actor: the #ClutterActor that received the signal
6601 * The ::unrealize signal is emitted each time an actor is being
6606 actor_signals[UNREALIZE] =
6607 g_signal_new (I_("unrealize"),
6608 G_TYPE_FROM_CLASS (object_class),
6610 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6612 _clutter_marshal_VOID__VOID,
6616 * ClutterActor::pick:
6617 * @actor: the #ClutterActor that received the signal
6618 * @color: the #ClutterColor to be used when picking
6620 * The ::pick signal is emitted each time an actor is being painted
6621 * in "pick mode". The pick mode is used to identify the actor during
6622 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6623 * The actor should paint its shape using the passed @pick_color.
6625 * Subclasses of #ClutterActor should override the class signal handler
6626 * and paint themselves in that function.
6628 * It is possible to connect a handler to the ::pick signal in order
6629 * to set up some custom aspect of a paint in pick mode.
6633 actor_signals[PICK] =
6634 g_signal_new (I_("pick"),
6635 G_TYPE_FROM_CLASS (object_class),
6637 G_STRUCT_OFFSET (ClutterActorClass, pick),
6639 _clutter_marshal_VOID__BOXED,
6641 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6644 * ClutterActor::allocation-changed:
6645 * @actor: the #ClutterActor that emitted the signal
6646 * @box: a #ClutterActorBox with the new allocation
6647 * @flags: #ClutterAllocationFlags for the allocation
6649 * The ::allocation-changed signal is emitted when the
6650 * #ClutterActor:allocation property changes. Usually, application
6651 * code should just use the notifications for the :allocation property
6652 * but if you want to track the allocation flags as well, for instance
6653 * to know whether the absolute origin of @actor changed, then you might
6654 * want use this signal instead.
6658 actor_signals[ALLOCATION_CHANGED] =
6659 g_signal_new (I_("allocation-changed"),
6660 G_TYPE_FROM_CLASS (object_class),
6664 _clutter_marshal_VOID__BOXED_FLAGS,
6666 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6667 CLUTTER_TYPE_ALLOCATION_FLAGS);
6671 clutter_actor_init (ClutterActor *self)
6673 ClutterActorPrivate *priv;
6675 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6677 priv->id = _clutter_context_acquire_id (self);
6680 priv->opacity = 0xff;
6681 priv->show_on_set_parent = TRUE;
6683 priv->needs_width_request = TRUE;
6684 priv->needs_height_request = TRUE;
6685 priv->needs_allocation = TRUE;
6687 priv->cached_width_age = 1;
6688 priv->cached_height_age = 1;
6690 priv->opacity_override = -1;
6691 priv->enable_model_view_transform = TRUE;
6693 /* Initialize an empty paint volume to start with */
6694 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6695 priv->last_paint_volume_valid = TRUE;
6697 priv->transform_valid = FALSE;
6701 * clutter_actor_new:
6703 * Creates a new #ClutterActor.
6705 * A newly created actor has a floating reference, which will be sunk
6706 * when it is added to another actor.
6708 * Return value: (transfer full): the newly created #ClutterActor
6713 clutter_actor_new (void)
6715 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6719 * clutter_actor_destroy:
6720 * @self: a #ClutterActor
6722 * Destroys an actor. When an actor is destroyed, it will break any
6723 * references it holds to other objects. If the actor is inside a
6724 * container, the actor will be removed.
6726 * When you destroy a container, its children will be destroyed as well.
6728 * Note: you cannot destroy the #ClutterStage returned by
6729 * clutter_stage_get_default().
6732 clutter_actor_destroy (ClutterActor *self)
6734 g_return_if_fail (CLUTTER_IS_ACTOR (self));
6736 g_object_ref (self);
6738 /* avoid recursion while destroying */
6739 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6741 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6743 g_object_run_dispose (G_OBJECT (self));
6745 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6748 g_object_unref (self);
6752 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6753 ClutterPaintVolume *clip)
6755 ClutterActorPrivate *priv = self->priv;
6756 ClutterPaintVolume *pv;
6759 /* Remove queue entry early in the process, otherwise a new
6760 queue_redraw() during signal handling could put back this
6761 object in the stage redraw list (but the entry is freed as
6762 soon as we return from this function, causing a segfault
6765 priv->queue_redraw_entry = NULL;
6767 /* If we've been explicitly passed a clip volume then there's
6768 * nothing more to calculate, but otherwise the only thing we know
6769 * is that the change is constrained to the given actor.
6771 * The idea is that if we know the paint volume for where the actor
6772 * was last drawn (in eye coordinates) and we also have the paint
6773 * volume for where it will be drawn next (in actor coordinates)
6774 * then if we queue a redraw for both these volumes that will cover
6775 * everything that needs to be redrawn to clear the old view and
6776 * show the latest view of the actor.
6778 * Don't clip this redraw if we don't know what position we had for
6779 * the previous redraw since we don't know where to set the clip so
6780 * it will clear the actor as it is currently.
6784 _clutter_actor_set_queue_redraw_clip (self, clip);
6787 else if (G_LIKELY (priv->last_paint_volume_valid))
6789 pv = _clutter_actor_get_paint_volume_mutable (self);
6792 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6794 /* make sure we redraw the actors old position... */
6795 _clutter_actor_set_queue_redraw_clip (stage,
6796 &priv->last_paint_volume);
6797 _clutter_actor_signal_queue_redraw (stage, stage);
6798 _clutter_actor_set_queue_redraw_clip (stage, NULL);
6800 /* XXX: Ideally the redraw signal would take a clip volume
6801 * argument, but that would be an ABI break. Until we can
6802 * break the ABI we pass the argument out-of-band
6805 /* setup the clip for the actors new position... */
6806 _clutter_actor_set_queue_redraw_clip (self, pv);
6815 _clutter_actor_signal_queue_redraw (self, self);
6817 /* Just in case anyone is manually firing redraw signals without
6818 * using the public queue_redraw() API we are careful to ensure that
6819 * our out-of-band clip member is cleared before returning...
6821 * Note: A NULL clip denotes a full-stage, un-clipped redraw
6823 if (G_LIKELY (clipped))
6824 _clutter_actor_set_queue_redraw_clip (self, NULL);
6828 _clutter_actor_get_allocation_clip (ClutterActor *self,
6829 ClutterActorBox *clip)
6831 ClutterActorBox allocation;
6833 /* XXX: we don't care if we get an out of date allocation here
6834 * because clutter_actor_queue_redraw_with_clip knows to ignore
6835 * the clip if the actor's allocation is invalid.
6837 * This is noted because clutter_actor_get_allocation_box does some
6838 * unnecessary work to support buggy code with a comment suggesting
6839 * that it could be changed later which would be good for this use
6842 clutter_actor_get_allocation_box (self, &allocation);
6844 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6845 * actor's own coordinate space but the allocation is in parent
6849 clip->x2 = allocation.x2 - allocation.x1;
6850 clip->y2 = allocation.y2 - allocation.y1;
6854 _clutter_actor_queue_redraw_full (ClutterActor *self,
6855 ClutterRedrawFlags flags,
6856 ClutterPaintVolume *volume,
6857 ClutterEffect *effect)
6859 ClutterActorPrivate *priv = self->priv;
6860 ClutterPaintVolume allocation_pv;
6861 ClutterPaintVolume *pv;
6862 gboolean should_free_pv;
6863 ClutterActor *stage;
6865 /* Here's an outline of the actor queue redraw mechanism:
6867 * The process starts in one of the following two functions which
6868 * are wrappers for this function:
6869 * clutter_actor_queue_redraw
6870 * _clutter_actor_queue_redraw_with_clip
6872 * additionally, an effect can queue a redraw by wrapping this
6873 * function in clutter_effect_queue_rerun
6875 * This functions queues an entry in a list associated with the
6876 * stage which is a list of actors that queued a redraw while
6877 * updating the timelines, performing layouting and processing other
6878 * mainloop sources before the next paint starts.
6880 * We aim to minimize the processing done at this point because
6881 * there is a good chance other events will happen while updating
6882 * the scenegraph that would invalidate any expensive work we might
6883 * otherwise try to do here. For example we don't try and resolve
6884 * the screen space bounding box of an actor at this stage so as to
6885 * minimize how much of the screen redraw because it's possible
6886 * something else will happen which will force a full redraw anyway.
6888 * When all updates are complete and we come to paint the stage then
6889 * we iterate this list and actually emit the "queue-redraw" signals
6890 * for each of the listed actors which will bubble up to the stage
6891 * for each actor and at that point we will transform the actors
6892 * paint volume into screen coordinates to determine the clip region
6893 * for what needs to be redrawn in the next paint.
6895 * Besides minimizing redundant work another reason for this
6896 * deferred design is that it's more likely we will be able to
6897 * determine the paint volume of an actor once we've finished
6898 * updating the scenegraph because its allocation should be up to
6899 * date. NB: If we can't determine an actors paint volume then we
6900 * can't automatically queue a clipped redraw which can make a big
6901 * difference to performance.
6903 * So the control flow goes like this:
6904 * One of clutter_actor_queue_redraw,
6905 * _clutter_actor_queue_redraw_with_clip
6906 * or clutter_effect_queue_rerun
6908 * then control moves to:
6909 * _clutter_stage_queue_actor_redraw
6911 * later during _clutter_stage_do_update, once relayouting is done
6912 * and the scenegraph has been updated we will call:
6913 * _clutter_stage_finish_queue_redraws
6915 * _clutter_stage_finish_queue_redraws will call
6916 * _clutter_actor_finish_queue_redraw for each listed actor.
6917 * Note: actors *are* allowed to queue further redraws during this
6918 * process (considering clone actors or texture_new_from_actor which
6919 * respond to their source queueing a redraw by queuing a redraw
6920 * themselves). We repeat the process until the list is empty.
6922 * This will result in the "queue-redraw" signal being fired for
6923 * each actor which will pass control to the default signal handler:
6924 * clutter_actor_real_queue_redraw
6926 * This will bubble up to the stages handler:
6927 * clutter_stage_real_queue_redraw
6929 * clutter_stage_real_queue_redraw will transform the actors paint
6930 * volume into screen space and add it as a clip region for the next
6934 /* ignore queueing a redraw for actors being destroyed */
6935 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6938 stage = _clutter_actor_get_stage_internal (self);
6940 /* Ignore queueing a redraw for actors not descended from a stage */
6944 /* ignore queueing a redraw on stages that are being destroyed */
6945 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6948 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6950 ClutterActorBox allocation_clip;
6951 ClutterVertex origin;
6953 /* If the actor doesn't have a valid allocation then we will
6954 * queue a full stage redraw. */
6955 if (priv->needs_allocation)
6957 /* NB: NULL denotes an undefined clip which will result in a
6959 _clutter_actor_set_queue_redraw_clip (self, NULL);
6960 _clutter_actor_signal_queue_redraw (self, self);
6964 _clutter_paint_volume_init_static (&allocation_pv, self);
6965 pv = &allocation_pv;
6967 _clutter_actor_get_allocation_clip (self, &allocation_clip);
6969 origin.x = allocation_clip.x1;
6970 origin.y = allocation_clip.y1;
6972 clutter_paint_volume_set_origin (pv, &origin);
6973 clutter_paint_volume_set_width (pv,
6974 allocation_clip.x2 - allocation_clip.x1);
6975 clutter_paint_volume_set_height (pv,
6976 allocation_clip.y2 -
6977 allocation_clip.y1);
6978 should_free_pv = TRUE;
6983 should_free_pv = FALSE;
6986 self->priv->queue_redraw_entry =
6987 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
6988 priv->queue_redraw_entry,
6993 clutter_paint_volume_free (pv);
6995 /* If this is the first redraw queued then we can directly use the
6997 if (!priv->is_dirty)
6998 priv->effect_to_redraw = effect;
6999 /* Otherwise we need to merge it with the existing effect parameter */
7000 else if (effect != NULL)
7002 /* If there's already an effect then we need to use whichever is
7003 later in the chain of actors. Otherwise a full redraw has
7004 already been queued on the actor so we need to ignore the
7006 if (priv->effect_to_redraw != NULL)
7008 if (priv->effects == NULL)
7009 g_warning ("Redraw queued with an effect that is "
7010 "not applied to the actor");
7015 for (l = _clutter_meta_group_peek_metas (priv->effects);
7019 if (l->data == priv->effect_to_redraw ||
7021 priv->effect_to_redraw = l->data;
7028 /* If no effect is specified then we need to redraw the whole
7030 priv->effect_to_redraw = NULL;
7033 priv->is_dirty = TRUE;
7037 * clutter_actor_queue_redraw:
7038 * @self: A #ClutterActor
7040 * Queues up a redraw of an actor and any children. The redraw occurs
7041 * once the main loop becomes idle (after the current batch of events
7042 * has been processed, roughly).
7044 * Applications rarely need to call this, as redraws are handled
7045 * automatically by modification functions.
7047 * This function will not do anything if @self is not visible, or
7048 * if the actor is inside an invisible part of the scenegraph.
7050 * Also be aware that painting is a NOP for actors with an opacity of
7053 * When you are implementing a custom actor you must queue a redraw
7054 * whenever some private state changes that will affect painting or
7055 * picking of your actor.
7058 clutter_actor_queue_redraw (ClutterActor *self)
7060 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7062 _clutter_actor_queue_redraw_full (self,
7064 NULL, /* clip volume */
7069 * _clutter_actor_queue_redraw_with_clip:
7070 * @self: A #ClutterActor
7071 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7072 * this queue redraw.
7073 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7074 * redrawn or %NULL if you are just using a @flag to state your
7077 * Queues up a clipped redraw of an actor and any children. The redraw
7078 * occurs once the main loop becomes idle (after the current batch of
7079 * events has been processed, roughly).
7081 * If no flags are given the clip volume is defined by @volume
7082 * specified in actor coordinates and tells Clutter that only content
7083 * within this volume has been changed so Clutter can optionally
7084 * optimize the redraw.
7086 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7087 * should be %NULL and this tells Clutter to use the actor's current
7088 * allocation as a clip box. This flag can only be used for 2D actors,
7089 * because any actor with depth may be projected outside its
7092 * Applications rarely need to call this, as redraws are handled
7093 * automatically by modification functions.
7095 * This function will not do anything if @self is not visible, or if
7096 * the actor is inside an invisible part of the scenegraph.
7098 * Also be aware that painting is a NOP for actors with an opacity of
7101 * When you are implementing a custom actor you must queue a redraw
7102 * whenever some private state changes that will affect painting or
7103 * picking of your actor.
7106 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7107 ClutterRedrawFlags flags,
7108 ClutterPaintVolume *volume)
7110 _clutter_actor_queue_redraw_full (self,
7112 volume, /* clip volume */
7117 _clutter_actor_queue_only_relayout (ClutterActor *self)
7119 ClutterActorPrivate *priv = self->priv;
7121 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7124 if (priv->needs_width_request &&
7125 priv->needs_height_request &&
7126 priv->needs_allocation)
7127 return; /* save some cpu cycles */
7129 #if CLUTTER_ENABLE_DEBUG
7130 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7132 g_warning ("The actor '%s' is currently inside an allocation "
7133 "cycle; calling clutter_actor_queue_relayout() is "
7135 _clutter_actor_get_debug_name (self));
7137 #endif /* CLUTTER_ENABLE_DEBUG */
7139 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7143 * clutter_actor_queue_redraw_with_clip:
7144 * @self: a #ClutterActor
7145 * @clip: (allow-none): a rectangular clip region, or %NULL
7147 * Queues a redraw on @self limited to a specific, actor-relative
7150 * If @clip is %NULL this function is equivalent to
7151 * clutter_actor_queue_redraw().
7156 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7157 const cairo_rectangle_int_t *clip)
7159 ClutterPaintVolume volume;
7160 ClutterVertex origin;
7162 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7166 clutter_actor_queue_redraw (self);
7170 _clutter_paint_volume_init_static (&volume, self);
7176 clutter_paint_volume_set_origin (&volume, &origin);
7177 clutter_paint_volume_set_width (&volume, clip->width);
7178 clutter_paint_volume_set_height (&volume, clip->height);
7180 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7182 clutter_paint_volume_free (&volume);
7186 * clutter_actor_queue_relayout:
7187 * @self: A #ClutterActor
7189 * Indicates that the actor's size request or other layout-affecting
7190 * properties may have changed. This function is used inside #ClutterActor
7191 * subclass implementations, not by applications directly.
7193 * Queueing a new layout automatically queues a redraw as well.
7198 clutter_actor_queue_relayout (ClutterActor *self)
7200 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7202 _clutter_actor_queue_only_relayout (self);
7203 clutter_actor_queue_redraw (self);
7207 * clutter_actor_get_preferred_size:
7208 * @self: a #ClutterActor
7209 * @min_width_p: (out) (allow-none): return location for the minimum
7211 * @min_height_p: (out) (allow-none): return location for the minimum
7213 * @natural_width_p: (out) (allow-none): return location for the natural
7215 * @natural_height_p: (out) (allow-none): return location for the natural
7218 * Computes the preferred minimum and natural size of an actor, taking into
7219 * account the actor's geometry management (either height-for-width
7220 * or width-for-height).
7222 * The width and height used to compute the preferred height and preferred
7223 * width are the actor's natural ones.
7225 * If you need to control the height for the preferred width, or the width for
7226 * the preferred height, you should use clutter_actor_get_preferred_width()
7227 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7228 * geometry management using the #ClutterActor:request-mode property.
7233 clutter_actor_get_preferred_size (ClutterActor *self,
7234 gfloat *min_width_p,
7235 gfloat *min_height_p,
7236 gfloat *natural_width_p,
7237 gfloat *natural_height_p)
7239 ClutterActorPrivate *priv;
7240 gfloat min_width, min_height;
7241 gfloat natural_width, natural_height;
7243 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7247 min_width = min_height = 0;
7248 natural_width = natural_height = 0;
7250 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7252 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7253 clutter_actor_get_preferred_width (self, -1,
7256 clutter_actor_get_preferred_height (self, natural_width,
7262 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7263 clutter_actor_get_preferred_height (self, -1,
7266 clutter_actor_get_preferred_width (self, natural_height,
7272 *min_width_p = min_width;
7275 *min_height_p = min_height;
7277 if (natural_width_p)
7278 *natural_width_p = natural_width;
7280 if (natural_height_p)
7281 *natural_height_p = natural_height;
7286 * @align: a #ClutterActorAlign
7287 * @direction: a #ClutterTextDirection
7289 * Retrieves the correct alignment depending on the text direction
7291 * Return value: the effective alignment
7293 static ClutterActorAlign
7294 effective_align (ClutterActorAlign align,
7295 ClutterTextDirection direction)
7297 ClutterActorAlign res;
7301 case CLUTTER_ACTOR_ALIGN_START:
7302 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7303 ? CLUTTER_ACTOR_ALIGN_END
7304 : CLUTTER_ACTOR_ALIGN_START;
7307 case CLUTTER_ACTOR_ALIGN_END:
7308 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7309 ? CLUTTER_ACTOR_ALIGN_START
7310 : CLUTTER_ACTOR_ALIGN_END;
7322 adjust_for_margin (float margin_start,
7324 float *minimum_size,
7325 float *natural_size,
7326 float *allocated_start,
7327 float *allocated_end)
7329 *minimum_size -= (margin_start + margin_end);
7330 *natural_size -= (margin_start + margin_end);
7331 *allocated_start += margin_start;
7332 *allocated_end -= margin_end;
7336 adjust_for_alignment (ClutterActorAlign alignment,
7338 float *allocated_start,
7339 float *allocated_end)
7341 float allocated_size = *allocated_end - *allocated_start;
7345 case CLUTTER_ACTOR_ALIGN_FILL:
7349 case CLUTTER_ACTOR_ALIGN_START:
7351 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7354 case CLUTTER_ACTOR_ALIGN_END:
7355 if (allocated_size > natural_size)
7357 *allocated_start += (allocated_size - natural_size);
7358 *allocated_end = *allocated_start + natural_size;
7362 case CLUTTER_ACTOR_ALIGN_CENTER:
7363 if (allocated_size > natural_size)
7365 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7366 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7373 * clutter_actor_adjust_width:
7374 * @self: a #ClutterActor
7375 * @minimum_width: (inout): the actor's preferred minimum width, which
7376 * will be adjusted depending on the margin
7377 * @natural_width: (inout): the actor's preferred natural width, which
7378 * will be adjusted depending on the margin
7379 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7380 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7382 * Adjusts the preferred and allocated position and size of an actor,
7383 * depending on the margin and alignment properties.
7386 clutter_actor_adjust_width (ClutterActor *self,
7387 gfloat *minimum_width,
7388 gfloat *natural_width,
7389 gfloat *adjusted_x1,
7390 gfloat *adjusted_x2)
7392 ClutterTextDirection text_dir;
7393 const ClutterLayoutInfo *info;
7395 info = _clutter_actor_get_layout_info_or_defaults (self);
7396 text_dir = clutter_actor_get_text_direction (self);
7398 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7400 /* this will tweak natural_width to remove the margin, so that
7401 * adjust_for_alignment() will use the correct size
7403 adjust_for_margin (info->margin.left, info->margin.right,
7404 minimum_width, natural_width,
7405 adjusted_x1, adjusted_x2);
7407 adjust_for_alignment (effective_align (info->x_align, text_dir),
7409 adjusted_x1, adjusted_x2);
7413 * clutter_actor_adjust_height:
7414 * @self: a #ClutterActor
7415 * @minimum_height: (inout): the actor's preferred minimum height, which
7416 * will be adjusted depending on the margin
7417 * @natural_height: (inout): the actor's preferred natural height, which
7418 * will be adjusted depending on the margin
7419 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7420 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7422 * Adjusts the preferred and allocated position and size of an actor,
7423 * depending on the margin and alignment properties.
7426 clutter_actor_adjust_height (ClutterActor *self,
7427 gfloat *minimum_height,
7428 gfloat *natural_height,
7429 gfloat *adjusted_y1,
7430 gfloat *adjusted_y2)
7432 const ClutterLayoutInfo *info;
7434 info = _clutter_actor_get_layout_info_or_defaults (self);
7436 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7438 /* this will tweak natural_height to remove the margin, so that
7439 * adjust_for_alignment() will use the correct size
7441 adjust_for_margin (info->margin.top, info->margin.bottom,
7442 minimum_height, natural_height,
7446 /* we don't use effective_align() here, because text direction
7447 * only affects the horizontal axis
7449 adjust_for_alignment (info->y_align,
7456 /* looks for a cached size request for this for_size. If not
7457 * found, returns the oldest entry so it can be overwritten */
7459 _clutter_actor_get_cached_size_request (gfloat for_size,
7460 SizeRequest *cached_size_requests,
7461 SizeRequest **result)
7465 *result = &cached_size_requests[0];
7467 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7471 sr = &cached_size_requests[i];
7474 sr->for_size == for_size)
7476 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7480 else if (sr->age < (*result)->age)
7486 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7492 * clutter_actor_get_preferred_width:
7493 * @self: A #ClutterActor
7494 * @for_height: available height when computing the preferred width,
7495 * or a negative value to indicate that no height is defined
7496 * @min_width_p: (out) (allow-none): return location for minimum width,
7498 * @natural_width_p: (out) (allow-none): return location for the natural
7501 * Computes the requested minimum and natural widths for an actor,
7502 * optionally depending on the specified height, or if they are
7503 * already computed, returns the cached values.
7505 * An actor may not get its request - depending on the layout
7506 * manager that's in effect.
7508 * A request should not incorporate the actor's scale or anchor point;
7509 * those transformations do not affect layout, only rendering.
7514 clutter_actor_get_preferred_width (ClutterActor *self,
7516 gfloat *min_width_p,
7517 gfloat *natural_width_p)
7519 float request_min_width, request_natural_width;
7520 SizeRequest *cached_size_request;
7521 const ClutterLayoutInfo *info;
7522 ClutterActorPrivate *priv;
7523 gboolean found_in_cache;
7525 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7529 info = _clutter_actor_get_layout_info_or_defaults (self);
7531 /* we shortcircuit the case of a fixed size set using set_width() */
7532 if (priv->min_width_set && priv->natural_width_set)
7534 if (min_width_p != NULL)
7535 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7537 if (natural_width_p != NULL)
7538 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7543 /* the remaining cases are:
7545 * - either min_width or natural_width have been set
7546 * - neither min_width or natural_width have been set
7548 * in both cases, we go through the cache (and through the actor in case
7549 * of cache misses) and determine the authoritative value depending on
7553 if (!priv->needs_width_request)
7556 _clutter_actor_get_cached_size_request (for_height,
7557 priv->width_requests,
7558 &cached_size_request);
7562 /* if the actor needs a width request we use the first slot */
7563 found_in_cache = FALSE;
7564 cached_size_request = &priv->width_requests[0];
7567 if (!found_in_cache)
7569 gfloat minimum_width, natural_width;
7570 ClutterActorClass *klass;
7572 minimum_width = natural_width = 0;
7574 /* adjust for the margin */
7575 if (for_height >= 0)
7577 for_height -= (info->margin.top + info->margin.bottom);
7582 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7584 klass = CLUTTER_ACTOR_GET_CLASS (self);
7585 klass->get_preferred_width (self, for_height,
7589 /* adjust for the margin */
7590 minimum_width += (info->margin.left + info->margin.right);
7591 natural_width += (info->margin.left + info->margin.right);
7593 /* Due to accumulated float errors, it's better not to warn
7594 * on this, but just fix it.
7596 if (natural_width < minimum_width)
7597 natural_width = minimum_width;
7599 cached_size_request->min_size = minimum_width;
7600 cached_size_request->natural_size = natural_width;
7601 cached_size_request->for_size = for_height;
7602 cached_size_request->age = priv->cached_width_age;
7604 priv->cached_width_age += 1;
7605 priv->needs_width_request = FALSE;
7608 if (!priv->min_width_set)
7609 request_min_width = cached_size_request->min_size;
7611 request_min_width = info->min_width;
7613 if (!priv->natural_width_set)
7614 request_natural_width = cached_size_request->natural_size;
7616 request_natural_width = info->natural_width;
7619 *min_width_p = request_min_width;
7621 if (natural_width_p)
7622 *natural_width_p = request_natural_width;
7626 * clutter_actor_get_preferred_height:
7627 * @self: A #ClutterActor
7628 * @for_width: available width to assume in computing desired height,
7629 * or a negative value to indicate that no width is defined
7630 * @min_height_p: (out) (allow-none): return location for minimum height,
7632 * @natural_height_p: (out) (allow-none): return location for natural
7635 * Computes the requested minimum and natural heights for an actor,
7636 * or if they are already computed, returns the cached values.
7638 * An actor may not get its request - depending on the layout
7639 * manager that's in effect.
7641 * A request should not incorporate the actor's scale or anchor point;
7642 * those transformations do not affect layout, only rendering.
7647 clutter_actor_get_preferred_height (ClutterActor *self,
7649 gfloat *min_height_p,
7650 gfloat *natural_height_p)
7652 float request_min_height, request_natural_height;
7653 SizeRequest *cached_size_request;
7654 const ClutterLayoutInfo *info;
7655 ClutterActorPrivate *priv;
7656 gboolean found_in_cache;
7658 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7662 info = _clutter_actor_get_layout_info_or_defaults (self);
7664 /* we shortcircuit the case of a fixed size set using set_height() */
7665 if (priv->min_height_set && priv->natural_height_set)
7667 if (min_height_p != NULL)
7668 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7670 if (natural_height_p != NULL)
7671 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7676 /* the remaining cases are:
7678 * - either min_height or natural_height have been set
7679 * - neither min_height or natural_height have been set
7681 * in both cases, we go through the cache (and through the actor in case
7682 * of cache misses) and determine the authoritative value depending on
7686 if (!priv->needs_height_request)
7689 _clutter_actor_get_cached_size_request (for_width,
7690 priv->height_requests,
7691 &cached_size_request);
7695 found_in_cache = FALSE;
7696 cached_size_request = &priv->height_requests[0];
7699 if (!found_in_cache)
7701 gfloat minimum_height, natural_height;
7702 ClutterActorClass *klass;
7704 minimum_height = natural_height = 0;
7706 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7708 /* adjust for margin */
7711 for_width -= (info->margin.left + info->margin.right);
7716 klass = CLUTTER_ACTOR_GET_CLASS (self);
7717 klass->get_preferred_height (self, for_width,
7721 /* adjust for margin */
7722 minimum_height += (info->margin.top + info->margin.bottom);
7723 natural_height += (info->margin.top + info->margin.bottom);
7725 /* Due to accumulated float errors, it's better not to warn
7726 * on this, but just fix it.
7728 if (natural_height < minimum_height)
7729 natural_height = minimum_height;
7731 cached_size_request->min_size = minimum_height;
7732 cached_size_request->natural_size = natural_height;
7733 cached_size_request->for_size = for_width;
7734 cached_size_request->age = priv->cached_height_age;
7736 priv->cached_height_age += 1;
7737 priv->needs_height_request = FALSE;
7740 if (!priv->min_height_set)
7741 request_min_height = cached_size_request->min_size;
7743 request_min_height = info->min_height;
7745 if (!priv->natural_height_set)
7746 request_natural_height = cached_size_request->natural_size;
7748 request_natural_height = info->natural_height;
7751 *min_height_p = request_min_height;
7753 if (natural_height_p)
7754 *natural_height_p = request_natural_height;
7758 * clutter_actor_get_allocation_box:
7759 * @self: A #ClutterActor
7760 * @box: (out): the function fills this in with the actor's allocation
7762 * Gets the layout box an actor has been assigned. The allocation can
7763 * only be assumed valid inside a paint() method; anywhere else, it
7764 * may be out-of-date.
7766 * An allocation does not incorporate the actor's scale or anchor point;
7767 * those transformations do not affect layout, only rendering.
7769 * <note>Do not call any of the clutter_actor_get_allocation_*() family
7770 * of functions inside the implementation of the get_preferred_width()
7771 * or get_preferred_height() virtual functions.</note>
7776 clutter_actor_get_allocation_box (ClutterActor *self,
7777 ClutterActorBox *box)
7779 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7781 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7782 * which limits calling get_allocation to inside paint() basically; or
7783 * we can 2) force a layout, which could be expensive if someone calls
7784 * get_allocation somewhere silly; or we can 3) just return the latest
7785 * value, allowing it to be out-of-date, and assume people know what
7788 * The least-surprises approach that keeps existing code working is
7789 * likely to be 2). People can end up doing some inefficient things,
7790 * though, and in general code that requires 2) is probably broken.
7793 /* this implements 2) */
7794 if (G_UNLIKELY (self->priv->needs_allocation))
7796 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7798 /* do not queue a relayout on an unparented actor */
7800 _clutter_stage_maybe_relayout (stage);
7803 /* commenting out the code above and just keeping this assigment
7806 *box = self->priv->allocation;
7810 * clutter_actor_get_allocation_geometry:
7811 * @self: A #ClutterActor
7812 * @geom: (out): allocation geometry in pixels
7814 * Gets the layout box an actor has been assigned. The allocation can
7815 * only be assumed valid inside a paint() method; anywhere else, it
7816 * may be out-of-date.
7818 * An allocation does not incorporate the actor's scale or anchor point;
7819 * those transformations do not affect layout, only rendering.
7821 * The returned rectangle is in pixels.
7826 clutter_actor_get_allocation_geometry (ClutterActor *self,
7827 ClutterGeometry *geom)
7829 ClutterActorBox box;
7831 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7832 g_return_if_fail (geom != NULL);
7834 clutter_actor_get_allocation_box (self, &box);
7836 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7837 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7838 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7839 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7843 clutter_actor_update_constraints (ClutterActor *self,
7844 ClutterActorBox *allocation)
7846 ClutterActorPrivate *priv = self->priv;
7847 const GList *constraints, *l;
7849 if (priv->constraints == NULL)
7852 constraints = _clutter_meta_group_peek_metas (priv->constraints);
7853 for (l = constraints; l != NULL; l = l->next)
7855 ClutterConstraint *constraint = l->data;
7856 ClutterActorMeta *meta = l->data;
7858 if (clutter_actor_meta_get_enabled (meta))
7860 _clutter_constraint_update_allocation (constraint,
7868 * clutter_actor_adjust_allocation:
7869 * @self: a #ClutterActor
7870 * @allocation: (inout): the allocation to adjust
7872 * Adjusts the passed allocation box taking into account the actor's
7873 * layout information, like alignment, expansion, and margin.
7876 clutter_actor_adjust_allocation (ClutterActor *self,
7877 ClutterActorBox *allocation)
7879 ClutterActorBox adj_allocation;
7880 float alloc_width, alloc_height;
7881 float min_width, min_height;
7882 float nat_width, nat_height;
7883 ClutterRequestMode req_mode;
7885 adj_allocation = *allocation;
7887 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7889 /* we want to hit the cache, so we use the public API */
7890 req_mode = clutter_actor_get_request_mode (self);
7892 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7894 clutter_actor_get_preferred_width (self, -1,
7897 clutter_actor_get_preferred_height (self, alloc_width,
7901 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7903 clutter_actor_get_preferred_height (self, -1,
7906 clutter_actor_get_preferred_height (self, alloc_height,
7911 #ifdef CLUTTER_ENABLE_DEBUG
7912 /* warn about underallocations */
7913 if (_clutter_diagnostic_enabled () &&
7914 (floorf (min_width - alloc_width) > 0 ||
7915 floorf (min_height - alloc_height) > 0))
7917 ClutterActor *parent = clutter_actor_get_parent (self);
7919 /* the only actors that are allowed to be underallocated are the Stage,
7920 * as it doesn't have an implicit size, and Actors that specifically
7921 * told us that they want to opt-out from layout control mechanisms
7922 * through the NO_LAYOUT escape hatch.
7924 if (parent != NULL &&
7925 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7927 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7928 "of %.2f x %.2f from its parent actor '%s', but its "
7929 "requested minimum size is of %.2f x %.2f",
7930 _clutter_actor_get_debug_name (self),
7931 alloc_width, alloc_height,
7932 _clutter_actor_get_debug_name (parent),
7933 min_width, min_height);
7938 clutter_actor_adjust_width (self,
7942 &adj_allocation.x2);
7944 clutter_actor_adjust_height (self,
7948 &adj_allocation.y2);
7950 /* we maintain the invariant that an allocation cannot be adjusted
7951 * to be outside the parent-given box
7953 if (adj_allocation.x1 < allocation->x1 ||
7954 adj_allocation.y1 < allocation->y1 ||
7955 adj_allocation.x2 > allocation->x2 ||
7956 adj_allocation.y2 > allocation->y2)
7958 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7959 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7960 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7961 _clutter_actor_get_debug_name (self),
7962 adj_allocation.x1, adj_allocation.y1,
7963 adj_allocation.x2 - adj_allocation.x1,
7964 adj_allocation.y2 - adj_allocation.y1,
7965 allocation->x1, allocation->y1,
7966 allocation->x2 - allocation->x1,
7967 allocation->y2 - allocation->y1);
7971 *allocation = adj_allocation;
7975 * clutter_actor_allocate:
7976 * @self: A #ClutterActor
7977 * @box: new allocation of the actor, in parent-relative coordinates
7978 * @flags: flags that control the allocation
7980 * Called by the parent of an actor to assign the actor its size.
7981 * Should never be called by applications (except when implementing
7982 * a container or layout manager).
7984 * Actors can know from their allocation box whether they have moved
7985 * with respect to their parent actor. The @flags parameter describes
7986 * additional information about the allocation, for instance whether
7987 * the parent has moved with respect to the stage, for example because
7988 * a grandparent's origin has moved.
7993 clutter_actor_allocate (ClutterActor *self,
7994 const ClutterActorBox *box,
7995 ClutterAllocationFlags flags)
7997 ClutterActorPrivate *priv;
7998 ClutterActorClass *klass;
7999 ClutterActorBox old_allocation, real_allocation;
8000 gboolean origin_changed, child_moved, size_changed;
8001 gboolean stage_allocation_changed;
8003 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8004 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8006 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8007 "which isn't a descendent of the stage!\n",
8008 self, _clutter_actor_get_debug_name (self));
8014 old_allocation = priv->allocation;
8015 real_allocation = *box;
8017 /* constraints are allowed to modify the allocation only here; we do
8018 * this prior to all the other checks so that we can bail out if the
8019 * allocation did not change
8021 clutter_actor_update_constraints (self, &real_allocation);
8023 /* adjust the allocation depending on the align/margin properties */
8024 clutter_actor_adjust_allocation (self, &real_allocation);
8026 if (real_allocation.x2 < real_allocation.x1 ||
8027 real_allocation.y2 < real_allocation.y1)
8029 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8030 _clutter_actor_get_debug_name (self),
8031 real_allocation.x2 - real_allocation.x1,
8032 real_allocation.y2 - real_allocation.y1);
8035 /* we allow 0-sized actors, but not negative-sized ones */
8036 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8037 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8039 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8041 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8042 real_allocation.y1 != old_allocation.y1);
8044 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8045 real_allocation.y2 != old_allocation.y2);
8047 if (origin_changed || child_moved || size_changed)
8048 stage_allocation_changed = TRUE;
8050 stage_allocation_changed = FALSE;
8052 /* If we get an allocation "out of the blue"
8053 * (we did not queue relayout), then we want to
8054 * ignore it. But if we have needs_allocation set,
8055 * we want to guarantee that allocate() virtual
8056 * method is always called, i.e. that queue_relayout()
8057 * always results in an allocate() invocation on
8060 * The optimization here is to avoid re-allocating
8061 * actors that did not queue relayout and were
8064 if (!priv->needs_allocation && !stage_allocation_changed)
8066 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8070 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8071 * clutter_actor_allocate(), it indicates whether the parent has its
8072 * absolute origin moved; when passed in to ClutterActor::allocate()
8073 * virtual method though, it indicates whether the child has its
8074 * absolute origin moved. So we set it when child_moved is TRUE
8077 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8079 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8081 klass = CLUTTER_ACTOR_GET_CLASS (self);
8082 klass->allocate (self, &real_allocation, flags);
8084 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8086 if (stage_allocation_changed)
8087 clutter_actor_queue_redraw (self);
8091 * clutter_actor_set_allocation:
8092 * @self: a #ClutterActor
8093 * @box: a #ClutterActorBox
8094 * @flags: allocation flags
8096 * Stores the allocation of @self as defined by @box.
8098 * This function can only be called from within the implementation of
8099 * the #ClutterActorClass.allocate() virtual function.
8101 * The allocation should have been adjusted to take into account constraints,
8102 * alignment, and margin properties. If you are implementing a #ClutterActor
8103 * subclass that provides its own layout management policy for its children
8104 * instead of using a #ClutterLayoutManager delegate, you should not call
8105 * this function on the children of @self; instead, you should call
8106 * clutter_actor_allocate(), which will adjust the allocation box for
8109 * This function should only be used by subclasses of #ClutterActor
8110 * that wish to store their allocation but cannot chain up to the
8111 * parent's implementation; the default implementation of the
8112 * #ClutterActorClass.allocate() virtual function will call this
8115 * It is important to note that, while chaining up was the recommended
8116 * behaviour for #ClutterActor subclasses prior to the introduction of
8117 * this function, it is recommended to call clutter_actor_set_allocation()
8120 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8121 * to handle the allocation of its children, this function will call
8122 * the clutter_layout_manager_allocate() function only if the
8123 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8124 * expected that the subclass will call clutter_layout_manager_allocate()
8125 * by itself. For instance, the following code:
8129 * my_actor_allocate (ClutterActor *actor,
8130 * const ClutterActorBox *allocation,
8131 * ClutterAllocationFlags flags)
8133 * ClutterActorBox new_alloc;
8134 * ClutterAllocationFlags new_flags;
8136 * adjust_allocation (allocation, &new_alloc);
8138 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8140 * /* this will use the layout manager set on the actor */
8141 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8145 * is equivalent to this:
8149 * my_actor_allocate (ClutterActor *actor,
8150 * const ClutterActorBox *allocation,
8151 * ClutterAllocationFlags flags)
8153 * ClutterLayoutManager *layout;
8154 * ClutterActorBox new_alloc;
8156 * adjust_allocation (allocation, &new_alloc);
8158 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8160 * layout = clutter_actor_get_layout_manager (actor);
8161 * clutter_layout_manager_allocate (layout,
8162 * CLUTTER_CONTAINER (actor),
8171 clutter_actor_set_allocation (ClutterActor *self,
8172 const ClutterActorBox *box,
8173 ClutterAllocationFlags flags)
8175 ClutterActorPrivate *priv;
8178 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8179 g_return_if_fail (box != NULL);
8181 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8183 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8184 "can only be called from within the implementation of "
8185 "the ClutterActor::allocate() virtual function.");
8191 g_object_freeze_notify (G_OBJECT (self));
8193 changed = clutter_actor_set_allocation_internal (self, box, flags);
8195 /* we allocate our children before we notify changes in our geometry,
8196 * so that people connecting to properties will be able to get valid
8197 * data out of the sub-tree of the scene graph that has this actor at
8200 clutter_actor_maybe_layout_children (self, box, flags);
8204 ClutterActorBox signal_box = priv->allocation;
8205 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8207 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8212 g_object_thaw_notify (G_OBJECT (self));
8216 * clutter_actor_set_geometry:
8217 * @self: A #ClutterActor
8218 * @geometry: A #ClutterGeometry
8220 * Sets the actor's fixed position and forces its minimum and natural
8221 * size, in pixels. This means the untransformed actor will have the
8222 * given geometry. This is the same as calling clutter_actor_set_position()
8223 * and clutter_actor_set_size().
8225 * Deprecated: 1.10: Use clutter_actor_set_position() and
8226 * clutter_actor_set_size() instead.
8229 clutter_actor_set_geometry (ClutterActor *self,
8230 const ClutterGeometry *geometry)
8232 g_object_freeze_notify (G_OBJECT (self));
8234 clutter_actor_set_position (self, geometry->x, geometry->y);
8235 clutter_actor_set_size (self, geometry->width, geometry->height);
8237 g_object_thaw_notify (G_OBJECT (self));
8241 * clutter_actor_get_geometry:
8242 * @self: A #ClutterActor
8243 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8245 * Gets the size and position of an actor relative to its parent
8246 * actor. This is the same as calling clutter_actor_get_position() and
8247 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8248 * requested size and position if the actor's allocation is invalid.
8250 * Deprecated: 1.10: Use clutter_actor_get_position() and
8251 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8255 clutter_actor_get_geometry (ClutterActor *self,
8256 ClutterGeometry *geometry)
8258 gfloat x, y, width, height;
8260 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8261 g_return_if_fail (geometry != NULL);
8263 clutter_actor_get_position (self, &x, &y);
8264 clutter_actor_get_size (self, &width, &height);
8266 geometry->x = (int) x;
8267 geometry->y = (int) y;
8268 geometry->width = (int) width;
8269 geometry->height = (int) height;
8273 * clutter_actor_set_position:
8274 * @self: A #ClutterActor
8275 * @x: New left position of actor in pixels.
8276 * @y: New top position of actor in pixels.
8278 * Sets the actor's fixed position in pixels relative to any parent
8281 * If a layout manager is in use, this position will override the
8282 * layout manager and force a fixed position.
8285 clutter_actor_set_position (ClutterActor *self,
8289 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8291 g_object_freeze_notify (G_OBJECT (self));
8293 clutter_actor_set_x (self, x);
8294 clutter_actor_set_y (self, y);
8296 g_object_thaw_notify (G_OBJECT (self));
8300 * clutter_actor_get_fixed_position_set:
8301 * @self: A #ClutterActor
8303 * Checks whether an actor has a fixed position set (and will thus be
8304 * unaffected by any layout manager).
8306 * Return value: %TRUE if the fixed position is set on the actor
8311 clutter_actor_get_fixed_position_set (ClutterActor *self)
8313 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8315 return self->priv->position_set;
8319 * clutter_actor_set_fixed_position_set:
8320 * @self: A #ClutterActor
8321 * @is_set: whether to use fixed position
8323 * Sets whether an actor has a fixed position set (and will thus be
8324 * unaffected by any layout manager).
8329 clutter_actor_set_fixed_position_set (ClutterActor *self,
8332 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8334 if (self->priv->position_set == (is_set != FALSE))
8337 self->priv->position_set = is_set != FALSE;
8338 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8340 clutter_actor_queue_relayout (self);
8344 * clutter_actor_move_by:
8345 * @self: A #ClutterActor
8346 * @dx: Distance to move Actor on X axis.
8347 * @dy: Distance to move Actor on Y axis.
8349 * Moves an actor by the specified distance relative to its current
8350 * position in pixels.
8352 * This function modifies the fixed position of an actor and thus removes
8353 * it from any layout management. Another way to move an actor is with an
8354 * anchor point, see clutter_actor_set_anchor_point().
8359 clutter_actor_move_by (ClutterActor *self,
8363 const ClutterLayoutInfo *info;
8366 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8368 info = _clutter_actor_get_layout_info_or_defaults (self);
8372 clutter_actor_set_position (self, x + dx, y + dy);
8376 clutter_actor_set_min_width (ClutterActor *self,
8379 ClutterActorPrivate *priv = self->priv;
8380 ClutterActorBox old = { 0, };
8381 ClutterLayoutInfo *info;
8383 /* if we are setting the size on a top-level actor and the
8384 * backend only supports static top-levels (e.g. framebuffers)
8385 * then we ignore the passed value and we override it with
8386 * the stage implementation's preferred size.
8388 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8389 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8392 info = _clutter_actor_get_layout_info (self);
8394 if (priv->min_width_set && min_width == info->min_width)
8397 g_object_freeze_notify (G_OBJECT (self));
8399 clutter_actor_store_old_geometry (self, &old);
8401 info->min_width = min_width;
8402 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8403 clutter_actor_set_min_width_set (self, TRUE);
8405 clutter_actor_notify_if_geometry_changed (self, &old);
8407 g_object_thaw_notify (G_OBJECT (self));
8409 clutter_actor_queue_relayout (self);
8413 clutter_actor_set_min_height (ClutterActor *self,
8417 ClutterActorPrivate *priv = self->priv;
8418 ClutterActorBox old = { 0, };
8419 ClutterLayoutInfo *info;
8421 /* if we are setting the size on a top-level actor and the
8422 * backend only supports static top-levels (e.g. framebuffers)
8423 * then we ignore the passed value and we override it with
8424 * the stage implementation's preferred size.
8426 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8427 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8430 info = _clutter_actor_get_layout_info (self);
8432 if (priv->min_height_set && min_height == info->min_height)
8435 g_object_freeze_notify (G_OBJECT (self));
8437 clutter_actor_store_old_geometry (self, &old);
8439 info->min_height = min_height;
8440 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8441 clutter_actor_set_min_height_set (self, TRUE);
8443 clutter_actor_notify_if_geometry_changed (self, &old);
8445 g_object_thaw_notify (G_OBJECT (self));
8447 clutter_actor_queue_relayout (self);
8451 clutter_actor_set_natural_width (ClutterActor *self,
8452 gfloat natural_width)
8454 ClutterActorPrivate *priv = self->priv;
8455 ClutterActorBox old = { 0, };
8456 ClutterLayoutInfo *info;
8458 /* if we are setting the size on a top-level actor and the
8459 * backend only supports static top-levels (e.g. framebuffers)
8460 * then we ignore the passed value and we override it with
8461 * the stage implementation's preferred size.
8463 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8464 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8467 info = _clutter_actor_get_layout_info (self);
8469 if (priv->natural_width_set && natural_width == info->natural_width)
8472 g_object_freeze_notify (G_OBJECT (self));
8474 clutter_actor_store_old_geometry (self, &old);
8476 info->natural_width = natural_width;
8477 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8478 clutter_actor_set_natural_width_set (self, TRUE);
8480 clutter_actor_notify_if_geometry_changed (self, &old);
8482 g_object_thaw_notify (G_OBJECT (self));
8484 clutter_actor_queue_relayout (self);
8488 clutter_actor_set_natural_height (ClutterActor *self,
8489 gfloat natural_height)
8491 ClutterActorPrivate *priv = self->priv;
8492 ClutterActorBox old = { 0, };
8493 ClutterLayoutInfo *info;
8495 /* if we are setting the size on a top-level actor and the
8496 * backend only supports static top-levels (e.g. framebuffers)
8497 * then we ignore the passed value and we override it with
8498 * the stage implementation's preferred size.
8500 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8501 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8504 info = _clutter_actor_get_layout_info (self);
8506 if (priv->natural_height_set && natural_height == info->natural_height)
8509 g_object_freeze_notify (G_OBJECT (self));
8511 clutter_actor_store_old_geometry (self, &old);
8513 info->natural_height = natural_height;
8514 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8515 clutter_actor_set_natural_height_set (self, TRUE);
8517 clutter_actor_notify_if_geometry_changed (self, &old);
8519 g_object_thaw_notify (G_OBJECT (self));
8521 clutter_actor_queue_relayout (self);
8525 clutter_actor_set_min_width_set (ClutterActor *self,
8526 gboolean use_min_width)
8528 ClutterActorPrivate *priv = self->priv;
8529 ClutterActorBox old = { 0, };
8531 if (priv->min_width_set == (use_min_width != FALSE))
8534 clutter_actor_store_old_geometry (self, &old);
8536 priv->min_width_set = use_min_width != FALSE;
8537 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8539 clutter_actor_notify_if_geometry_changed (self, &old);
8541 clutter_actor_queue_relayout (self);
8545 clutter_actor_set_min_height_set (ClutterActor *self,
8546 gboolean use_min_height)
8548 ClutterActorPrivate *priv = self->priv;
8549 ClutterActorBox old = { 0, };
8551 if (priv->min_height_set == (use_min_height != FALSE))
8554 clutter_actor_store_old_geometry (self, &old);
8556 priv->min_height_set = use_min_height != FALSE;
8557 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8559 clutter_actor_notify_if_geometry_changed (self, &old);
8561 clutter_actor_queue_relayout (self);
8565 clutter_actor_set_natural_width_set (ClutterActor *self,
8566 gboolean use_natural_width)
8568 ClutterActorPrivate *priv = self->priv;
8569 ClutterActorBox old = { 0, };
8571 if (priv->natural_width_set == (use_natural_width != FALSE))
8574 clutter_actor_store_old_geometry (self, &old);
8576 priv->natural_width_set = use_natural_width != FALSE;
8577 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8579 clutter_actor_notify_if_geometry_changed (self, &old);
8581 clutter_actor_queue_relayout (self);
8585 clutter_actor_set_natural_height_set (ClutterActor *self,
8586 gboolean use_natural_height)
8588 ClutterActorPrivate *priv = self->priv;
8589 ClutterActorBox old = { 0, };
8591 if (priv->natural_height_set == (use_natural_height != FALSE))
8594 clutter_actor_store_old_geometry (self, &old);
8596 priv->natural_height_set = use_natural_height != FALSE;
8597 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8599 clutter_actor_notify_if_geometry_changed (self, &old);
8601 clutter_actor_queue_relayout (self);
8605 * clutter_actor_set_request_mode:
8606 * @self: a #ClutterActor
8607 * @mode: the request mode
8609 * Sets the geometry request mode of @self.
8611 * The @mode determines the order for invoking
8612 * clutter_actor_get_preferred_width() and
8613 * clutter_actor_get_preferred_height()
8618 clutter_actor_set_request_mode (ClutterActor *self,
8619 ClutterRequestMode mode)
8621 ClutterActorPrivate *priv;
8623 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8627 if (priv->request_mode == mode)
8630 priv->request_mode = mode;
8632 priv->needs_width_request = TRUE;
8633 priv->needs_height_request = TRUE;
8635 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8637 clutter_actor_queue_relayout (self);
8641 * clutter_actor_get_request_mode:
8642 * @self: a #ClutterActor
8644 * Retrieves the geometry request mode of @self
8646 * Return value: the request mode for the actor
8651 clutter_actor_get_request_mode (ClutterActor *self)
8653 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8654 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8656 return self->priv->request_mode;
8659 /* variant of set_width() without checks and without notification
8660 * freeze+thaw, for internal usage only
8663 clutter_actor_set_width_internal (ClutterActor *self,
8668 /* the Stage will use the :min-width to control the minimum
8669 * width to be resized to, so we should not be setting it
8670 * along with the :natural-width
8672 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8673 clutter_actor_set_min_width (self, width);
8675 clutter_actor_set_natural_width (self, width);
8679 /* we only unset the :natural-width for the Stage */
8680 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8681 clutter_actor_set_min_width_set (self, FALSE);
8683 clutter_actor_set_natural_width_set (self, FALSE);
8687 /* variant of set_height() without checks and without notification
8688 * freeze+thaw, for internal usage only
8691 clutter_actor_set_height_internal (ClutterActor *self,
8696 /* see the comment above in set_width_internal() */
8697 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8698 clutter_actor_set_min_height (self, height);
8700 clutter_actor_set_natural_height (self, height);
8704 /* see the comment above in set_width_internal() */
8705 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8706 clutter_actor_set_min_height_set (self, FALSE);
8708 clutter_actor_set_natural_height_set (self, FALSE);
8713 * clutter_actor_set_size:
8714 * @self: A #ClutterActor
8715 * @width: New width of actor in pixels, or -1
8716 * @height: New height of actor in pixels, or -1
8718 * Sets the actor's size request in pixels. This overrides any
8719 * "normal" size request the actor would have. For example
8720 * a text actor might normally request the size of the text;
8721 * this function would force a specific size instead.
8723 * If @width and/or @height are -1 the actor will use its
8724 * "normal" size request instead of overriding it, i.e.
8725 * you can "unset" the size with -1.
8727 * This function sets or unsets both the minimum and natural size.
8730 clutter_actor_set_size (ClutterActor *self,
8734 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8736 g_object_freeze_notify (G_OBJECT (self));
8738 clutter_actor_set_width (self, width);
8739 clutter_actor_set_height (self, height);
8741 g_object_thaw_notify (G_OBJECT (self));
8745 * clutter_actor_get_size:
8746 * @self: A #ClutterActor
8747 * @width: (out) (allow-none): return location for the width, or %NULL.
8748 * @height: (out) (allow-none): return location for the height, or %NULL.
8750 * This function tries to "do what you mean" and return
8751 * the size an actor will have. If the actor has a valid
8752 * allocation, the allocation will be returned; otherwise,
8753 * the actors natural size request will be returned.
8755 * If you care whether you get the request vs. the allocation, you
8756 * should probably call a different function like
8757 * clutter_actor_get_allocation_box() or
8758 * clutter_actor_get_preferred_width().
8763 clutter_actor_get_size (ClutterActor *self,
8767 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8770 *width = clutter_actor_get_width (self);
8773 *height = clutter_actor_get_height (self);
8777 * clutter_actor_get_position:
8778 * @self: a #ClutterActor
8779 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8780 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8782 * This function tries to "do what you mean" and tell you where the
8783 * actor is, prior to any transformations. Retrieves the fixed
8784 * position of an actor in pixels, if one has been set; otherwise, if
8785 * the allocation is valid, returns the actor's allocated position;
8786 * otherwise, returns 0,0.
8788 * The returned position is in pixels.
8793 clutter_actor_get_position (ClutterActor *self,
8797 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8800 *x = clutter_actor_get_x (self);
8803 *y = clutter_actor_get_y (self);
8807 * clutter_actor_get_transformed_position:
8808 * @self: A #ClutterActor
8809 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8810 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8812 * Gets the absolute position of an actor, in pixels relative to the stage.
8817 clutter_actor_get_transformed_position (ClutterActor *self,
8824 v1.x = v1.y = v1.z = 0;
8825 clutter_actor_apply_transform_to_point (self, &v1, &v2);
8835 * clutter_actor_get_transformed_size:
8836 * @self: A #ClutterActor
8837 * @width: (out) (allow-none): return location for the width, or %NULL
8838 * @height: (out) (allow-none): return location for the height, or %NULL
8840 * Gets the absolute size of an actor in pixels, taking into account the
8843 * If the actor has a valid allocation, the allocated size will be used.
8844 * If the actor has not a valid allocation then the preferred size will
8845 * be transformed and returned.
8847 * If you want the transformed allocation, see
8848 * clutter_actor_get_abs_allocation_vertices() instead.
8850 * <note>When the actor (or one of its ancestors) is rotated around the
8851 * X or Y axis, it no longer appears as on the stage as a rectangle, but
8852 * as a generic quadrangle; in that case this function returns the size
8853 * of the smallest rectangle that encapsulates the entire quad. Please
8854 * note that in this case no assumptions can be made about the relative
8855 * position of this envelope to the absolute position of the actor, as
8856 * returned by clutter_actor_get_transformed_position(); if you need this
8857 * information, you need to use clutter_actor_get_abs_allocation_vertices()
8858 * to get the coords of the actual quadrangle.</note>
8863 clutter_actor_get_transformed_size (ClutterActor *self,
8867 ClutterActorPrivate *priv;
8869 gfloat x_min, x_max, y_min, y_max;
8872 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8876 /* if the actor hasn't been allocated yet, get the preferred
8877 * size and transform that
8879 if (priv->needs_allocation)
8881 gfloat natural_width, natural_height;
8882 ClutterActorBox box;
8884 /* Make a fake allocation to transform.
8886 * NB: _clutter_actor_transform_and_project_box expects a box in
8887 * the actor's coordinate space... */
8892 natural_width = natural_height = 0;
8893 clutter_actor_get_preferred_size (self, NULL, NULL,
8897 box.x2 = natural_width;
8898 box.y2 = natural_height;
8900 _clutter_actor_transform_and_project_box (self, &box, v);
8903 clutter_actor_get_abs_allocation_vertices (self, v);
8905 x_min = x_max = v[0].x;
8906 y_min = y_max = v[0].y;
8908 for (i = 1; i < G_N_ELEMENTS (v); ++i)
8924 *width = x_max - x_min;
8927 *height = y_max - y_min;
8931 * clutter_actor_get_width:
8932 * @self: A #ClutterActor
8934 * Retrieves the width of a #ClutterActor.
8936 * If the actor has a valid allocation, this function will return the
8937 * width of the allocated area given to the actor.
8939 * If the actor does not have a valid allocation, this function will
8940 * return the actor's natural width, that is the preferred width of
8943 * If you care whether you get the preferred width or the width that
8944 * has been assigned to the actor, you should probably call a different
8945 * function like clutter_actor_get_allocation_box() to retrieve the
8946 * allocated size or clutter_actor_get_preferred_width() to retrieve the
8949 * If an actor has a fixed width, for instance a width that has been
8950 * assigned using clutter_actor_set_width(), the width returned will
8951 * be the same value.
8953 * Return value: the width of the actor, in pixels
8956 clutter_actor_get_width (ClutterActor *self)
8958 ClutterActorPrivate *priv;
8960 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
8964 if (priv->needs_allocation)
8966 gfloat natural_width = 0;
8968 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8969 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
8972 gfloat natural_height = 0;
8974 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
8975 clutter_actor_get_preferred_width (self, natural_height,
8980 return natural_width;
8983 return priv->allocation.x2 - priv->allocation.x1;
8987 * clutter_actor_get_height:
8988 * @self: A #ClutterActor
8990 * Retrieves the height of a #ClutterActor.
8992 * If the actor has a valid allocation, this function will return the
8993 * height of the allocated area given to the actor.
8995 * If the actor does not have a valid allocation, this function will
8996 * return the actor's natural height, that is the preferred height of
8999 * If you care whether you get the preferred height or the height that
9000 * has been assigned to the actor, you should probably call a different
9001 * function like clutter_actor_get_allocation_box() to retrieve the
9002 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9005 * If an actor has a fixed height, for instance a height that has been
9006 * assigned using clutter_actor_set_height(), the height returned will
9007 * be the same value.
9009 * Return value: the height of the actor, in pixels
9012 clutter_actor_get_height (ClutterActor *self)
9014 ClutterActorPrivate *priv;
9016 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9020 if (priv->needs_allocation)
9022 gfloat natural_height = 0;
9024 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9026 gfloat natural_width = 0;
9028 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9029 clutter_actor_get_preferred_height (self, natural_width,
9030 NULL, &natural_height);
9033 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9035 return natural_height;
9038 return priv->allocation.y2 - priv->allocation.y1;
9042 * clutter_actor_set_width:
9043 * @self: A #ClutterActor
9044 * @width: Requested new width for the actor, in pixels, or -1
9046 * Forces a width on an actor, causing the actor's preferred width
9047 * and height (if any) to be ignored.
9049 * If @width is -1 the actor will use its preferred width request
9050 * instead of overriding it, i.e. you can "unset" the width with -1.
9052 * This function sets both the minimum and natural size of the actor.
9057 clutter_actor_set_width (ClutterActor *self,
9060 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9062 if (clutter_actor_get_easing_duration (self) != 0)
9064 ClutterTransition *transition;
9066 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9067 if (transition == NULL)
9069 float old_width = clutter_actor_get_width (self);
9071 transition = _clutter_actor_create_transition (self,
9072 obj_props[PROP_WIDTH],
9075 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9078 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9080 clutter_actor_queue_relayout (self);
9084 g_object_freeze_notify (G_OBJECT (self));
9086 clutter_actor_set_width_internal (self, width);
9088 g_object_thaw_notify (G_OBJECT (self));
9093 * clutter_actor_set_height:
9094 * @self: A #ClutterActor
9095 * @height: Requested new height for the actor, in pixels, or -1
9097 * Forces a height on an actor, causing the actor's preferred width
9098 * and height (if any) to be ignored.
9100 * If @height is -1 the actor will use its preferred height instead of
9101 * overriding it, i.e. you can "unset" the height with -1.
9103 * This function sets both the minimum and natural size of the actor.
9108 clutter_actor_set_height (ClutterActor *self,
9111 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9113 if (clutter_actor_get_easing_duration (self) != 0)
9115 ClutterTransition *transition;
9117 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9118 if (transition == NULL)
9120 float old_height = clutter_actor_get_height (self);
9122 transition = _clutter_actor_create_transition (self,
9123 obj_props[PROP_HEIGHT],
9126 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9129 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9131 clutter_actor_queue_relayout (self);
9135 g_object_freeze_notify (G_OBJECT (self));
9137 clutter_actor_set_height_internal (self, height);
9139 g_object_thaw_notify (G_OBJECT (self));
9144 clutter_actor_set_x_internal (ClutterActor *self,
9147 ClutterActorPrivate *priv = self->priv;
9148 ClutterLayoutInfo *linfo;
9149 ClutterActorBox old = { 0, };
9151 linfo = _clutter_actor_get_layout_info (self);
9153 if (priv->position_set && linfo->fixed_x == x)
9156 clutter_actor_store_old_geometry (self, &old);
9159 clutter_actor_set_fixed_position_set (self, TRUE);
9161 clutter_actor_notify_if_geometry_changed (self, &old);
9163 clutter_actor_queue_relayout (self);
9167 clutter_actor_set_y_internal (ClutterActor *self,
9170 ClutterActorPrivate *priv = self->priv;
9171 ClutterLayoutInfo *linfo;
9172 ClutterActorBox old = { 0, };
9174 linfo = _clutter_actor_get_layout_info (self);
9176 if (priv->position_set && linfo->fixed_y == y)
9179 clutter_actor_store_old_geometry (self, &old);
9182 clutter_actor_set_fixed_position_set (self, TRUE);
9184 clutter_actor_notify_if_geometry_changed (self, &old);
9188 * clutter_actor_set_x:
9189 * @self: a #ClutterActor
9190 * @x: the actor's position on the X axis
9192 * Sets the actor's X coordinate, relative to its parent, in pixels.
9194 * Overrides any layout manager and forces a fixed position for
9197 * The #ClutterActor:x property is animatable.
9202 clutter_actor_set_x (ClutterActor *self,
9205 const ClutterLayoutInfo *linfo;
9207 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9209 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9211 if (clutter_actor_get_easing_duration (self) != 0)
9213 ClutterTransition *transition;
9215 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9216 if (transition == NULL)
9218 transition = _clutter_actor_create_transition (self,
9223 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9226 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9228 clutter_actor_queue_relayout (self);
9231 clutter_actor_set_x_internal (self, x);
9235 * clutter_actor_set_y:
9236 * @self: a #ClutterActor
9237 * @y: the actor's position on the Y axis
9239 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9241 * Overrides any layout manager and forces a fixed position for
9244 * The #ClutterActor:y property is animatable.
9249 clutter_actor_set_y (ClutterActor *self,
9252 const ClutterLayoutInfo *linfo;
9254 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9256 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9258 if (clutter_actor_get_easing_duration (self) != 0)
9260 ClutterTransition *transition;
9262 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9263 if (transition == NULL)
9265 transition = _clutter_actor_create_transition (self,
9270 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9273 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9275 clutter_actor_queue_relayout (self);
9278 clutter_actor_set_y_internal (self, y);
9280 clutter_actor_queue_relayout (self);
9284 * clutter_actor_get_x:
9285 * @self: A #ClutterActor
9287 * Retrieves the X coordinate of a #ClutterActor.
9289 * This function tries to "do what you mean", by returning the
9290 * correct value depending on the actor's state.
9292 * If the actor has a valid allocation, this function will return
9293 * the X coordinate of the origin of the allocation box.
9295 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9296 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9297 * function will return that coordinate.
9299 * If both the allocation and a fixed position are missing, this function
9302 * Return value: the X coordinate, in pixels, ignoring any
9303 * transformation (i.e. scaling, rotation)
9306 clutter_actor_get_x (ClutterActor *self)
9308 ClutterActorPrivate *priv;
9310 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9314 if (priv->needs_allocation)
9316 if (priv->position_set)
9318 const ClutterLayoutInfo *info;
9320 info = _clutter_actor_get_layout_info_or_defaults (self);
9322 return info->fixed_x;
9328 return priv->allocation.x1;
9332 * clutter_actor_get_y:
9333 * @self: A #ClutterActor
9335 * Retrieves the Y coordinate of a #ClutterActor.
9337 * This function tries to "do what you mean", by returning the
9338 * correct value depending on the actor's state.
9340 * If the actor has a valid allocation, this function will return
9341 * the Y coordinate of the origin of the allocation box.
9343 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9344 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9345 * function will return that coordinate.
9347 * If both the allocation and a fixed position are missing, this function
9350 * Return value: the Y coordinate, in pixels, ignoring any
9351 * transformation (i.e. scaling, rotation)
9354 clutter_actor_get_y (ClutterActor *self)
9356 ClutterActorPrivate *priv;
9358 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9362 if (priv->needs_allocation)
9364 if (priv->position_set)
9366 const ClutterLayoutInfo *info;
9368 info = _clutter_actor_get_layout_info_or_defaults (self);
9370 return info->fixed_y;
9376 return priv->allocation.y1;
9380 * clutter_actor_set_scale:
9381 * @self: A #ClutterActor
9382 * @scale_x: double factor to scale actor by horizontally.
9383 * @scale_y: double factor to scale actor by vertically.
9385 * Scales an actor with the given factors. The scaling is relative to
9386 * the scale center and the anchor point. The scale center is
9387 * unchanged by this function and defaults to 0,0.
9389 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9395 clutter_actor_set_scale (ClutterActor *self,
9399 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9401 g_object_freeze_notify (G_OBJECT (self));
9403 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9404 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9406 g_object_thaw_notify (G_OBJECT (self));
9410 * clutter_actor_set_scale_full:
9411 * @self: A #ClutterActor
9412 * @scale_x: double factor to scale actor by horizontally.
9413 * @scale_y: double factor to scale actor by vertically.
9414 * @center_x: X coordinate of the center of the scale.
9415 * @center_y: Y coordinate of the center of the scale
9417 * Scales an actor with the given factors around the given center
9418 * point. The center point is specified in pixels relative to the
9419 * anchor point (usually the top left corner of the actor).
9421 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9427 clutter_actor_set_scale_full (ClutterActor *self,
9433 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9435 g_object_freeze_notify (G_OBJECT (self));
9437 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9438 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9439 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9440 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9442 g_object_thaw_notify (G_OBJECT (self));
9446 * clutter_actor_set_scale_with_gravity:
9447 * @self: A #ClutterActor
9448 * @scale_x: double factor to scale actor by horizontally.
9449 * @scale_y: double factor to scale actor by vertically.
9450 * @gravity: the location of the scale center expressed as a compass
9453 * Scales an actor with the given factors around the given
9454 * center point. The center point is specified as one of the compass
9455 * directions in #ClutterGravity. For example, setting it to north
9456 * will cause the top of the actor to remain unchanged and the rest of
9457 * the actor to expand left, right and downwards.
9459 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9465 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9468 ClutterGravity gravity)
9470 ClutterTransformInfo *info;
9473 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9475 obj = G_OBJECT (self);
9477 g_object_freeze_notify (obj);
9479 info = _clutter_actor_get_transform_info (self);
9480 info->scale_x = scale_x;
9481 info->scale_y = scale_y;
9483 if (gravity == CLUTTER_GRAVITY_NONE)
9484 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9486 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9488 self->priv->transform_valid = FALSE;
9490 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9491 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9492 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9493 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9494 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9496 clutter_actor_queue_redraw (self);
9498 g_object_thaw_notify (obj);
9502 * clutter_actor_get_scale:
9503 * @self: A #ClutterActor
9504 * @scale_x: (out) (allow-none): Location to store horizonal
9505 * scale factor, or %NULL.
9506 * @scale_y: (out) (allow-none): Location to store vertical
9507 * scale factor, or %NULL.
9509 * Retrieves an actors scale factors.
9514 clutter_actor_get_scale (ClutterActor *self,
9518 const ClutterTransformInfo *info;
9520 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9522 info = _clutter_actor_get_transform_info_or_defaults (self);
9525 *scale_x = info->scale_x;
9528 *scale_y = info->scale_y;
9532 * clutter_actor_get_scale_center:
9533 * @self: A #ClutterActor
9534 * @center_x: (out) (allow-none): Location to store the X position
9535 * of the scale center, or %NULL.
9536 * @center_y: (out) (allow-none): Location to store the Y position
9537 * of the scale center, or %NULL.
9539 * Retrieves the scale center coordinate in pixels relative to the top
9540 * left corner of the actor. If the scale center was specified using a
9541 * #ClutterGravity this will calculate the pixel offset using the
9542 * current size of the actor.
9547 clutter_actor_get_scale_center (ClutterActor *self,
9551 const ClutterTransformInfo *info;
9553 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9555 info = _clutter_actor_get_transform_info_or_defaults (self);
9557 clutter_anchor_coord_get_units (self, &info->scale_center,
9564 * clutter_actor_get_scale_gravity:
9565 * @self: A #ClutterActor
9567 * Retrieves the scale center as a compass direction. If the scale
9568 * center was specified in pixels or units this will return
9569 * %CLUTTER_GRAVITY_NONE.
9571 * Return value: the scale gravity
9576 clutter_actor_get_scale_gravity (ClutterActor *self)
9578 const ClutterTransformInfo *info;
9580 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9582 info = _clutter_actor_get_transform_info_or_defaults (self);
9584 return clutter_anchor_coord_get_gravity (&info->scale_center);
9588 clutter_actor_set_opacity_internal (ClutterActor *self,
9591 ClutterActorPrivate *priv = self->priv;
9593 if (priv->opacity != opacity)
9595 priv->opacity = opacity;
9597 /* Queue a redraw from the flatten effect so that it can use
9598 its cached image if available instead of having to redraw the
9599 actual actor. If it doesn't end up using the FBO then the
9600 effect is still able to continue the paint anyway. If there
9601 is no flatten effect yet then this is equivalent to queueing
9603 _clutter_actor_queue_redraw_full (self,
9606 priv->flatten_effect);
9608 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9613 * clutter_actor_set_opacity:
9614 * @self: A #ClutterActor
9615 * @opacity: New opacity value for the actor.
9617 * Sets the actor's opacity, with zero being completely transparent and
9618 * 255 (0xff) being fully opaque.
9620 * The #ClutterActor:opacity property is animatable.
9623 clutter_actor_set_opacity (ClutterActor *self,
9626 ClutterActorPrivate *priv;
9628 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9632 if (clutter_actor_get_easing_duration (self) != 0)
9634 ClutterTransition *transition;
9636 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9637 if (transition == NULL)
9639 transition = _clutter_actor_create_transition (self,
9640 obj_props[PROP_OPACITY],
9643 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9646 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9648 clutter_actor_queue_redraw (self);
9651 clutter_actor_set_opacity_internal (self, opacity);
9655 * clutter_actor_get_paint_opacity_internal:
9656 * @self: a #ClutterActor
9658 * Retrieves the absolute opacity of the actor, as it appears on the stage
9660 * This function does not do type checks
9662 * Return value: the absolute opacity of the actor
9665 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9667 ClutterActorPrivate *priv = self->priv;
9668 ClutterActor *parent;
9670 /* override the top-level opacity to always be 255; even in
9671 * case of ClutterStage:use-alpha being TRUE we want the rest
9672 * of the scene to be painted
9674 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9677 if (priv->opacity_override >= 0)
9678 return priv->opacity_override;
9680 parent = priv->parent;
9682 /* Factor in the actual actors opacity with parents */
9685 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9687 if (opacity != 0xff)
9688 return (opacity * priv->opacity) / 0xff;
9691 return priv->opacity;
9696 * clutter_actor_get_paint_opacity:
9697 * @self: A #ClutterActor
9699 * Retrieves the absolute opacity of the actor, as it appears on the stage.
9701 * This function traverses the hierarchy chain and composites the opacity of
9702 * the actor with that of its parents.
9704 * This function is intended for subclasses to use in the paint virtual
9705 * function, to paint themselves with the correct opacity.
9707 * Return value: The actor opacity value.
9712 clutter_actor_get_paint_opacity (ClutterActor *self)
9714 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9716 return clutter_actor_get_paint_opacity_internal (self);
9720 * clutter_actor_get_opacity:
9721 * @self: a #ClutterActor
9723 * Retrieves the opacity value of an actor, as set by
9724 * clutter_actor_set_opacity().
9726 * For retrieving the absolute opacity of the actor inside a paint
9727 * virtual function, see clutter_actor_get_paint_opacity().
9729 * Return value: the opacity of the actor
9732 clutter_actor_get_opacity (ClutterActor *self)
9734 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9736 return self->priv->opacity;
9740 * clutter_actor_set_offscreen_redirect:
9741 * @self: A #ClutterActor
9742 * @redirect: New offscreen redirect flags for the actor.
9744 * Defines the circumstances where the actor should be redirected into
9745 * an offscreen image. The offscreen image is used to flatten the
9746 * actor into a single image while painting for two main reasons.
9747 * Firstly, when the actor is painted a second time without any of its
9748 * contents changing it can simply repaint the cached image without
9749 * descending further down the actor hierarchy. Secondly, it will make
9750 * the opacity look correct even if there are overlapping primitives
9753 * Caching the actor could in some cases be a performance win and in
9754 * some cases be a performance lose so it is important to determine
9755 * which value is right for an actor before modifying this value. For
9756 * example, there is never any reason to flatten an actor that is just
9757 * a single texture (such as a #ClutterTexture) because it is
9758 * effectively already cached in an image so the offscreen would be
9759 * redundant. Also if the actor contains primitives that are far apart
9760 * with a large transparent area in the middle (such as a large
9761 * CluterGroup with a small actor in the top left and a small actor in
9762 * the bottom right) then the cached image will contain the entire
9763 * image of the large area and the paint will waste time blending all
9764 * of the transparent pixels in the middle.
9766 * The default method of implementing opacity on a container simply
9767 * forwards on the opacity to all of the children. If the children are
9768 * overlapping then it will appear as if they are two separate glassy
9769 * objects and there will be a break in the color where they
9770 * overlap. By redirecting to an offscreen buffer it will be as if the
9771 * two opaque objects are combined into one and then made transparent
9772 * which is usually what is expected.
9774 * The image below demonstrates the difference between redirecting and
9775 * not. The image shows two Clutter groups, each containing a red and
9776 * a green rectangle which overlap. The opacity on the group is set to
9777 * 128 (which is 50%). When the offscreen redirect is not used, the
9778 * red rectangle can be seen through the blue rectangle as if the two
9779 * rectangles were separately transparent. When the redirect is used
9780 * the group as a whole is transparent instead so the red rectangle is
9781 * not visible where they overlap.
9783 * <figure id="offscreen-redirect">
9784 * <title>Sample of using an offscreen redirect for transparency</title>
9785 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
9788 * The default value for this property is 0, so we effectively will
9789 * never redirect an actor offscreen by default. This means that there
9790 * are times that transparent actors may look glassy as described
9791 * above. The reason this is the default is because there is a
9792 * performance trade off between quality and performance here. In many
9793 * cases the default form of glassy opacity looks good enough, but if
9794 * it's not you will need to set the
9795 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9796 * redirection for opacity.
9798 * Custom actors that don't contain any overlapping primitives are
9799 * recommended to override the has_overlaps() virtual to return %FALSE
9800 * for maximum efficiency.
9805 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9806 ClutterOffscreenRedirect redirect)
9808 ClutterActorPrivate *priv;
9810 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9814 if (priv->offscreen_redirect != redirect)
9816 priv->offscreen_redirect = redirect;
9818 /* Queue a redraw from the effect so that it can use its cached
9819 image if available instead of having to redraw the actual
9820 actor. If it doesn't end up using the FBO then the effect is
9821 still able to continue the paint anyway. If there is no
9822 effect then this is equivalent to queuing a full redraw */
9823 _clutter_actor_queue_redraw_full (self,
9826 priv->flatten_effect);
9828 g_object_notify_by_pspec (G_OBJECT (self),
9829 obj_props[PROP_OFFSCREEN_REDIRECT]);
9834 * clutter_actor_get_offscreen_redirect:
9835 * @self: a #ClutterActor
9837 * Retrieves whether to redirect the actor to an offscreen buffer, as
9838 * set by clutter_actor_set_offscreen_redirect().
9840 * Return value: the value of the offscreen-redirect property of the actor
9844 ClutterOffscreenRedirect
9845 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9847 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9849 return self->priv->offscreen_redirect;
9853 * clutter_actor_set_name:
9854 * @self: A #ClutterActor
9855 * @name: Textual tag to apply to actor
9857 * Sets the given name to @self. The name can be used to identify
9861 clutter_actor_set_name (ClutterActor *self,
9864 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9866 g_free (self->priv->name);
9867 self->priv->name = g_strdup (name);
9869 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9873 * clutter_actor_get_name:
9874 * @self: A #ClutterActor
9876 * Retrieves the name of @self.
9878 * Return value: the name of the actor, or %NULL. The returned string is
9879 * owned by the actor and should not be modified or freed.
9882 clutter_actor_get_name (ClutterActor *self)
9884 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9886 return self->priv->name;
9890 * clutter_actor_get_gid:
9891 * @self: A #ClutterActor
9893 * Retrieves the unique id for @self.
9895 * Return value: Globally unique value for this object instance.
9899 * Deprecated: 1.8: The id is not used any longer.
9902 clutter_actor_get_gid (ClutterActor *self)
9904 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9906 return self->priv->id;
9910 clutter_actor_set_depth_internal (ClutterActor *self,
9913 ClutterTransformInfo *info;
9915 info = _clutter_actor_get_transform_info (self);
9917 if (info->depth != depth)
9919 /* Sets Z value - XXX 2.0: should we invert? */
9920 info->depth = depth;
9922 self->priv->transform_valid = FALSE;
9924 /* FIXME - remove this crap; sadly, there are still containers
9925 * in Clutter that depend on this utter brain damage
9927 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9929 clutter_actor_queue_redraw (self);
9931 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9936 * clutter_actor_set_depth:
9937 * @self: a #ClutterActor
9940 * Sets the Z coordinate of @self to @depth.
9942 * The unit used by @depth is dependant on the perspective setup. See
9943 * also clutter_stage_set_perspective().
9946 clutter_actor_set_depth (ClutterActor *self,
9949 const ClutterTransformInfo *tinfo;
9951 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9953 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
9955 if (clutter_actor_get_easing_duration (self) != 0)
9957 ClutterTransition *transition;
9959 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
9960 if (transition == NULL)
9962 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
9965 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9968 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
9970 clutter_actor_queue_redraw (self);
9973 clutter_actor_set_depth_internal (self, depth);
9977 * clutter_actor_get_depth:
9978 * @self: a #ClutterActor
9980 * Retrieves the depth of @self.
9982 * Return value: the depth of the actor
9985 clutter_actor_get_depth (ClutterActor *self)
9987 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
9989 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
9993 * clutter_actor_set_rotation:
9994 * @self: a #ClutterActor
9995 * @axis: the axis of rotation
9996 * @angle: the angle of rotation
9997 * @x: X coordinate of the rotation center
9998 * @y: Y coordinate of the rotation center
9999 * @z: Z coordinate of the rotation center
10001 * Sets the rotation angle of @self around the given axis.
10003 * The rotation center coordinates used depend on the value of @axis:
10005 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10006 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10007 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10010 * The rotation coordinates are relative to the anchor point of the
10011 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10012 * point is set, the upper left corner is assumed as the origin.
10017 clutter_actor_set_rotation (ClutterActor *self,
10018 ClutterRotateAxis axis,
10026 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10032 g_object_freeze_notify (G_OBJECT (self));
10034 clutter_actor_set_rotation_angle (self, axis, angle);
10035 clutter_actor_set_rotation_center_internal (self, axis, &v);
10037 g_object_thaw_notify (G_OBJECT (self));
10041 * clutter_actor_set_z_rotation_from_gravity:
10042 * @self: a #ClutterActor
10043 * @angle: the angle of rotation
10044 * @gravity: the center point of the rotation
10046 * Sets the rotation angle of @self around the Z axis using the center
10047 * point specified as a compass point. For example to rotate such that
10048 * the center of the actor remains static you can use
10049 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10050 * will move accordingly.
10055 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10057 ClutterGravity gravity)
10059 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10061 if (gravity == CLUTTER_GRAVITY_NONE)
10062 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10065 GObject *obj = G_OBJECT (self);
10066 ClutterTransformInfo *info;
10068 info = _clutter_actor_get_transform_info (self);
10070 g_object_freeze_notify (obj);
10072 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10074 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10075 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10076 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10078 g_object_thaw_notify (obj);
10083 * clutter_actor_get_rotation:
10084 * @self: a #ClutterActor
10085 * @axis: the axis of rotation
10086 * @x: (out): return value for the X coordinate of the center of rotation
10087 * @y: (out): return value for the Y coordinate of the center of rotation
10088 * @z: (out): return value for the Z coordinate of the center of rotation
10090 * Retrieves the angle and center of rotation on the given axis,
10091 * set using clutter_actor_set_rotation().
10093 * Return value: the angle of rotation
10098 clutter_actor_get_rotation (ClutterActor *self,
10099 ClutterRotateAxis axis,
10104 const ClutterTransformInfo *info;
10105 const AnchorCoord *anchor_coord;
10106 gdouble retval = 0;
10108 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10110 info = _clutter_actor_get_transform_info_or_defaults (self);
10114 case CLUTTER_X_AXIS:
10115 anchor_coord = &info->rx_center;
10116 retval = info->rx_angle;
10119 case CLUTTER_Y_AXIS:
10120 anchor_coord = &info->ry_center;
10121 retval = info->ry_angle;
10124 case CLUTTER_Z_AXIS:
10125 anchor_coord = &info->rz_center;
10126 retval = info->rz_angle;
10130 anchor_coord = NULL;
10135 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10141 * clutter_actor_get_z_rotation_gravity:
10142 * @self: A #ClutterActor
10144 * Retrieves the center for the rotation around the Z axis as a
10145 * compass direction. If the center was specified in pixels or units
10146 * this will return %CLUTTER_GRAVITY_NONE.
10148 * Return value: the Z rotation center
10153 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10155 const ClutterTransformInfo *info;
10157 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10159 info = _clutter_actor_get_transform_info_or_defaults (self);
10161 return clutter_anchor_coord_get_gravity (&info->rz_center);
10165 * clutter_actor_set_clip:
10166 * @self: A #ClutterActor
10167 * @xoff: X offset of the clip rectangle
10168 * @yoff: Y offset of the clip rectangle
10169 * @width: Width of the clip rectangle
10170 * @height: Height of the clip rectangle
10172 * Sets clip area for @self. The clip area is always computed from the
10173 * upper left corner of the actor, even if the anchor point is set
10179 clutter_actor_set_clip (ClutterActor *self,
10185 ClutterActorPrivate *priv;
10187 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10191 if (priv->has_clip &&
10192 priv->clip.x == xoff &&
10193 priv->clip.y == yoff &&
10194 priv->clip.width == width &&
10195 priv->clip.height == height)
10198 priv->clip.x = xoff;
10199 priv->clip.y = yoff;
10200 priv->clip.width = width;
10201 priv->clip.height = height;
10203 priv->has_clip = TRUE;
10205 clutter_actor_queue_redraw (self);
10207 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10208 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10212 * clutter_actor_remove_clip:
10213 * @self: A #ClutterActor
10215 * Removes clip area from @self.
10218 clutter_actor_remove_clip (ClutterActor *self)
10220 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10222 if (!self->priv->has_clip)
10225 self->priv->has_clip = FALSE;
10227 clutter_actor_queue_redraw (self);
10229 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10233 * clutter_actor_has_clip:
10234 * @self: a #ClutterActor
10236 * Determines whether the actor has a clip area set or not.
10238 * Return value: %TRUE if the actor has a clip area set.
10243 clutter_actor_has_clip (ClutterActor *self)
10245 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10247 return self->priv->has_clip;
10251 * clutter_actor_get_clip:
10252 * @self: a #ClutterActor
10253 * @xoff: (out) (allow-none): return location for the X offset of
10254 * the clip rectangle, or %NULL
10255 * @yoff: (out) (allow-none): return location for the Y offset of
10256 * the clip rectangle, or %NULL
10257 * @width: (out) (allow-none): return location for the width of
10258 * the clip rectangle, or %NULL
10259 * @height: (out) (allow-none): return location for the height of
10260 * the clip rectangle, or %NULL
10262 * Gets the clip area for @self, if any is set
10267 clutter_actor_get_clip (ClutterActor *self,
10273 ClutterActorPrivate *priv;
10275 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10279 if (!priv->has_clip)
10283 *xoff = priv->clip.x;
10286 *yoff = priv->clip.y;
10289 *width = priv->clip.width;
10291 if (height != NULL)
10292 *height = priv->clip.height;
10296 * clutter_actor_get_children:
10297 * @self: a #ClutterActor
10299 * Retrieves the list of children of @self.
10301 * Return value: (transfer container) (element-type ClutterActor): A newly
10302 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10308 clutter_actor_get_children (ClutterActor *self)
10310 ClutterActor *iter;
10313 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10315 /* we walk the list backward so that we can use prepend(),
10318 for (iter = self->priv->last_child, res = NULL;
10320 iter = iter->priv->prev_sibling)
10322 res = g_list_prepend (res, iter);
10329 * insert_child_at_depth:
10330 * @self: a #ClutterActor
10331 * @child: a #ClutterActor
10333 * Inserts @child inside the list of children held by @self, using
10334 * the depth as the insertion criteria.
10336 * This sadly makes the insertion not O(1), but we can keep the
10337 * list sorted so that the painters algorithm we use for painting
10338 * the children will work correctly.
10341 insert_child_at_depth (ClutterActor *self,
10342 ClutterActor *child,
10343 gpointer dummy G_GNUC_UNUSED)
10345 ClutterActor *iter;
10348 child->priv->parent = self;
10351 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10353 /* special-case the first child */
10354 if (self->priv->n_children == 0)
10356 self->priv->first_child = child;
10357 self->priv->last_child = child;
10359 child->priv->next_sibling = NULL;
10360 child->priv->prev_sibling = NULL;
10365 /* Find the right place to insert the child so that it will still be
10366 sorted and the child will be after all of the actors at the same
10368 for (iter = self->priv->first_child;
10370 iter = iter->priv->next_sibling)
10375 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10377 if (iter_depth > child_depth)
10383 ClutterActor *tmp = iter->priv->prev_sibling;
10386 tmp->priv->next_sibling = child;
10388 /* Insert the node before the found one */
10389 child->priv->prev_sibling = iter->priv->prev_sibling;
10390 child->priv->next_sibling = iter;
10391 iter->priv->prev_sibling = child;
10395 ClutterActor *tmp = self->priv->last_child;
10398 tmp->priv->next_sibling = child;
10400 /* insert the node at the end of the list */
10401 child->priv->prev_sibling = self->priv->last_child;
10402 child->priv->next_sibling = NULL;
10405 if (child->priv->prev_sibling == NULL)
10406 self->priv->first_child = child;
10408 if (child->priv->next_sibling == NULL)
10409 self->priv->last_child = child;
10413 insert_child_at_index (ClutterActor *self,
10414 ClutterActor *child,
10417 gint index_ = GPOINTER_TO_INT (data_);
10419 child->priv->parent = self;
10423 ClutterActor *tmp = self->priv->first_child;
10426 tmp->priv->prev_sibling = child;
10428 child->priv->prev_sibling = NULL;
10429 child->priv->next_sibling = tmp;
10431 else if (index_ < 0 || index_ >= self->priv->n_children)
10433 ClutterActor *tmp = self->priv->last_child;
10436 tmp->priv->next_sibling = child;
10438 child->priv->prev_sibling = tmp;
10439 child->priv->next_sibling = NULL;
10443 ClutterActor *iter;
10446 for (iter = self->priv->first_child, i = 0;
10448 iter = iter->priv->next_sibling, i += 1)
10452 ClutterActor *tmp = iter->priv->prev_sibling;
10454 child->priv->prev_sibling = tmp;
10455 child->priv->next_sibling = iter;
10457 iter->priv->prev_sibling = child;
10460 tmp->priv->next_sibling = child;
10467 if (child->priv->prev_sibling == NULL)
10468 self->priv->first_child = child;
10470 if (child->priv->next_sibling == NULL)
10471 self->priv->last_child = child;
10475 insert_child_above (ClutterActor *self,
10476 ClutterActor *child,
10479 ClutterActor *sibling = data;
10481 child->priv->parent = self;
10483 if (sibling == NULL)
10484 sibling = self->priv->last_child;
10486 child->priv->prev_sibling = sibling;
10488 if (sibling != NULL)
10490 ClutterActor *tmp = sibling->priv->next_sibling;
10492 child->priv->next_sibling = tmp;
10495 tmp->priv->prev_sibling = child;
10497 sibling->priv->next_sibling = child;
10500 child->priv->next_sibling = NULL;
10502 if (child->priv->prev_sibling == NULL)
10503 self->priv->first_child = child;
10505 if (child->priv->next_sibling == NULL)
10506 self->priv->last_child = child;
10510 insert_child_below (ClutterActor *self,
10511 ClutterActor *child,
10514 ClutterActor *sibling = data;
10516 child->priv->parent = self;
10518 if (sibling == NULL)
10519 sibling = self->priv->first_child;
10521 child->priv->next_sibling = sibling;
10523 if (sibling != NULL)
10525 ClutterActor *tmp = sibling->priv->prev_sibling;
10527 child->priv->prev_sibling = tmp;
10530 tmp->priv->next_sibling = child;
10532 sibling->priv->prev_sibling = child;
10535 child->priv->prev_sibling = NULL;
10537 if (child->priv->prev_sibling == NULL)
10538 self->priv->first_child = child;
10540 if (child->priv->next_sibling == NULL)
10541 self->priv->last_child = child;
10544 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10545 ClutterActor *child,
10549 ADD_CHILD_CREATE_META = 1 << 0,
10550 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10551 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10552 ADD_CHILD_CHECK_STATE = 1 << 3,
10553 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10555 /* default flags for public API */
10556 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10557 ADD_CHILD_EMIT_PARENT_SET |
10558 ADD_CHILD_EMIT_ACTOR_ADDED |
10559 ADD_CHILD_CHECK_STATE |
10560 ADD_CHILD_NOTIFY_FIRST_LAST,
10562 /* flags for legacy/deprecated API */
10563 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10564 ADD_CHILD_CHECK_STATE |
10565 ADD_CHILD_NOTIFY_FIRST_LAST
10566 } ClutterActorAddChildFlags;
10569 * clutter_actor_add_child_internal:
10570 * @self: a #ClutterActor
10571 * @child: a #ClutterActor
10572 * @flags: control flags for actions
10573 * @add_func: delegate function
10574 * @data: (closure): data to pass to @add_func
10576 * Adds @child to the list of children of @self.
10578 * The actual insertion inside the list is delegated to @add_func: this
10579 * function will just set up the state, perform basic checks, and emit
10582 * The @flags argument is used to perform additional operations.
10585 clutter_actor_add_child_internal (ClutterActor *self,
10586 ClutterActor *child,
10587 ClutterActorAddChildFlags flags,
10588 ClutterActorAddChildFunc add_func,
10591 ClutterTextDirection text_dir;
10592 gboolean create_meta;
10593 gboolean emit_parent_set, emit_actor_added;
10594 gboolean check_state;
10595 gboolean notify_first_last;
10596 ClutterActor *old_first_child, *old_last_child;
10598 if (child->priv->parent != NULL)
10600 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10601 "use clutter_actor_remove_child() first.",
10602 _clutter_actor_get_debug_name (child),
10603 _clutter_actor_get_debug_name (child->priv->parent));
10607 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10609 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10610 "a child of another actor.",
10611 _clutter_actor_get_debug_name (child));
10616 /* XXX - this check disallows calling methods that change the stacking
10617 * order within the destruction sequence, by triggering a critical
10618 * warning first, and leaving the actor in an undefined state, which
10619 * then ends up being caught by an assertion.
10621 * the reproducible sequence is:
10623 * - actor gets destroyed;
10624 * - another actor, linked to the first, will try to change the
10625 * stacking order of the first actor;
10626 * - changing the stacking order is a composite operation composed
10627 * by the following steps:
10628 * 1. ref() the child;
10629 * 2. remove_child_internal(), which removes the reference;
10630 * 3. add_child_internal(), which adds a reference;
10631 * - the state of the actor is not changed between (2) and (3), as
10632 * it could be an expensive recomputation;
10633 * - if (3) bails out, then the actor is in an undefined state, but
10635 * - the destruction sequence terminates, but the actor is unparented
10636 * while its state indicates being parented instead.
10637 * - assertion failure.
10639 * the obvious fix would be to decompose each set_child_*_sibling()
10640 * method into proper remove_child()/add_child(), with state validation;
10641 * this may cause excessive work, though, and trigger a cascade of other
10642 * bugs in code that assumes that a change in the stacking order is an
10643 * atomic operation.
10645 * another potential fix is to just remove this check here, and let
10646 * code doing stacking order changes inside the destruction sequence
10647 * of an actor continue doing the work.
10649 * the third fix is to silently bail out early from every
10650 * set_child_*_sibling() and set_child_at_index() method, and avoid
10653 * I have a preference for the second solution, since it involves the
10654 * least amount of work, and the least amount of code duplication.
10656 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10658 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10660 g_warning ("The actor '%s' is currently being destroyed, and "
10661 "cannot be added as a child of another actor.",
10662 _clutter_actor_get_debug_name (child));
10667 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10668 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10669 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10670 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10671 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10673 old_first_child = self->priv->first_child;
10674 old_last_child = self->priv->last_child;
10676 g_object_freeze_notify (G_OBJECT (self));
10679 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10681 g_object_ref_sink (child);
10682 child->priv->parent = NULL;
10683 child->priv->next_sibling = NULL;
10684 child->priv->prev_sibling = NULL;
10686 /* delegate the actual insertion */
10687 add_func (self, child, data);
10689 g_assert (child->priv->parent == self);
10691 self->priv->n_children += 1;
10693 self->priv->age += 1;
10695 /* if push_internal() has been called then we automatically set
10696 * the flag on the actor
10698 if (self->priv->internal_child)
10699 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10701 /* clutter_actor_reparent() will emit ::parent-set for us */
10702 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10703 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10707 /* If parent is mapped or realized, we need to also be mapped or
10708 * realized once we're inside the parent.
10710 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10712 /* propagate the parent's text direction to the child */
10713 text_dir = clutter_actor_get_text_direction (self);
10714 clutter_actor_set_text_direction (child, text_dir);
10717 if (child->priv->show_on_set_parent)
10718 clutter_actor_show (child);
10720 if (CLUTTER_ACTOR_IS_MAPPED (child))
10721 clutter_actor_queue_redraw (child);
10723 /* maintain the invariant that if an actor needs layout,
10724 * its parents do as well
10726 if (child->priv->needs_width_request ||
10727 child->priv->needs_height_request ||
10728 child->priv->needs_allocation)
10730 /* we work around the short-circuiting we do
10731 * in clutter_actor_queue_relayout() since we
10732 * want to force a relayout
10734 child->priv->needs_width_request = TRUE;
10735 child->priv->needs_height_request = TRUE;
10736 child->priv->needs_allocation = TRUE;
10738 clutter_actor_queue_relayout (child->priv->parent);
10741 if (emit_actor_added)
10742 g_signal_emit_by_name (self, "actor-added", child);
10744 if (notify_first_last)
10746 if (old_first_child != self->priv->first_child)
10747 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10749 if (old_last_child != self->priv->last_child)
10750 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10753 g_object_thaw_notify (G_OBJECT (self));
10757 * clutter_actor_add_child:
10758 * @self: a #ClutterActor
10759 * @child: a #ClutterActor
10761 * Adds @child to the children of @self.
10763 * This function will acquire a reference on @child that will only
10764 * be released when calling clutter_actor_remove_child().
10766 * This function will take into consideration the #ClutterActor:depth
10767 * of @child, and will keep the list of children sorted.
10769 * This function will emit the #ClutterContainer::actor-added signal
10775 clutter_actor_add_child (ClutterActor *self,
10776 ClutterActor *child)
10778 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10779 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10780 g_return_if_fail (self != child);
10781 g_return_if_fail (child->priv->parent == NULL);
10783 clutter_actor_add_child_internal (self, child,
10784 ADD_CHILD_DEFAULT_FLAGS,
10785 insert_child_at_depth,
10790 * clutter_actor_insert_child_at_index:
10791 * @self: a #ClutterActor
10792 * @child: a #ClutterActor
10793 * @index_: the index
10795 * Inserts @child into the list of children of @self, using the
10796 * given @index_. If @index_ is greater than the number of children
10797 * in @self, or is less than 0, then the new child is added at the end.
10799 * This function will acquire a reference on @child that will only
10800 * be released when calling clutter_actor_remove_child().
10802 * This function will not take into consideration the #ClutterActor:depth
10805 * This function will emit the #ClutterContainer::actor-added signal
10811 clutter_actor_insert_child_at_index (ClutterActor *self,
10812 ClutterActor *child,
10815 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10816 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10817 g_return_if_fail (self != child);
10818 g_return_if_fail (child->priv->parent == NULL);
10820 clutter_actor_add_child_internal (self, child,
10821 ADD_CHILD_DEFAULT_FLAGS,
10822 insert_child_at_index,
10823 GINT_TO_POINTER (index_));
10827 * clutter_actor_insert_child_above:
10828 * @self: a #ClutterActor
10829 * @child: a #ClutterActor
10830 * @sibling: (allow-none): a child of @self, or %NULL
10832 * Inserts @child into the list of children of @self, above another
10833 * child of @self or, if @sibling is %NULL, above all the children
10836 * This function will acquire a reference on @child that will only
10837 * be released when calling clutter_actor_remove_child().
10839 * This function will not take into consideration the #ClutterActor:depth
10842 * This function will emit the #ClutterContainer::actor-added signal
10848 clutter_actor_insert_child_above (ClutterActor *self,
10849 ClutterActor *child,
10850 ClutterActor *sibling)
10852 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10853 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10854 g_return_if_fail (self != child);
10855 g_return_if_fail (child != sibling);
10856 g_return_if_fail (child->priv->parent == NULL);
10857 g_return_if_fail (sibling == NULL ||
10858 (CLUTTER_IS_ACTOR (sibling) &&
10859 sibling->priv->parent == self));
10861 clutter_actor_add_child_internal (self, child,
10862 ADD_CHILD_DEFAULT_FLAGS,
10863 insert_child_above,
10868 * clutter_actor_insert_child_below:
10869 * @self: a #ClutterActor
10870 * @child: a #ClutterActor
10871 * @sibling: (allow-none): a child of @self, or %NULL
10873 * Inserts @child into the list of children of @self, below another
10874 * child of @self or, if @sibling is %NULL, below all the children
10877 * This function will acquire a reference on @child that will only
10878 * be released when calling clutter_actor_remove_child().
10880 * This function will not take into consideration the #ClutterActor:depth
10883 * This function will emit the #ClutterContainer::actor-added signal
10889 clutter_actor_insert_child_below (ClutterActor *self,
10890 ClutterActor *child,
10891 ClutterActor *sibling)
10893 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10894 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10895 g_return_if_fail (self != child);
10896 g_return_if_fail (child != sibling);
10897 g_return_if_fail (child->priv->parent == NULL);
10898 g_return_if_fail (sibling == NULL ||
10899 (CLUTTER_IS_ACTOR (sibling) &&
10900 sibling->priv->parent == self));
10902 clutter_actor_add_child_internal (self, child,
10903 ADD_CHILD_DEFAULT_FLAGS,
10904 insert_child_below,
10909 * clutter_actor_set_parent:
10910 * @self: A #ClutterActor
10911 * @parent: A new #ClutterActor parent
10913 * Sets the parent of @self to @parent.
10915 * This function will result in @parent acquiring a reference on @self,
10916 * eventually by sinking its floating reference first. The reference
10917 * will be released by clutter_actor_unparent().
10919 * This function should only be called by legacy #ClutterActor<!-- -->s
10920 * implementing the #ClutterContainer interface.
10922 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10925 clutter_actor_set_parent (ClutterActor *self,
10926 ClutterActor *parent)
10928 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10929 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10930 g_return_if_fail (self != parent);
10931 g_return_if_fail (self->priv->parent == NULL);
10933 /* as this function will be called inside ClutterContainer::add
10934 * implementations or when building up a composite actor, we have
10935 * to preserve the old behaviour, and not create child meta or
10936 * emit the ::actor-added signal, to avoid recursion or double
10939 clutter_actor_add_child_internal (parent, self,
10940 ADD_CHILD_LEGACY_FLAGS,
10941 insert_child_at_depth,
10946 * clutter_actor_get_parent:
10947 * @self: A #ClutterActor
10949 * Retrieves the parent of @self.
10951 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10952 * if no parent is set
10955 clutter_actor_get_parent (ClutterActor *self)
10957 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10959 return self->priv->parent;
10963 * clutter_actor_get_paint_visibility:
10964 * @self: A #ClutterActor
10966 * Retrieves the 'paint' visibility of an actor recursively checking for non
10969 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
10971 * Return Value: %TRUE if the actor is visibile and will be painted.
10976 clutter_actor_get_paint_visibility (ClutterActor *actor)
10978 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
10980 return CLUTTER_ACTOR_IS_MAPPED (actor);
10984 * clutter_actor_remove_child:
10985 * @self: a #ClutterActor
10986 * @child: a #ClutterActor
10988 * Removes @child from the children of @self.
10990 * This function will release the reference added by
10991 * clutter_actor_add_child(), so if you want to keep using @child
10992 * you will have to acquire a referenced on it before calling this
10995 * This function will emit the #ClutterContainer::actor-removed
11001 clutter_actor_remove_child (ClutterActor *self,
11002 ClutterActor *child)
11004 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11005 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11006 g_return_if_fail (self != child);
11007 g_return_if_fail (child->priv->parent != NULL);
11008 g_return_if_fail (child->priv->parent == self);
11010 clutter_actor_remove_child_internal (self, child,
11011 REMOVE_CHILD_DEFAULT_FLAGS);
11015 * clutter_actor_remove_all_children:
11016 * @self: a #ClutterActor
11018 * Removes all children of @self.
11020 * This function releases the reference added by inserting a child actor
11021 * in the list of children of @self.
11023 * If the reference count of a child drops to zero, the child will be
11024 * destroyed. If you want to ensure the destruction of all the children
11025 * of @self, use clutter_actor_destroy_all_children().
11030 clutter_actor_remove_all_children (ClutterActor *self)
11032 ClutterActorIter iter;
11034 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11036 if (self->priv->n_children == 0)
11039 g_object_freeze_notify (G_OBJECT (self));
11041 clutter_actor_iter_init (&iter, self);
11042 while (clutter_actor_iter_next (&iter, NULL))
11043 clutter_actor_iter_remove (&iter);
11045 g_object_thaw_notify (G_OBJECT (self));
11048 g_assert (self->priv->first_child == NULL);
11049 g_assert (self->priv->last_child == NULL);
11050 g_assert (self->priv->n_children == 0);
11054 * clutter_actor_destroy_all_children:
11055 * @self: a #ClutterActor
11057 * Destroys all children of @self.
11059 * This function releases the reference added by inserting a child
11060 * actor in the list of children of @self, and ensures that the
11061 * #ClutterActor::destroy signal is emitted on each child of the
11064 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11065 * when its reference count drops to 0; the default handler of the
11066 * #ClutterActor::destroy signal will destroy all the children of an
11067 * actor. This function ensures that all children are destroyed, instead
11068 * of just removed from @self, unlike clutter_actor_remove_all_children()
11069 * which will merely release the reference and remove each child.
11071 * Unless you acquired an additional reference on each child of @self
11072 * prior to calling clutter_actor_remove_all_children() and want to reuse
11073 * the actors, you should use clutter_actor_destroy_all_children() in
11074 * order to make sure that children are destroyed and signal handlers
11075 * are disconnected even in cases where circular references prevent this
11076 * from automatically happening through reference counting alone.
11081 clutter_actor_destroy_all_children (ClutterActor *self)
11083 ClutterActorIter iter;
11085 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11087 if (self->priv->n_children == 0)
11090 g_object_freeze_notify (G_OBJECT (self));
11092 clutter_actor_iter_init (&iter, self);
11093 while (clutter_actor_iter_next (&iter, NULL))
11094 clutter_actor_iter_destroy (&iter);
11096 g_object_thaw_notify (G_OBJECT (self));
11099 g_assert (self->priv->first_child == NULL);
11100 g_assert (self->priv->last_child == NULL);
11101 g_assert (self->priv->n_children == 0);
11104 typedef struct _InsertBetweenData {
11105 ClutterActor *prev_sibling;
11106 ClutterActor *next_sibling;
11107 } InsertBetweenData;
11110 insert_child_between (ClutterActor *self,
11111 ClutterActor *child,
11114 InsertBetweenData *data = data_;
11115 ClutterActor *prev_sibling = data->prev_sibling;
11116 ClutterActor *next_sibling = data->next_sibling;
11118 child->priv->parent = self;
11119 child->priv->prev_sibling = prev_sibling;
11120 child->priv->next_sibling = next_sibling;
11122 if (prev_sibling != NULL)
11123 prev_sibling->priv->next_sibling = child;
11125 if (next_sibling != NULL)
11126 next_sibling->priv->prev_sibling = child;
11128 if (child->priv->prev_sibling == NULL)
11129 self->priv->first_child = child;
11131 if (child->priv->next_sibling == NULL)
11132 self->priv->last_child = child;
11136 * clutter_actor_replace_child:
11137 * @self: a #ClutterActor
11138 * @old_child: the child of @self to replace
11139 * @new_child: the #ClutterActor to replace @old_child
11141 * Replaces @old_child with @new_child in the list of children of @self.
11146 clutter_actor_replace_child (ClutterActor *self,
11147 ClutterActor *old_child,
11148 ClutterActor *new_child)
11150 ClutterActor *prev_sibling, *next_sibling;
11151 InsertBetweenData clos;
11153 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11154 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11155 g_return_if_fail (old_child->priv->parent == self);
11156 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11157 g_return_if_fail (old_child != new_child);
11158 g_return_if_fail (new_child != self);
11159 g_return_if_fail (new_child->priv->parent == NULL);
11161 prev_sibling = old_child->priv->prev_sibling;
11162 next_sibling = old_child->priv->next_sibling;
11163 clutter_actor_remove_child_internal (self, old_child,
11164 REMOVE_CHILD_DEFAULT_FLAGS);
11166 clos.prev_sibling = prev_sibling;
11167 clos.next_sibling = next_sibling;
11168 clutter_actor_add_child_internal (self, new_child,
11169 ADD_CHILD_DEFAULT_FLAGS,
11170 insert_child_between,
11175 * clutter_actor_unparent:
11176 * @self: a #ClutterActor
11178 * Removes the parent of @self.
11180 * This will cause the parent of @self to release the reference
11181 * acquired when calling clutter_actor_set_parent(), so if you
11182 * want to keep @self you will have to acquire a reference of
11183 * your own, through g_object_ref().
11185 * This function should only be called by legacy #ClutterActor<!-- -->s
11186 * implementing the #ClutterContainer interface.
11190 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11193 clutter_actor_unparent (ClutterActor *self)
11195 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11197 if (self->priv->parent == NULL)
11200 clutter_actor_remove_child_internal (self->priv->parent, self,
11201 REMOVE_CHILD_LEGACY_FLAGS);
11205 * clutter_actor_reparent:
11206 * @self: a #ClutterActor
11207 * @new_parent: the new #ClutterActor parent
11209 * Resets the parent actor of @self.
11211 * This function is logically equivalent to calling clutter_actor_unparent()
11212 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11213 * ensures the child is not finalized when unparented, and emits the
11214 * #ClutterActor::parent-set signal only once.
11216 * In reality, calling this function is less useful than it sounds, as some
11217 * application code may rely on changes in the intermediate state between
11218 * removal and addition of the actor from its old parent to the @new_parent.
11219 * Thus, it is strongly encouraged to avoid using this function in application
11224 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11225 * clutter_actor_add_child() instead; remember to take a reference on
11226 * the actor being removed before calling clutter_actor_remove_child()
11227 * to avoid the reference count dropping to zero and the actor being
11231 clutter_actor_reparent (ClutterActor *self,
11232 ClutterActor *new_parent)
11234 ClutterActorPrivate *priv;
11236 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11237 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11238 g_return_if_fail (self != new_parent);
11240 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11242 g_warning ("Cannot set a parent on a toplevel actor");
11246 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11248 g_warning ("Cannot set a parent currently being destroyed");
11254 if (priv->parent != new_parent)
11256 ClutterActor *old_parent;
11258 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11260 old_parent = priv->parent;
11262 g_object_ref (self);
11264 if (old_parent != NULL)
11266 /* go through the Container implementation if this is a regular
11267 * child and not an internal one
11269 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11271 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11273 /* this will have to call unparent() */
11274 clutter_container_remove_actor (parent, self);
11277 clutter_actor_remove_child_internal (old_parent, self,
11278 REMOVE_CHILD_LEGACY_FLAGS);
11281 /* Note, will call set_parent() */
11282 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11283 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11285 clutter_actor_add_child_internal (new_parent, self,
11286 ADD_CHILD_LEGACY_FLAGS,
11287 insert_child_at_depth,
11290 /* we emit the ::parent-set signal once */
11291 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11293 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11295 /* the IN_REPARENT flag suspends state updates */
11296 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11298 g_object_unref (self);
11303 * clutter_actor_contains:
11304 * @self: A #ClutterActor
11305 * @descendant: A #ClutterActor, possibly contained in @self
11307 * Determines if @descendant is contained inside @self (either as an
11308 * immediate child, or as a deeper descendant). If @self and
11309 * @descendant point to the same actor then it will also return %TRUE.
11311 * Return value: whether @descendent is contained within @self
11316 clutter_actor_contains (ClutterActor *self,
11317 ClutterActor *descendant)
11319 ClutterActor *actor;
11321 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11322 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11324 for (actor = descendant; actor; actor = actor->priv->parent)
11332 * clutter_actor_set_child_above_sibling:
11333 * @self: a #ClutterActor
11334 * @child: a #ClutterActor child of @self
11335 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11337 * Sets @child to be above @sibling in the list of children of @self.
11339 * If @sibling is %NULL, @child will be the new last child of @self.
11341 * This function is logically equivalent to removing @child and using
11342 * clutter_actor_insert_child_above(), but it will not emit signals
11343 * or change state on @child.
11348 clutter_actor_set_child_above_sibling (ClutterActor *self,
11349 ClutterActor *child,
11350 ClutterActor *sibling)
11352 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11353 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11354 g_return_if_fail (child->priv->parent == self);
11355 g_return_if_fail (child != sibling);
11356 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11358 if (sibling != NULL)
11359 g_return_if_fail (sibling->priv->parent == self);
11361 /* we don't want to change the state of child, or emit signals, or
11362 * regenerate ChildMeta instances here, but we still want to follow
11363 * the correct sequence of steps encoded in remove_child() and
11364 * add_child(), so that correctness is ensured, and we only go
11365 * through one known code path.
11367 g_object_ref (child);
11368 clutter_actor_remove_child_internal (self, child, 0);
11369 clutter_actor_add_child_internal (self, child,
11370 ADD_CHILD_NOTIFY_FIRST_LAST,
11371 insert_child_above,
11374 clutter_actor_queue_relayout (self);
11378 * clutter_actor_set_child_below_sibling:
11379 * @self: a #ClutterActor
11380 * @child: a #ClutterActor child of @self
11381 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11383 * Sets @child to be below @sibling in the list of children of @self.
11385 * If @sibling is %NULL, @child will be the new first child of @self.
11387 * This function is logically equivalent to removing @self and using
11388 * clutter_actor_insert_child_below(), but it will not emit signals
11389 * or change state on @child.
11394 clutter_actor_set_child_below_sibling (ClutterActor *self,
11395 ClutterActor *child,
11396 ClutterActor *sibling)
11398 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11399 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11400 g_return_if_fail (child->priv->parent == self);
11401 g_return_if_fail (child != sibling);
11402 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11404 if (sibling != NULL)
11405 g_return_if_fail (sibling->priv->parent == self);
11407 /* see the comment in set_child_above_sibling() */
11408 g_object_ref (child);
11409 clutter_actor_remove_child_internal (self, child, 0);
11410 clutter_actor_add_child_internal (self, child,
11411 ADD_CHILD_NOTIFY_FIRST_LAST,
11412 insert_child_below,
11415 clutter_actor_queue_relayout (self);
11419 * clutter_actor_set_child_at_index:
11420 * @self: a #ClutterActor
11421 * @child: a #ClutterActor child of @self
11422 * @index_: the new index for @child
11424 * Changes the index of @child in the list of children of @self.
11426 * This function is logically equivalent to removing @child and
11427 * calling clutter_actor_insert_child_at_index(), but it will not
11428 * emit signals or change state on @child.
11433 clutter_actor_set_child_at_index (ClutterActor *self,
11434 ClutterActor *child,
11437 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11438 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11439 g_return_if_fail (child->priv->parent == self);
11440 g_return_if_fail (index_ <= self->priv->n_children);
11442 g_object_ref (child);
11443 clutter_actor_remove_child_internal (self, child, 0);
11444 clutter_actor_add_child_internal (self, child,
11445 ADD_CHILD_NOTIFY_FIRST_LAST,
11446 insert_child_at_index,
11447 GINT_TO_POINTER (index_));
11449 clutter_actor_queue_relayout (self);
11453 * clutter_actor_raise:
11454 * @self: A #ClutterActor
11455 * @below: (allow-none): A #ClutterActor to raise above.
11457 * Puts @self above @below.
11459 * Both actors must have the same parent, and the parent must implement
11460 * the #ClutterContainer interface
11462 * This function calls clutter_container_raise_child() internally.
11464 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11467 clutter_actor_raise (ClutterActor *self,
11468 ClutterActor *below)
11470 ClutterActor *parent;
11472 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11474 parent = clutter_actor_get_parent (self);
11475 if (parent == NULL)
11477 g_warning ("%s: Actor '%s' is not inside a container",
11479 _clutter_actor_get_debug_name (self));
11485 if (parent != clutter_actor_get_parent (below))
11487 g_warning ("%s Actor '%s' is not in the same container as "
11490 _clutter_actor_get_debug_name (self),
11491 _clutter_actor_get_debug_name (below));
11496 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11500 * clutter_actor_lower:
11501 * @self: A #ClutterActor
11502 * @above: (allow-none): A #ClutterActor to lower below
11504 * Puts @self below @above.
11506 * Both actors must have the same parent, and the parent must implement
11507 * the #ClutterContainer interface.
11509 * This function calls clutter_container_lower_child() internally.
11511 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11514 clutter_actor_lower (ClutterActor *self,
11515 ClutterActor *above)
11517 ClutterActor *parent;
11519 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11521 parent = clutter_actor_get_parent (self);
11522 if (parent == NULL)
11524 g_warning ("%s: Actor of type %s is not inside a container",
11526 _clutter_actor_get_debug_name (self));
11532 if (parent != clutter_actor_get_parent (above))
11534 g_warning ("%s: Actor '%s' is not in the same container as "
11537 _clutter_actor_get_debug_name (self),
11538 _clutter_actor_get_debug_name (above));
11543 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11547 * clutter_actor_raise_top:
11548 * @self: A #ClutterActor
11550 * Raises @self to the top.
11552 * This function calls clutter_actor_raise() internally.
11554 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11555 * a %NULL sibling, instead.
11558 clutter_actor_raise_top (ClutterActor *self)
11560 clutter_actor_raise (self, NULL);
11564 * clutter_actor_lower_bottom:
11565 * @self: A #ClutterActor
11567 * Lowers @self to the bottom.
11569 * This function calls clutter_actor_lower() internally.
11571 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11572 * a %NULL sibling, instead.
11575 clutter_actor_lower_bottom (ClutterActor *self)
11577 clutter_actor_lower (self, NULL);
11585 * clutter_actor_event:
11586 * @actor: a #ClutterActor
11587 * @event: a #ClutterEvent
11588 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11590 * This function is used to emit an event on the main stage.
11591 * You should rarely need to use this function, except for
11592 * synthetising events.
11594 * Return value: the return value from the signal emission: %TRUE
11595 * if the actor handled the event, or %FALSE if the event was
11601 clutter_actor_event (ClutterActor *actor,
11602 ClutterEvent *event,
11605 gboolean retval = FALSE;
11606 gint signal_num = -1;
11608 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11609 g_return_val_if_fail (event != NULL, FALSE);
11611 g_object_ref (actor);
11615 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11621 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11625 switch (event->type)
11627 case CLUTTER_NOTHING:
11629 case CLUTTER_BUTTON_PRESS:
11630 signal_num = BUTTON_PRESS_EVENT;
11632 case CLUTTER_BUTTON_RELEASE:
11633 signal_num = BUTTON_RELEASE_EVENT;
11635 case CLUTTER_SCROLL:
11636 signal_num = SCROLL_EVENT;
11638 case CLUTTER_KEY_PRESS:
11639 signal_num = KEY_PRESS_EVENT;
11641 case CLUTTER_KEY_RELEASE:
11642 signal_num = KEY_RELEASE_EVENT;
11644 case CLUTTER_MOTION:
11645 signal_num = MOTION_EVENT;
11647 case CLUTTER_ENTER:
11648 signal_num = ENTER_EVENT;
11650 case CLUTTER_LEAVE:
11651 signal_num = LEAVE_EVENT;
11653 case CLUTTER_DELETE:
11654 case CLUTTER_DESTROY_NOTIFY:
11655 case CLUTTER_CLIENT_MESSAGE:
11661 if (signal_num != -1)
11662 g_signal_emit (actor, actor_signals[signal_num], 0,
11667 g_object_unref (actor);
11673 * clutter_actor_set_reactive:
11674 * @actor: a #ClutterActor
11675 * @reactive: whether the actor should be reactive to events
11677 * Sets @actor as reactive. Reactive actors will receive events.
11682 clutter_actor_set_reactive (ClutterActor *actor,
11685 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11687 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11691 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11693 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11695 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11699 * clutter_actor_get_reactive:
11700 * @actor: a #ClutterActor
11702 * Checks whether @actor is marked as reactive.
11704 * Return value: %TRUE if the actor is reactive
11709 clutter_actor_get_reactive (ClutterActor *actor)
11711 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11713 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11717 * clutter_actor_get_anchor_point:
11718 * @self: a #ClutterActor
11719 * @anchor_x: (out): return location for the X coordinate of the anchor point
11720 * @anchor_y: (out): return location for the Y coordinate of the anchor point
11722 * Gets the current anchor point of the @actor in pixels.
11727 clutter_actor_get_anchor_point (ClutterActor *self,
11731 const ClutterTransformInfo *info;
11733 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11735 info = _clutter_actor_get_transform_info_or_defaults (self);
11736 clutter_anchor_coord_get_units (self, &info->anchor,
11743 * clutter_actor_set_anchor_point:
11744 * @self: a #ClutterActor
11745 * @anchor_x: X coordinate of the anchor point
11746 * @anchor_y: Y coordinate of the anchor point
11748 * Sets an anchor point for @self. The anchor point is a point in the
11749 * coordinate space of an actor to which the actor position within its
11750 * parent is relative; the default is (0, 0), i.e. the top-left corner
11756 clutter_actor_set_anchor_point (ClutterActor *self,
11760 ClutterTransformInfo *info;
11761 ClutterActorPrivate *priv;
11762 gboolean changed = FALSE;
11763 gfloat old_anchor_x, old_anchor_y;
11766 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11768 obj = G_OBJECT (self);
11770 info = _clutter_actor_get_transform_info (self);
11772 g_object_freeze_notify (obj);
11774 clutter_anchor_coord_get_units (self, &info->anchor,
11779 if (info->anchor.is_fractional)
11780 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11782 if (old_anchor_x != anchor_x)
11784 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11788 if (old_anchor_y != anchor_y)
11790 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11794 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11798 priv->transform_valid = FALSE;
11799 clutter_actor_queue_redraw (self);
11802 g_object_thaw_notify (obj);
11806 * clutter_actor_get_anchor_point_gravity:
11807 * @self: a #ClutterActor
11809 * Retrieves the anchor position expressed as a #ClutterGravity. If
11810 * the anchor point was specified using pixels or units this will
11811 * return %CLUTTER_GRAVITY_NONE.
11813 * Return value: the #ClutterGravity used by the anchor point
11818 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11820 const ClutterTransformInfo *info;
11822 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11824 info = _clutter_actor_get_transform_info_or_defaults (self);
11826 return clutter_anchor_coord_get_gravity (&info->anchor);
11830 * clutter_actor_move_anchor_point:
11831 * @self: a #ClutterActor
11832 * @anchor_x: X coordinate of the anchor point
11833 * @anchor_y: Y coordinate of the anchor point
11835 * Sets an anchor point for the actor, and adjusts the actor postion so that
11836 * the relative position of the actor toward its parent remains the same.
11841 clutter_actor_move_anchor_point (ClutterActor *self,
11845 gfloat old_anchor_x, old_anchor_y;
11846 const ClutterTransformInfo *info;
11848 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11850 info = _clutter_actor_get_transform_info (self);
11851 clutter_anchor_coord_get_units (self, &info->anchor,
11856 g_object_freeze_notify (G_OBJECT (self));
11858 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11860 if (self->priv->position_set)
11861 clutter_actor_move_by (self,
11862 anchor_x - old_anchor_x,
11863 anchor_y - old_anchor_y);
11865 g_object_thaw_notify (G_OBJECT (self));
11869 * clutter_actor_move_anchor_point_from_gravity:
11870 * @self: a #ClutterActor
11871 * @gravity: #ClutterGravity.
11873 * Sets an anchor point on the actor based on the given gravity, adjusting the
11874 * actor postion so that its relative position within its parent remains
11877 * Since version 1.0 the anchor point will be stored as a gravity so
11878 * that if the actor changes size then the anchor point will move. For
11879 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11880 * and later double the size of the actor, the anchor point will move
11881 * to the bottom right.
11886 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
11887 ClutterGravity gravity)
11889 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11890 const ClutterTransformInfo *info;
11891 ClutterActorPrivate *priv;
11893 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11896 info = _clutter_actor_get_transform_info (self);
11898 g_object_freeze_notify (G_OBJECT (self));
11900 clutter_anchor_coord_get_units (self, &info->anchor,
11904 clutter_actor_set_anchor_point_from_gravity (self, gravity);
11905 clutter_anchor_coord_get_units (self, &info->anchor,
11910 if (priv->position_set)
11911 clutter_actor_move_by (self,
11912 new_anchor_x - old_anchor_x,
11913 new_anchor_y - old_anchor_y);
11915 g_object_thaw_notify (G_OBJECT (self));
11919 * clutter_actor_set_anchor_point_from_gravity:
11920 * @self: a #ClutterActor
11921 * @gravity: #ClutterGravity.
11923 * Sets an anchor point on the actor, based on the given gravity (this is a
11924 * convenience function wrapping clutter_actor_set_anchor_point()).
11926 * Since version 1.0 the anchor point will be stored as a gravity so
11927 * that if the actor changes size then the anchor point will move. For
11928 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11929 * and later double the size of the actor, the anchor point will move
11930 * to the bottom right.
11935 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
11936 ClutterGravity gravity)
11938 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11940 if (gravity == CLUTTER_GRAVITY_NONE)
11941 clutter_actor_set_anchor_point (self, 0, 0);
11944 GObject *obj = G_OBJECT (self);
11945 ClutterTransformInfo *info;
11947 g_object_freeze_notify (obj);
11949 info = _clutter_actor_get_transform_info (self);
11950 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11952 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11953 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11954 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11956 self->priv->transform_valid = FALSE;
11958 clutter_actor_queue_redraw (self);
11960 g_object_thaw_notify (obj);
11965 clutter_container_iface_init (ClutterContainerIface *iface)
11967 /* we don't override anything, as ClutterContainer already has a default
11968 * implementation that we can use, and which calls into our own API.
11983 parse_units (ClutterActor *self,
11984 ParseDimension dimension,
11987 GValue value = { 0, };
11990 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
11993 json_node_get_value (node, &value);
11995 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
11997 retval = (gfloat) g_value_get_int64 (&value);
11999 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12001 retval = g_value_get_double (&value);
12003 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12005 ClutterUnits units;
12008 res = clutter_units_from_string (&units, g_value_get_string (&value));
12010 retval = clutter_units_to_pixels (&units);
12013 g_warning ("Invalid value '%s': integers, strings or floating point "
12014 "values can be used for the x, y, width and height "
12015 "properties. Valid modifiers for strings are 'px', 'mm', "
12017 g_value_get_string (&value));
12023 g_warning ("Invalid value of type '%s': integers, strings of floating "
12024 "point values can be used for the x, y, width, height "
12025 "anchor-x and anchor-y properties.",
12026 g_type_name (G_VALUE_TYPE (&value)));
12029 g_value_unset (&value);
12035 ClutterRotateAxis axis;
12044 static inline gboolean
12045 parse_rotation_array (ClutterActor *actor,
12047 RotationInfo *info)
12051 if (json_array_get_length (array) != 2)
12055 element = json_array_get_element (array, 0);
12056 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12057 info->angle = json_node_get_double (element);
12062 element = json_array_get_element (array, 1);
12063 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12065 JsonArray *center = json_node_get_array (element);
12067 if (json_array_get_length (center) != 2)
12070 switch (info->axis)
12072 case CLUTTER_X_AXIS:
12073 info->center_y = parse_units (actor, PARSE_Y,
12074 json_array_get_element (center, 0));
12075 info->center_z = parse_units (actor, PARSE_Y,
12076 json_array_get_element (center, 1));
12079 case CLUTTER_Y_AXIS:
12080 info->center_x = parse_units (actor, PARSE_X,
12081 json_array_get_element (center, 0));
12082 info->center_z = parse_units (actor, PARSE_X,
12083 json_array_get_element (center, 1));
12086 case CLUTTER_Z_AXIS:
12087 info->center_x = parse_units (actor, PARSE_X,
12088 json_array_get_element (center, 0));
12089 info->center_y = parse_units (actor, PARSE_Y,
12090 json_array_get_element (center, 1));
12099 parse_rotation (ClutterActor *actor,
12101 RotationInfo *info)
12105 gboolean retval = FALSE;
12107 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12109 g_warning ("Invalid node of type '%s' found, expecting an array",
12110 json_node_type_name (node));
12114 array = json_node_get_array (node);
12115 len = json_array_get_length (array);
12117 for (i = 0; i < len; i++)
12119 JsonNode *element = json_array_get_element (array, i);
12120 JsonObject *object;
12123 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12125 g_warning ("Invalid node of type '%s' found, expecting an object",
12126 json_node_type_name (element));
12130 object = json_node_get_object (element);
12132 if (json_object_has_member (object, "x-axis"))
12134 member = json_object_get_member (object, "x-axis");
12136 info->axis = CLUTTER_X_AXIS;
12138 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12140 info->angle = json_node_get_double (member);
12143 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12144 retval = parse_rotation_array (actor,
12145 json_node_get_array (member),
12150 else if (json_object_has_member (object, "y-axis"))
12152 member = json_object_get_member (object, "y-axis");
12154 info->axis = CLUTTER_Y_AXIS;
12156 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12158 info->angle = json_node_get_double (member);
12161 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12162 retval = parse_rotation_array (actor,
12163 json_node_get_array (member),
12168 else if (json_object_has_member (object, "z-axis"))
12170 member = json_object_get_member (object, "z-axis");
12172 info->axis = CLUTTER_Z_AXIS;
12174 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12176 info->angle = json_node_get_double (member);
12179 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12180 retval = parse_rotation_array (actor,
12181 json_node_get_array (member),
12192 parse_actor_metas (ClutterScript *script,
12193 ClutterActor *actor,
12196 GList *elements, *l;
12197 GSList *retval = NULL;
12199 if (!JSON_NODE_HOLDS_ARRAY (node))
12202 elements = json_array_get_elements (json_node_get_array (node));
12204 for (l = elements; l != NULL; l = l->next)
12206 JsonNode *element = l->data;
12207 const gchar *id_ = _clutter_script_get_id_from_node (element);
12210 if (id_ == NULL || *id_ == '\0')
12213 meta = clutter_script_get_object (script, id_);
12217 retval = g_slist_prepend (retval, meta);
12220 g_list_free (elements);
12222 return g_slist_reverse (retval);
12226 parse_behaviours (ClutterScript *script,
12227 ClutterActor *actor,
12230 GList *elements, *l;
12231 GSList *retval = NULL;
12233 if (!JSON_NODE_HOLDS_ARRAY (node))
12236 elements = json_array_get_elements (json_node_get_array (node));
12238 for (l = elements; l != NULL; l = l->next)
12240 JsonNode *element = l->data;
12241 const gchar *id_ = _clutter_script_get_id_from_node (element);
12242 GObject *behaviour;
12244 if (id_ == NULL || *id_ == '\0')
12247 behaviour = clutter_script_get_object (script, id_);
12248 if (behaviour == NULL)
12251 retval = g_slist_prepend (retval, behaviour);
12254 g_list_free (elements);
12256 return g_slist_reverse (retval);
12260 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12261 ClutterScript *script,
12266 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12267 gboolean retval = FALSE;
12269 if ((name[0] == 'x' && name[1] == '\0') ||
12270 (name[0] == 'y' && name[1] == '\0') ||
12271 (strcmp (name, "width") == 0) ||
12272 (strcmp (name, "height") == 0) ||
12273 (strcmp (name, "anchor_x") == 0) ||
12274 (strcmp (name, "anchor_y") == 0))
12276 ParseDimension dimension;
12279 if (name[0] == 'x')
12280 dimension = PARSE_X;
12281 else if (name[0] == 'y')
12282 dimension = PARSE_Y;
12283 else if (name[0] == 'w')
12284 dimension = PARSE_WIDTH;
12285 else if (name[0] == 'h')
12286 dimension = PARSE_HEIGHT;
12287 else if (name[0] == 'a' && name[7] == 'x')
12288 dimension = PARSE_ANCHOR_X;
12289 else if (name[0] == 'a' && name[7] == 'y')
12290 dimension = PARSE_ANCHOR_Y;
12294 units = parse_units (actor, dimension, node);
12296 /* convert back to pixels: all properties are pixel-based */
12297 g_value_init (value, G_TYPE_FLOAT);
12298 g_value_set_float (value, units);
12302 else if (strcmp (name, "rotation") == 0)
12304 RotationInfo *info;
12306 info = g_slice_new0 (RotationInfo);
12307 retval = parse_rotation (actor, node, info);
12311 g_value_init (value, G_TYPE_POINTER);
12312 g_value_set_pointer (value, info);
12315 g_slice_free (RotationInfo, info);
12317 else if (strcmp (name, "behaviours") == 0)
12321 #ifdef CLUTTER_ENABLE_DEBUG
12322 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12323 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12324 "and it should not be used in newly "
12325 "written ClutterScript definitions.");
12328 l = parse_behaviours (script, actor, node);
12330 g_value_init (value, G_TYPE_POINTER);
12331 g_value_set_pointer (value, l);
12335 else if (strcmp (name, "actions") == 0 ||
12336 strcmp (name, "constraints") == 0 ||
12337 strcmp (name, "effects") == 0)
12341 l = parse_actor_metas (script, actor, node);
12343 g_value_init (value, G_TYPE_POINTER);
12344 g_value_set_pointer (value, l);
12353 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12354 ClutterScript *script,
12356 const GValue *value)
12358 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12360 #ifdef CLUTTER_ENABLE_DEBUG
12361 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12363 gchar *tmp = g_strdup_value_contents (value);
12365 CLUTTER_NOTE (SCRIPT,
12366 "in ClutterActor::set_custom_property('%s') = %s",
12372 #endif /* CLUTTER_ENABLE_DEBUG */
12374 if (strcmp (name, "rotation") == 0)
12376 RotationInfo *info;
12378 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12381 info = g_value_get_pointer (value);
12383 clutter_actor_set_rotation (actor,
12384 info->axis, info->angle,
12389 g_slice_free (RotationInfo, info);
12394 if (strcmp (name, "behaviours") == 0)
12396 GSList *behaviours, *l;
12398 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12401 behaviours = g_value_get_pointer (value);
12402 for (l = behaviours; l != NULL; l = l->next)
12404 ClutterBehaviour *behaviour = l->data;
12406 clutter_behaviour_apply (behaviour, actor);
12409 g_slist_free (behaviours);
12414 if (strcmp (name, "actions") == 0 ||
12415 strcmp (name, "constraints") == 0 ||
12416 strcmp (name, "effects") == 0)
12420 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12423 metas = g_value_get_pointer (value);
12424 for (l = metas; l != NULL; l = l->next)
12426 if (name[0] == 'a')
12427 clutter_actor_add_action (actor, l->data);
12429 if (name[0] == 'c')
12430 clutter_actor_add_constraint (actor, l->data);
12432 if (name[0] == 'e')
12433 clutter_actor_add_effect (actor, l->data);
12436 g_slist_free (metas);
12441 g_object_set_property (G_OBJECT (scriptable), name, value);
12445 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12447 iface->parse_custom_node = clutter_actor_parse_custom_node;
12448 iface->set_custom_property = clutter_actor_set_custom_property;
12451 static ClutterActorMeta *
12452 get_meta_from_animation_property (ClutterActor *actor,
12456 ClutterActorPrivate *priv = actor->priv;
12457 ClutterActorMeta *meta = NULL;
12460 /* if this is not a special property, fall through */
12461 if (name[0] != '@')
12464 /* detect the properties named using the following spec:
12466 * @<section>.<meta-name>.<property-name>
12468 * where <section> can be one of the following:
12474 * and <meta-name> is the name set on a specific ActorMeta
12477 tokens = g_strsplit (name + 1, ".", -1);
12478 if (tokens == NULL || g_strv_length (tokens) != 3)
12480 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12482 g_strfreev (tokens);
12486 if (strcmp (tokens[0], "actions") == 0)
12487 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12489 if (strcmp (tokens[0], "constraints") == 0)
12490 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12492 if (strcmp (tokens[0], "effects") == 0)
12493 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12495 if (name_p != NULL)
12496 *name_p = g_strdup (tokens[2]);
12498 CLUTTER_NOTE (ANIMATION,
12499 "Looking for property '%s' of object '%s' in section '%s'",
12504 g_strfreev (tokens);
12509 static GParamSpec *
12510 clutter_actor_find_property (ClutterAnimatable *animatable,
12511 const gchar *property_name)
12513 ClutterActorMeta *meta = NULL;
12514 GObjectClass *klass = NULL;
12515 GParamSpec *pspec = NULL;
12516 gchar *p_name = NULL;
12518 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12524 klass = G_OBJECT_GET_CLASS (meta);
12526 pspec = g_object_class_find_property (klass, p_name);
12530 klass = G_OBJECT_GET_CLASS (animatable);
12532 pspec = g_object_class_find_property (klass, property_name);
12541 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12542 const gchar *property_name,
12545 ClutterActorMeta *meta = NULL;
12546 gchar *p_name = NULL;
12548 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12553 g_object_get_property (G_OBJECT (meta), p_name, initial);
12555 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12561 * clutter_actor_set_animatable_property:
12562 * @actor: a #ClutterActor
12563 * @prop_id: the paramspec id
12564 * @value: the value to set
12565 * @pspec: the paramspec
12567 * Sets values of animatable properties.
12569 * This is a variant of clutter_actor_set_property() that gets called
12570 * by the #ClutterAnimatable implementation of #ClutterActor for the
12571 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12574 * Unlike the implementation of #GObjectClass.set_property(), this
12575 * function will not update the interval if a transition involving an
12576 * animatable property is in progress - this avoids cycles with the
12577 * transition API calling the public API.
12580 clutter_actor_set_animatable_property (ClutterActor *actor,
12582 const GValue *value,
12588 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12592 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12596 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12600 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12604 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12608 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12611 case PROP_BACKGROUND_COLOR:
12612 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12616 clutter_actor_set_scale_factor_internal (actor,
12617 g_value_get_double (value),
12622 clutter_actor_set_scale_factor_internal (actor,
12623 g_value_get_double (value),
12627 case PROP_ROTATION_ANGLE_X:
12628 clutter_actor_set_rotation_angle_internal (actor,
12630 g_value_get_double (value));
12633 case PROP_ROTATION_ANGLE_Y:
12634 clutter_actor_set_rotation_angle_internal (actor,
12636 g_value_get_double (value));
12639 case PROP_ROTATION_ANGLE_Z:
12640 clutter_actor_set_rotation_angle_internal (actor,
12642 g_value_get_double (value));
12646 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12652 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12653 const gchar *property_name,
12654 const GValue *final)
12656 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12657 ClutterActorMeta *meta = NULL;
12658 gchar *p_name = NULL;
12660 meta = get_meta_from_animation_property (actor,
12664 g_object_set_property (G_OBJECT (meta), p_name, final);
12667 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12670 pspec = g_object_class_find_property (obj_class, property_name);
12672 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12674 /* XXX - I'm going to the special hell for this */
12675 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12678 g_object_set_property (G_OBJECT (animatable), property_name, final);
12685 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12687 iface->find_property = clutter_actor_find_property;
12688 iface->get_initial_state = clutter_actor_get_initial_state;
12689 iface->set_final_state = clutter_actor_set_final_state;
12693 * clutter_actor_transform_stage_point:
12694 * @self: A #ClutterActor
12695 * @x: (in): x screen coordinate of the point to unproject
12696 * @y: (in): y screen coordinate of the point to unproject
12697 * @x_out: (out): return location for the unprojected x coordinance
12698 * @y_out: (out): return location for the unprojected y coordinance
12700 * This function translates screen coordinates (@x, @y) to
12701 * coordinates relative to the actor. For example, it can be used to translate
12702 * screen events from global screen coordinates into actor-local coordinates.
12704 * The conversion can fail, notably if the transform stack results in the
12705 * actor being projected on the screen as a mere line.
12707 * The conversion should not be expected to be pixel-perfect due to the
12708 * nature of the operation. In general the error grows when the skewing
12709 * of the actor rectangle on screen increases.
12711 * <note><para>This function can be computationally intensive.</para></note>
12713 * <note><para>This function only works when the allocation is up-to-date,
12714 * i.e. inside of paint().</para></note>
12716 * Return value: %TRUE if conversion was successful.
12721 clutter_actor_transform_stage_point (ClutterActor *self,
12727 ClutterVertex v[4];
12730 int du, dv, xi, yi;
12732 float xf, yf, wf, det;
12733 ClutterActorPrivate *priv;
12735 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12739 /* This implementation is based on the quad -> quad projection algorithm
12740 * described by Paul Heckbert in:
12742 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12744 * and the sample implementation at:
12746 * http://www.cs.cmu.edu/~ph/src/texfund/
12748 * Our texture is a rectangle with origin [0, 0], so we are mapping from
12749 * quad to rectangle only, which significantly simplifies things; the
12750 * function calls have been unrolled, and most of the math is done in fixed
12754 clutter_actor_get_abs_allocation_vertices (self, v);
12756 /* Keeping these as ints simplifies the multiplication (no significant
12757 * loss of precision here).
12759 du = (int) (priv->allocation.x2 - priv->allocation.x1);
12760 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12765 #define UX2FP(x) (x)
12766 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12768 /* First, find mapping from unit uv square to xy quadrilateral; this
12769 * equivalent to the pmap_square_quad() functions in the sample
12770 * implementation, which we can simplify, since our target is always
12773 px = v[0].x - v[1].x + v[3].x - v[2].x;
12774 py = v[0].y - v[1].y + v[3].y - v[2].y;
12778 /* affine transform */
12779 RQ[0][0] = UX2FP (v[1].x - v[0].x);
12780 RQ[1][0] = UX2FP (v[3].x - v[1].x);
12781 RQ[2][0] = UX2FP (v[0].x);
12782 RQ[0][1] = UX2FP (v[1].y - v[0].y);
12783 RQ[1][1] = UX2FP (v[3].y - v[1].y);
12784 RQ[2][1] = UX2FP (v[0].y);
12791 /* projective transform */
12792 double dx1, dx2, dy1, dy2, del;
12794 dx1 = UX2FP (v[1].x - v[3].x);
12795 dx2 = UX2FP (v[2].x - v[3].x);
12796 dy1 = UX2FP (v[1].y - v[3].y);
12797 dy2 = UX2FP (v[2].y - v[3].y);
12799 del = DET2FP (dx1, dx2, dy1, dy2);
12804 * The division here needs to be done in floating point for
12805 * precisions reasons.
12807 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12808 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12809 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12811 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12812 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12813 RQ[2][0] = UX2FP (v[0].x);
12814 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12815 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12816 RQ[2][1] = UX2FP (v[0].y);
12820 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12821 * square. Since our rectangle is based at 0,0 we only need to scale.
12831 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12834 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12835 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12836 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12837 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12838 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12839 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12840 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12841 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12842 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12845 * Check the resulting matrix is OK.
12847 det = (RQ[0][0] * ST[0][0])
12848 + (RQ[0][1] * ST[0][1])
12849 + (RQ[0][2] * ST[0][2]);
12854 * Now transform our point with the ST matrix; the notional w
12855 * coordinate is 1, hence the last part is simply added.
12860 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12861 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12862 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12880 static ClutterGeometry*
12881 clutter_geometry_copy (const ClutterGeometry *geometry)
12883 return g_slice_dup (ClutterGeometry, geometry);
12887 clutter_geometry_free (ClutterGeometry *geometry)
12889 if (G_LIKELY (geometry != NULL))
12890 g_slice_free (ClutterGeometry, geometry);
12894 * clutter_geometry_union:
12895 * @geometry_a: a #ClutterGeometry
12896 * @geometry_b: another #ClutterGeometry
12897 * @result: (out): location to store the result
12899 * Find the union of two rectangles represented as #ClutterGeometry.
12904 clutter_geometry_union (const ClutterGeometry *geometry_a,
12905 const ClutterGeometry *geometry_b,
12906 ClutterGeometry *result)
12908 /* We don't try to handle rectangles that can't be represented
12909 * as a signed integer box */
12910 gint x_1 = MIN (geometry_a->x, geometry_b->x);
12911 gint y_1 = MIN (geometry_a->y, geometry_b->y);
12912 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12913 geometry_b->x + (gint)geometry_b->width);
12914 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12915 geometry_b->y + (gint)geometry_b->height);
12918 result->width = x_2 - x_1;
12919 result->height = y_2 - y_1;
12923 * clutter_geometry_intersects:
12924 * @geometry0: The first geometry to test
12925 * @geometry1: The second geometry to test
12927 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12928 * they do else %FALSE.
12930 * Return value: %TRUE of @geometry0 and geometry1 intersect else
12936 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12937 const ClutterGeometry *geometry1)
12939 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12940 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12941 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12942 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12949 clutter_geometry_progress (const GValue *a,
12954 const ClutterGeometry *a_geom = g_value_get_boxed (a);
12955 const ClutterGeometry *b_geom = g_value_get_boxed (b);
12956 ClutterGeometry res = { 0, };
12957 gint a_width = a_geom->width;
12958 gint b_width = b_geom->width;
12959 gint a_height = a_geom->height;
12960 gint b_height = b_geom->height;
12962 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12963 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
12965 res.width = a_width + (b_width - a_width) * progress;
12966 res.height = a_height + (b_height - a_height) * progress;
12968 g_value_set_boxed (retval, &res);
12973 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
12974 clutter_geometry_copy,
12975 clutter_geometry_free,
12976 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
12983 * clutter_vertex_new:
12988 * Creates a new #ClutterVertex for the point in 3D space
12989 * identified by the 3 coordinates @x, @y, @z
12991 * Return value: the newly allocate #ClutterVertex. Use
12992 * clutter_vertex_free() to free the resources
12997 clutter_vertex_new (gfloat x,
13001 ClutterVertex *vertex;
13003 vertex = g_slice_new (ClutterVertex);
13012 * clutter_vertex_copy:
13013 * @vertex: a #ClutterVertex
13017 * Return value: a newly allocated copy of #ClutterVertex. Use
13018 * clutter_vertex_free() to free the allocated resources
13023 clutter_vertex_copy (const ClutterVertex *vertex)
13025 if (G_LIKELY (vertex != NULL))
13026 return g_slice_dup (ClutterVertex, vertex);
13032 * clutter_vertex_free:
13033 * @vertex: a #ClutterVertex
13035 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13040 clutter_vertex_free (ClutterVertex *vertex)
13042 if (G_UNLIKELY (vertex != NULL))
13043 g_slice_free (ClutterVertex, vertex);
13047 * clutter_vertex_equal:
13048 * @vertex_a: a #ClutterVertex
13049 * @vertex_b: a #ClutterVertex
13051 * Compares @vertex_a and @vertex_b for equality
13053 * Return value: %TRUE if the passed #ClutterVertex are equal
13058 clutter_vertex_equal (const ClutterVertex *vertex_a,
13059 const ClutterVertex *vertex_b)
13061 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13063 if (vertex_a == vertex_b)
13066 return vertex_a->x == vertex_b->x &&
13067 vertex_a->y == vertex_b->y &&
13068 vertex_a->z == vertex_b->z;
13072 clutter_vertex_progress (const GValue *a,
13077 const ClutterVertex *av = g_value_get_boxed (a);
13078 const ClutterVertex *bv = g_value_get_boxed (b);
13079 ClutterVertex res = { 0, };
13081 res.x = av->x + (bv->x - av->x) * progress;
13082 res.y = av->y + (bv->y - av->y) * progress;
13083 res.z = av->z + (bv->z - av->z) * progress;
13085 g_value_set_boxed (retval, &res);
13090 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13091 clutter_vertex_copy,
13092 clutter_vertex_free,
13093 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13096 * clutter_actor_is_rotated:
13097 * @self: a #ClutterActor
13099 * Checks whether any rotation is applied to the actor.
13101 * Return value: %TRUE if the actor is rotated.
13106 clutter_actor_is_rotated (ClutterActor *self)
13108 const ClutterTransformInfo *info;
13110 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13112 info = _clutter_actor_get_transform_info_or_defaults (self);
13114 if (info->rx_angle || info->ry_angle || info->rz_angle)
13121 * clutter_actor_is_scaled:
13122 * @self: a #ClutterActor
13124 * Checks whether the actor is scaled in either dimension.
13126 * Return value: %TRUE if the actor is scaled.
13131 clutter_actor_is_scaled (ClutterActor *self)
13133 const ClutterTransformInfo *info;
13135 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13137 info = _clutter_actor_get_transform_info_or_defaults (self);
13139 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13146 _clutter_actor_get_stage_internal (ClutterActor *actor)
13148 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13149 actor = actor->priv->parent;
13155 * clutter_actor_get_stage:
13156 * @actor: a #ClutterActor
13158 * Retrieves the #ClutterStage where @actor is contained.
13160 * Return value: (transfer none) (type Clutter.Stage): the stage
13161 * containing the actor, or %NULL
13166 clutter_actor_get_stage (ClutterActor *actor)
13168 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13170 return _clutter_actor_get_stage_internal (actor);
13174 * clutter_actor_allocate_available_size:
13175 * @self: a #ClutterActor
13176 * @x: the actor's X coordinate
13177 * @y: the actor's Y coordinate
13178 * @available_width: the maximum available width, or -1 to use the
13179 * actor's natural width
13180 * @available_height: the maximum available height, or -1 to use the
13181 * actor's natural height
13182 * @flags: flags controlling the allocation
13184 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13185 * preferred size, but limiting it to the maximum available width
13186 * and height provided.
13188 * This function will do the right thing when dealing with the
13189 * actor's request mode.
13191 * The implementation of this function is equivalent to:
13194 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13196 * clutter_actor_get_preferred_width (self, available_height,
13198 * &natural_width);
13199 * width = CLAMP (natural_width, min_width, available_width);
13201 * clutter_actor_get_preferred_height (self, width,
13203 * &natural_height);
13204 * height = CLAMP (natural_height, min_height, available_height);
13208 * clutter_actor_get_preferred_height (self, available_width,
13210 * &natural_height);
13211 * height = CLAMP (natural_height, min_height, available_height);
13213 * clutter_actor_get_preferred_width (self, height,
13215 * &natural_width);
13216 * width = CLAMP (natural_width, min_width, available_width);
13219 * box.x1 = x; box.y1 = y;
13220 * box.x2 = box.x1 + available_width;
13221 * box.y2 = box.y1 + available_height;
13222 * clutter_actor_allocate (self, &box, flags);
13225 * This function can be used by fluid layout managers to allocate
13226 * an actor's preferred size without making it bigger than the area
13227 * available for the container.
13232 clutter_actor_allocate_available_size (ClutterActor *self,
13235 gfloat available_width,
13236 gfloat available_height,
13237 ClutterAllocationFlags flags)
13239 ClutterActorPrivate *priv;
13240 gfloat width, height;
13241 gfloat min_width, min_height;
13242 gfloat natural_width, natural_height;
13243 ClutterActorBox box;
13245 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13249 width = height = 0.0;
13251 switch (priv->request_mode)
13253 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13254 clutter_actor_get_preferred_width (self, available_height,
13257 width = CLAMP (natural_width, min_width, available_width);
13259 clutter_actor_get_preferred_height (self, width,
13262 height = CLAMP (natural_height, min_height, available_height);
13265 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13266 clutter_actor_get_preferred_height (self, available_width,
13269 height = CLAMP (natural_height, min_height, available_height);
13271 clutter_actor_get_preferred_width (self, height,
13274 width = CLAMP (natural_width, min_width, available_width);
13281 box.x2 = box.x1 + width;
13282 box.y2 = box.y1 + height;
13283 clutter_actor_allocate (self, &box, flags);
13287 * clutter_actor_allocate_preferred_size:
13288 * @self: a #ClutterActor
13289 * @flags: flags controlling the allocation
13291 * Allocates the natural size of @self.
13293 * This function is a utility call for #ClutterActor implementations
13294 * that allocates the actor's preferred natural size. It can be used
13295 * by fixed layout managers (like #ClutterGroup or so called
13296 * 'composite actors') inside the ClutterActor::allocate
13297 * implementation to give each child exactly how much space it
13300 * This function is not meant to be used by applications. It is also
13301 * not meant to be used outside the implementation of the
13302 * ClutterActor::allocate virtual function.
13307 clutter_actor_allocate_preferred_size (ClutterActor *self,
13308 ClutterAllocationFlags flags)
13310 gfloat actor_x, actor_y;
13311 gfloat natural_width, natural_height;
13312 ClutterActorBox actor_box;
13314 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13316 actor_x = clutter_actor_get_x (self);
13317 actor_y = clutter_actor_get_y (self);
13319 clutter_actor_get_preferred_size (self,
13324 actor_box.x1 = actor_x;
13325 actor_box.y1 = actor_y;
13326 actor_box.x2 = actor_box.x1 + natural_width;
13327 actor_box.y2 = actor_box.y1 + natural_height;
13329 clutter_actor_allocate (self, &actor_box, flags);
13333 * clutter_actor_allocate_align_fill:
13334 * @self: a #ClutterActor
13335 * @box: a #ClutterActorBox, containing the available width and height
13336 * @x_align: the horizontal alignment, between 0 and 1
13337 * @y_align: the vertical alignment, between 0 and 1
13338 * @x_fill: whether the actor should fill horizontally
13339 * @y_fill: whether the actor should fill vertically
13340 * @flags: allocation flags to be passed to clutter_actor_allocate()
13342 * Allocates @self by taking into consideration the available allocation
13343 * area; an alignment factor on either axis; and whether the actor should
13344 * fill the allocation on either axis.
13346 * The @box should contain the available allocation width and height;
13347 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13348 * allocation will be offset by their value.
13350 * This function takes into consideration the geometry request specified by
13351 * the #ClutterActor:request-mode property, and the text direction.
13353 * This function is useful for fluid layout managers, like #ClutterBinLayout
13354 * or #ClutterTableLayout
13359 clutter_actor_allocate_align_fill (ClutterActor *self,
13360 const ClutterActorBox *box,
13365 ClutterAllocationFlags flags)
13367 ClutterActorPrivate *priv;
13368 ClutterActorBox allocation = { 0, };
13369 gfloat x_offset, y_offset;
13370 gfloat available_width, available_height;
13371 gfloat child_width, child_height;
13373 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13374 g_return_if_fail (box != NULL);
13375 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13376 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13380 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13381 clutter_actor_box_get_size (box, &available_width, &available_height);
13383 if (available_width < 0)
13384 available_width = 0;
13386 if (available_height < 0)
13387 available_height = 0;
13391 allocation.x1 = x_offset;
13392 allocation.x2 = allocation.x1 + available_width;
13397 allocation.y1 = y_offset;
13398 allocation.y2 = allocation.y1 + available_height;
13401 /* if we are filling horizontally and vertically then we're done */
13402 if (x_fill && y_fill)
13405 child_width = child_height = 0.0f;
13407 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13409 gfloat min_width, natural_width;
13410 gfloat min_height, natural_height;
13412 clutter_actor_get_preferred_width (self, available_height,
13416 child_width = CLAMP (natural_width, min_width, available_width);
13420 clutter_actor_get_preferred_height (self, child_width,
13424 child_height = CLAMP (natural_height, min_height, available_height);
13429 gfloat min_width, natural_width;
13430 gfloat min_height, natural_height;
13432 clutter_actor_get_preferred_height (self, available_width,
13436 child_height = CLAMP (natural_height, min_height, available_height);
13440 clutter_actor_get_preferred_width (self, child_height,
13444 child_width = CLAMP (natural_width, min_width, available_width);
13448 /* invert the horizontal alignment for RTL languages */
13449 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13450 x_align = 1.0 - x_align;
13454 allocation.x1 = x_offset
13455 + ((available_width - child_width) * x_align);
13456 allocation.x2 = allocation.x1 + child_width;
13461 allocation.y1 = y_offset
13462 + ((available_height - child_height) * y_align);
13463 allocation.y2 = allocation.y1 + child_height;
13467 clutter_actor_box_clamp_to_pixel (&allocation);
13468 clutter_actor_allocate (self, &allocation, flags);
13472 * clutter_actor_grab_key_focus:
13473 * @self: a #ClutterActor
13475 * Sets the key focus of the #ClutterStage including @self
13476 * to this #ClutterActor.
13481 clutter_actor_grab_key_focus (ClutterActor *self)
13483 ClutterActor *stage;
13485 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13487 stage = _clutter_actor_get_stage_internal (self);
13489 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13493 * clutter_actor_get_pango_context:
13494 * @self: a #ClutterActor
13496 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13497 * is already configured using the appropriate font map, resolution
13498 * and font options.
13500 * Unlike clutter_actor_create_pango_context(), this context is owend
13501 * by the #ClutterActor and it will be updated each time the options
13502 * stored by the #ClutterBackend change.
13504 * You can use the returned #PangoContext to create a #PangoLayout
13505 * and render text using cogl_pango_render_layout() to reuse the
13506 * glyphs cache also used by Clutter.
13508 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13509 * The returned #PangoContext is owned by the actor and should not be
13510 * unreferenced by the application code
13515 clutter_actor_get_pango_context (ClutterActor *self)
13517 ClutterActorPrivate *priv;
13519 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13523 if (priv->pango_context != NULL)
13524 return priv->pango_context;
13526 priv->pango_context = _clutter_context_get_pango_context ();
13527 g_object_ref (priv->pango_context);
13529 return priv->pango_context;
13533 * clutter_actor_create_pango_context:
13534 * @self: a #ClutterActor
13536 * Creates a #PangoContext for the given actor. The #PangoContext
13537 * is already configured using the appropriate font map, resolution
13538 * and font options.
13540 * See also clutter_actor_get_pango_context().
13542 * Return value: (transfer full): the newly created #PangoContext.
13543 * Use g_object_unref() on the returned value to deallocate its
13549 clutter_actor_create_pango_context (ClutterActor *self)
13551 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13553 return _clutter_context_create_pango_context ();
13557 * clutter_actor_create_pango_layout:
13558 * @self: a #ClutterActor
13559 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13561 * Creates a new #PangoLayout from the same #PangoContext used
13562 * by the #ClutterActor. The #PangoLayout is already configured
13563 * with the font map, resolution and font options, and the
13566 * If you want to keep around a #PangoLayout created by this
13567 * function you will have to connect to the #ClutterBackend::font-changed
13568 * and #ClutterBackend::resolution-changed signals, and call
13569 * pango_layout_context_changed() in response to them.
13571 * Return value: (transfer full): the newly created #PangoLayout.
13572 * Use g_object_unref() when done
13577 clutter_actor_create_pango_layout (ClutterActor *self,
13580 PangoContext *context;
13581 PangoLayout *layout;
13583 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13585 context = clutter_actor_get_pango_context (self);
13586 layout = pango_layout_new (context);
13589 pango_layout_set_text (layout, text, -1);
13594 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13595 * ClutterOffscreenEffect.
13598 _clutter_actor_set_opacity_override (ClutterActor *self,
13601 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13603 self->priv->opacity_override = opacity;
13607 _clutter_actor_get_opacity_override (ClutterActor *self)
13609 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13611 return self->priv->opacity_override;
13614 /* Allows you to disable applying the actors model view transform during
13615 * a paint. Used by ClutterClone. */
13617 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13620 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13622 self->priv->enable_model_view_transform = enable;
13626 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13629 ClutterActorPrivate *priv;
13631 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13635 priv->enable_paint_unmapped = enable;
13637 if (priv->enable_paint_unmapped)
13639 /* Make sure that the parents of the widget are realized first;
13640 * otherwise checks in clutter_actor_update_map_state() will
13643 clutter_actor_realize (self);
13645 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13649 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13654 clutter_anchor_coord_get_units (ClutterActor *self,
13655 const AnchorCoord *coord,
13660 if (coord->is_fractional)
13662 gfloat actor_width, actor_height;
13664 clutter_actor_get_size (self, &actor_width, &actor_height);
13667 *x = actor_width * coord->v.fraction.x;
13670 *y = actor_height * coord->v.fraction.y;
13678 *x = coord->v.units.x;
13681 *y = coord->v.units.y;
13684 *z = coord->v.units.z;
13689 clutter_anchor_coord_set_units (AnchorCoord *coord,
13694 coord->is_fractional = FALSE;
13695 coord->v.units.x = x;
13696 coord->v.units.y = y;
13697 coord->v.units.z = z;
13700 static ClutterGravity
13701 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13703 if (coord->is_fractional)
13705 if (coord->v.fraction.x == 0.0)
13707 if (coord->v.fraction.y == 0.0)
13708 return CLUTTER_GRAVITY_NORTH_WEST;
13709 else if (coord->v.fraction.y == 0.5)
13710 return CLUTTER_GRAVITY_WEST;
13711 else if (coord->v.fraction.y == 1.0)
13712 return CLUTTER_GRAVITY_SOUTH_WEST;
13714 return CLUTTER_GRAVITY_NONE;
13716 else if (coord->v.fraction.x == 0.5)
13718 if (coord->v.fraction.y == 0.0)
13719 return CLUTTER_GRAVITY_NORTH;
13720 else if (coord->v.fraction.y == 0.5)
13721 return CLUTTER_GRAVITY_CENTER;
13722 else if (coord->v.fraction.y == 1.0)
13723 return CLUTTER_GRAVITY_SOUTH;
13725 return CLUTTER_GRAVITY_NONE;
13727 else if (coord->v.fraction.x == 1.0)
13729 if (coord->v.fraction.y == 0.0)
13730 return CLUTTER_GRAVITY_NORTH_EAST;
13731 else if (coord->v.fraction.y == 0.5)
13732 return CLUTTER_GRAVITY_EAST;
13733 else if (coord->v.fraction.y == 1.0)
13734 return CLUTTER_GRAVITY_SOUTH_EAST;
13736 return CLUTTER_GRAVITY_NONE;
13739 return CLUTTER_GRAVITY_NONE;
13742 return CLUTTER_GRAVITY_NONE;
13746 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
13747 ClutterGravity gravity)
13751 case CLUTTER_GRAVITY_NORTH:
13752 coord->v.fraction.x = 0.5;
13753 coord->v.fraction.y = 0.0;
13756 case CLUTTER_GRAVITY_NORTH_EAST:
13757 coord->v.fraction.x = 1.0;
13758 coord->v.fraction.y = 0.0;
13761 case CLUTTER_GRAVITY_EAST:
13762 coord->v.fraction.x = 1.0;
13763 coord->v.fraction.y = 0.5;
13766 case CLUTTER_GRAVITY_SOUTH_EAST:
13767 coord->v.fraction.x = 1.0;
13768 coord->v.fraction.y = 1.0;
13771 case CLUTTER_GRAVITY_SOUTH:
13772 coord->v.fraction.x = 0.5;
13773 coord->v.fraction.y = 1.0;
13776 case CLUTTER_GRAVITY_SOUTH_WEST:
13777 coord->v.fraction.x = 0.0;
13778 coord->v.fraction.y = 1.0;
13781 case CLUTTER_GRAVITY_WEST:
13782 coord->v.fraction.x = 0.0;
13783 coord->v.fraction.y = 0.5;
13786 case CLUTTER_GRAVITY_NORTH_WEST:
13787 coord->v.fraction.x = 0.0;
13788 coord->v.fraction.y = 0.0;
13791 case CLUTTER_GRAVITY_CENTER:
13792 coord->v.fraction.x = 0.5;
13793 coord->v.fraction.y = 0.5;
13797 coord->v.fraction.x = 0.0;
13798 coord->v.fraction.y = 0.0;
13802 coord->is_fractional = TRUE;
13806 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13808 if (coord->is_fractional)
13809 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13811 return (coord->v.units.x == 0.0
13812 && coord->v.units.y == 0.0
13813 && coord->v.units.z == 0.0);
13817 * clutter_actor_get_flags:
13818 * @self: a #ClutterActor
13820 * Retrieves the flags set on @self
13822 * Return value: a bitwise or of #ClutterActorFlags or 0
13827 clutter_actor_get_flags (ClutterActor *self)
13829 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13831 return self->flags;
13835 * clutter_actor_set_flags:
13836 * @self: a #ClutterActor
13837 * @flags: the flags to set
13839 * Sets @flags on @self
13841 * This function will emit notifications for the changed properties
13846 clutter_actor_set_flags (ClutterActor *self,
13847 ClutterActorFlags flags)
13849 ClutterActorFlags old_flags;
13851 gboolean was_reactive_set, reactive_set;
13852 gboolean was_realized_set, realized_set;
13853 gboolean was_mapped_set, mapped_set;
13854 gboolean was_visible_set, visible_set;
13856 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13858 if (self->flags == flags)
13861 obj = G_OBJECT (self);
13862 g_object_ref (obj);
13863 g_object_freeze_notify (obj);
13865 old_flags = self->flags;
13867 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13868 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13869 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
13870 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
13872 self->flags |= flags;
13874 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13875 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13876 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
13877 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
13879 if (reactive_set != was_reactive_set)
13880 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13882 if (realized_set != was_realized_set)
13883 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13885 if (mapped_set != was_mapped_set)
13886 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13888 if (visible_set != was_visible_set)
13889 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13891 g_object_thaw_notify (obj);
13892 g_object_unref (obj);
13896 * clutter_actor_unset_flags:
13897 * @self: a #ClutterActor
13898 * @flags: the flags to unset
13900 * Unsets @flags on @self
13902 * This function will emit notifications for the changed properties
13907 clutter_actor_unset_flags (ClutterActor *self,
13908 ClutterActorFlags flags)
13910 ClutterActorFlags old_flags;
13912 gboolean was_reactive_set, reactive_set;
13913 gboolean was_realized_set, realized_set;
13914 gboolean was_mapped_set, mapped_set;
13915 gboolean was_visible_set, visible_set;
13917 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13919 obj = G_OBJECT (self);
13920 g_object_freeze_notify (obj);
13922 old_flags = self->flags;
13924 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13925 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13926 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
13927 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
13929 self->flags &= ~flags;
13931 if (self->flags == old_flags)
13934 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13935 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13936 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
13937 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
13939 if (reactive_set != was_reactive_set)
13940 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13942 if (realized_set != was_realized_set)
13943 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13945 if (mapped_set != was_mapped_set)
13946 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13948 if (visible_set != was_visible_set)
13949 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13951 g_object_thaw_notify (obj);
13955 * clutter_actor_get_transformation_matrix:
13956 * @self: a #ClutterActor
13957 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13959 * Retrieves the transformations applied to @self relative to its
13965 clutter_actor_get_transformation_matrix (ClutterActor *self,
13966 CoglMatrix *matrix)
13968 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13970 cogl_matrix_init_identity (matrix);
13972 _clutter_actor_apply_modelview_transform (self, matrix);
13976 _clutter_actor_set_in_clone_paint (ClutterActor *self,
13977 gboolean is_in_clone_paint)
13979 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13980 self->priv->in_clone_paint = is_in_clone_paint;
13984 * clutter_actor_is_in_clone_paint:
13985 * @self: a #ClutterActor
13987 * Checks whether @self is being currently painted by a #ClutterClone
13989 * This function is useful only inside the ::paint virtual function
13990 * implementations or within handlers for the #ClutterActor::paint
13993 * This function should not be used by applications
13995 * Return value: %TRUE if the #ClutterActor is currently being painted
13996 * by a #ClutterClone, and %FALSE otherwise
14001 clutter_actor_is_in_clone_paint (ClutterActor *self)
14003 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14005 return self->priv->in_clone_paint;
14009 set_direction_recursive (ClutterActor *actor,
14010 gpointer user_data)
14012 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14014 clutter_actor_set_text_direction (actor, text_dir);
14020 * clutter_actor_set_text_direction:
14021 * @self: a #ClutterActor
14022 * @text_dir: the text direction for @self
14024 * Sets the #ClutterTextDirection for an actor
14026 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14028 * If @self implements #ClutterContainer then this function will recurse
14029 * inside all the children of @self (including the internal ones).
14031 * Composite actors not implementing #ClutterContainer, or actors requiring
14032 * special handling when the text direction changes, should connect to
14033 * the #GObject::notify signal for the #ClutterActor:text-direction property
14038 clutter_actor_set_text_direction (ClutterActor *self,
14039 ClutterTextDirection text_dir)
14041 ClutterActorPrivate *priv;
14043 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14044 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14048 if (priv->text_direction != text_dir)
14050 priv->text_direction = text_dir;
14052 /* we need to emit the notify::text-direction first, so that
14053 * the sub-classes can catch that and do specific handling of
14054 * the text direction; see clutter_text_direction_changed_cb()
14055 * inside clutter-text.c
14057 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14059 _clutter_actor_foreach_child (self, set_direction_recursive,
14060 GINT_TO_POINTER (text_dir));
14062 clutter_actor_queue_relayout (self);
14067 _clutter_actor_set_has_pointer (ClutterActor *self,
14068 gboolean has_pointer)
14070 ClutterActorPrivate *priv = self->priv;
14072 if (priv->has_pointer != has_pointer)
14074 priv->has_pointer = has_pointer;
14076 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14081 * clutter_actor_get_text_direction:
14082 * @self: a #ClutterActor
14084 * Retrieves the value set using clutter_actor_set_text_direction()
14086 * If no text direction has been previously set, the default text
14087 * direction, as returned by clutter_get_default_text_direction(), will
14088 * be returned instead
14090 * Return value: the #ClutterTextDirection for the actor
14094 ClutterTextDirection
14095 clutter_actor_get_text_direction (ClutterActor *self)
14097 ClutterActorPrivate *priv;
14099 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14100 CLUTTER_TEXT_DIRECTION_LTR);
14104 /* if no direction has been set yet use the default */
14105 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14106 priv->text_direction = clutter_get_default_text_direction ();
14108 return priv->text_direction;
14112 * clutter_actor_push_internal:
14113 * @self: a #ClutterActor
14115 * Should be used by actors implementing the #ClutterContainer and with
14116 * internal children added through clutter_actor_set_parent(), for instance:
14120 * my_actor_init (MyActor *self)
14122 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14124 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14126 * /* calling clutter_actor_set_parent() now will result in
14127 * * the internal flag being set on a child of MyActor
14130 * /* internal child - a background texture */
14131 * self->priv->background_tex = clutter_texture_new ();
14132 * clutter_actor_set_parent (self->priv->background_tex,
14133 * CLUTTER_ACTOR (self));
14135 * /* internal child - a label */
14136 * self->priv->label = clutter_text_new ();
14137 * clutter_actor_set_parent (self->priv->label,
14138 * CLUTTER_ACTOR (self));
14140 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14142 * /* calling clutter_actor_set_parent() now will not result in
14143 * * the internal flag being set on a child of MyActor
14148 * This function will be used by Clutter to toggle an "internal child"
14149 * flag whenever clutter_actor_set_parent() is called; internal children
14150 * are handled differently by Clutter, specifically when destroying their
14153 * Call clutter_actor_pop_internal() when you finished adding internal
14156 * Nested calls to clutter_actor_push_internal() are allowed, but each
14157 * one must by followed by a clutter_actor_pop_internal() call.
14161 * Deprecated: 1.10: All children of an actor are accessible through
14162 * the #ClutterActor API, and #ClutterActor implements the
14163 * #ClutterContainer interface, so this function is only useful
14164 * for legacy containers overriding the default implementation.
14167 clutter_actor_push_internal (ClutterActor *self)
14169 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14171 self->priv->internal_child += 1;
14175 * clutter_actor_pop_internal:
14176 * @self: a #ClutterActor
14178 * Disables the effects of clutter_actor_push_internal().
14182 * Deprecated: 1.10: All children of an actor are accessible through
14183 * the #ClutterActor API. This function is only useful for legacy
14184 * containers overriding the default implementation of the
14185 * #ClutterContainer interface.
14188 clutter_actor_pop_internal (ClutterActor *self)
14190 ClutterActorPrivate *priv;
14192 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14196 if (priv->internal_child == 0)
14198 g_warning ("Mismatched %s: you need to call "
14199 "clutter_actor_push_composite() at least once before "
14200 "calling this function", G_STRFUNC);
14204 priv->internal_child -= 1;
14208 * clutter_actor_has_pointer:
14209 * @self: a #ClutterActor
14211 * Checks whether an actor contains the pointer of a
14212 * #ClutterInputDevice
14214 * Return value: %TRUE if the actor contains the pointer, and
14220 clutter_actor_has_pointer (ClutterActor *self)
14222 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14224 return self->priv->has_pointer;
14227 /* XXX: This is a workaround for not being able to break the ABI of
14228 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14229 * clutter_actor_queue_clipped_redraw() for details.
14231 ClutterPaintVolume *
14232 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14234 return g_object_get_data (G_OBJECT (self),
14235 "-clutter-actor-queue-redraw-clip");
14239 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14240 ClutterPaintVolume *clip)
14242 g_object_set_data (G_OBJECT (self),
14243 "-clutter-actor-queue-redraw-clip",
14248 * clutter_actor_has_allocation:
14249 * @self: a #ClutterActor
14251 * Checks if the actor has an up-to-date allocation assigned to
14252 * it. This means that the actor should have an allocation: it's
14253 * visible and has a parent. It also means that there is no
14254 * outstanding relayout request in progress for the actor or its
14255 * children (There might be other outstanding layout requests in
14256 * progress that will cause the actor to get a new allocation
14257 * when the stage is laid out, however).
14259 * If this function returns %FALSE, then the actor will normally
14260 * be allocated before it is next drawn on the screen.
14262 * Return value: %TRUE if the actor has an up-to-date allocation
14267 clutter_actor_has_allocation (ClutterActor *self)
14269 ClutterActorPrivate *priv;
14271 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14275 return priv->parent != NULL &&
14276 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14277 !priv->needs_allocation;
14281 * clutter_actor_add_action:
14282 * @self: a #ClutterActor
14283 * @action: a #ClutterAction
14285 * Adds @action to the list of actions applied to @self
14287 * A #ClutterAction can only belong to one actor at a time
14289 * The #ClutterActor will hold a reference on @action until either
14290 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14296 clutter_actor_add_action (ClutterActor *self,
14297 ClutterAction *action)
14299 ClutterActorPrivate *priv;
14301 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14302 g_return_if_fail (CLUTTER_IS_ACTION (action));
14306 if (priv->actions == NULL)
14308 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14309 priv->actions->actor = self;
14312 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14314 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14318 * clutter_actor_add_action_with_name:
14319 * @self: a #ClutterActor
14320 * @name: the name to set on the action
14321 * @action: a #ClutterAction
14323 * A convenience function for setting the name of a #ClutterAction
14324 * while adding it to the list of actions applied to @self
14326 * This function is the logical equivalent of:
14329 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14330 * clutter_actor_add_action (self, action);
14336 clutter_actor_add_action_with_name (ClutterActor *self,
14338 ClutterAction *action)
14340 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14341 g_return_if_fail (name != NULL);
14342 g_return_if_fail (CLUTTER_IS_ACTION (action));
14344 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14345 clutter_actor_add_action (self, action);
14349 * clutter_actor_remove_action:
14350 * @self: a #ClutterActor
14351 * @action: a #ClutterAction
14353 * Removes @action from the list of actions applied to @self
14355 * The reference held by @self on the #ClutterAction will be released
14360 clutter_actor_remove_action (ClutterActor *self,
14361 ClutterAction *action)
14363 ClutterActorPrivate *priv;
14365 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14366 g_return_if_fail (CLUTTER_IS_ACTION (action));
14370 if (priv->actions == NULL)
14373 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14375 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14379 * clutter_actor_remove_action_by_name:
14380 * @self: a #ClutterActor
14381 * @name: the name of the action to remove
14383 * Removes the #ClutterAction with the given name from the list
14384 * of actions applied to @self
14389 clutter_actor_remove_action_by_name (ClutterActor *self,
14392 ClutterActorPrivate *priv;
14393 ClutterActorMeta *meta;
14395 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14396 g_return_if_fail (name != NULL);
14400 if (priv->actions == NULL)
14403 meta = _clutter_meta_group_get_meta (priv->actions, name);
14407 _clutter_meta_group_remove_meta (priv->actions, meta);
14409 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14413 * clutter_actor_get_actions:
14414 * @self: a #ClutterActor
14416 * Retrieves the list of actions applied to @self
14418 * Return value: (transfer container) (element-type Clutter.Action): a copy
14419 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14420 * owned by the #ClutterActor. Use g_list_free() to free the resources
14421 * allocated by the returned #GList
14426 clutter_actor_get_actions (ClutterActor *self)
14428 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14430 if (self->priv->actions == NULL)
14433 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14437 * clutter_actor_get_action:
14438 * @self: a #ClutterActor
14439 * @name: the name of the action to retrieve
14441 * Retrieves the #ClutterAction with the given name in the list
14442 * of actions applied to @self
14444 * Return value: (transfer none): a #ClutterAction for the given
14445 * name, or %NULL. The returned #ClutterAction is owned by the
14446 * actor and it should not be unreferenced directly
14451 clutter_actor_get_action (ClutterActor *self,
14454 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14455 g_return_val_if_fail (name != NULL, NULL);
14457 if (self->priv->actions == NULL)
14460 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14464 * clutter_actor_clear_actions:
14465 * @self: a #ClutterActor
14467 * Clears the list of actions applied to @self
14472 clutter_actor_clear_actions (ClutterActor *self)
14474 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14476 if (self->priv->actions == NULL)
14479 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14483 * clutter_actor_add_constraint:
14484 * @self: a #ClutterActor
14485 * @constraint: a #ClutterConstraint
14487 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14490 * The #ClutterActor will hold a reference on the @constraint until
14491 * either clutter_actor_remove_constraint() or
14492 * clutter_actor_clear_constraints() is called.
14497 clutter_actor_add_constraint (ClutterActor *self,
14498 ClutterConstraint *constraint)
14500 ClutterActorPrivate *priv;
14502 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14503 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14507 if (priv->constraints == NULL)
14509 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14510 priv->constraints->actor = self;
14513 _clutter_meta_group_add_meta (priv->constraints,
14514 CLUTTER_ACTOR_META (constraint));
14515 clutter_actor_queue_relayout (self);
14517 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14521 * clutter_actor_add_constraint_with_name:
14522 * @self: a #ClutterActor
14523 * @name: the name to set on the constraint
14524 * @constraint: a #ClutterConstraint
14526 * A convenience function for setting the name of a #ClutterConstraint
14527 * while adding it to the list of constraints applied to @self
14529 * This function is the logical equivalent of:
14532 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14533 * clutter_actor_add_constraint (self, constraint);
14539 clutter_actor_add_constraint_with_name (ClutterActor *self,
14541 ClutterConstraint *constraint)
14543 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14544 g_return_if_fail (name != NULL);
14545 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14547 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14548 clutter_actor_add_constraint (self, constraint);
14552 * clutter_actor_remove_constraint:
14553 * @self: a #ClutterActor
14554 * @constraint: a #ClutterConstraint
14556 * Removes @constraint from the list of constraints applied to @self
14558 * The reference held by @self on the #ClutterConstraint will be released
14563 clutter_actor_remove_constraint (ClutterActor *self,
14564 ClutterConstraint *constraint)
14566 ClutterActorPrivate *priv;
14568 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14569 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14573 if (priv->constraints == NULL)
14576 _clutter_meta_group_remove_meta (priv->constraints,
14577 CLUTTER_ACTOR_META (constraint));
14578 clutter_actor_queue_relayout (self);
14580 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14584 * clutter_actor_remove_constraint_by_name:
14585 * @self: a #ClutterActor
14586 * @name: the name of the constraint to remove
14588 * Removes the #ClutterConstraint with the given name from the list
14589 * of constraints applied to @self
14594 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14597 ClutterActorPrivate *priv;
14598 ClutterActorMeta *meta;
14600 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14601 g_return_if_fail (name != NULL);
14605 if (priv->constraints == NULL)
14608 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14612 _clutter_meta_group_remove_meta (priv->constraints, meta);
14613 clutter_actor_queue_relayout (self);
14617 * clutter_actor_get_constraints:
14618 * @self: a #ClutterActor
14620 * Retrieves the list of constraints applied to @self
14622 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14623 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14624 * owned by the #ClutterActor. Use g_list_free() to free the resources
14625 * allocated by the returned #GList
14630 clutter_actor_get_constraints (ClutterActor *self)
14632 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14634 if (self->priv->constraints == NULL)
14637 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14641 * clutter_actor_get_constraint:
14642 * @self: a #ClutterActor
14643 * @name: the name of the constraint to retrieve
14645 * Retrieves the #ClutterConstraint with the given name in the list
14646 * of constraints applied to @self
14648 * Return value: (transfer none): a #ClutterConstraint for the given
14649 * name, or %NULL. The returned #ClutterConstraint is owned by the
14650 * actor and it should not be unreferenced directly
14654 ClutterConstraint *
14655 clutter_actor_get_constraint (ClutterActor *self,
14658 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14659 g_return_val_if_fail (name != NULL, NULL);
14661 if (self->priv->constraints == NULL)
14664 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14668 * clutter_actor_clear_constraints:
14669 * @self: a #ClutterActor
14671 * Clears the list of constraints applied to @self
14676 clutter_actor_clear_constraints (ClutterActor *self)
14678 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14680 if (self->priv->constraints == NULL)
14683 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14685 clutter_actor_queue_relayout (self);
14689 * clutter_actor_set_clip_to_allocation:
14690 * @self: a #ClutterActor
14691 * @clip_set: %TRUE to apply a clip tracking the allocation
14693 * Sets whether @self should be clipped to the same size as its
14699 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14702 ClutterActorPrivate *priv;
14704 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14706 clip_set = !!clip_set;
14710 if (priv->clip_to_allocation != clip_set)
14712 priv->clip_to_allocation = clip_set;
14714 clutter_actor_queue_redraw (self);
14716 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14721 * clutter_actor_get_clip_to_allocation:
14722 * @self: a #ClutterActor
14724 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14726 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14731 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14733 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14735 return self->priv->clip_to_allocation;
14739 * clutter_actor_add_effect:
14740 * @self: a #ClutterActor
14741 * @effect: a #ClutterEffect
14743 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14745 * The #ClutterActor will hold a reference on the @effect until either
14746 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14752 clutter_actor_add_effect (ClutterActor *self,
14753 ClutterEffect *effect)
14755 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14756 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14758 _clutter_actor_add_effect_internal (self, effect);
14760 clutter_actor_queue_redraw (self);
14762 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14766 * clutter_actor_add_effect_with_name:
14767 * @self: a #ClutterActor
14768 * @name: the name to set on the effect
14769 * @effect: a #ClutterEffect
14771 * A convenience function for setting the name of a #ClutterEffect
14772 * while adding it to the list of effectss applied to @self
14774 * This function is the logical equivalent of:
14777 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14778 * clutter_actor_add_effect (self, effect);
14784 clutter_actor_add_effect_with_name (ClutterActor *self,
14786 ClutterEffect *effect)
14788 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14789 g_return_if_fail (name != NULL);
14790 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14792 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14793 clutter_actor_add_effect (self, effect);
14797 * clutter_actor_remove_effect:
14798 * @self: a #ClutterActor
14799 * @effect: a #ClutterEffect
14801 * Removes @effect from the list of effects applied to @self
14803 * The reference held by @self on the #ClutterEffect will be released
14808 clutter_actor_remove_effect (ClutterActor *self,
14809 ClutterEffect *effect)
14811 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14812 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14814 _clutter_actor_remove_effect_internal (self, effect);
14816 clutter_actor_queue_redraw (self);
14818 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14822 * clutter_actor_remove_effect_by_name:
14823 * @self: a #ClutterActor
14824 * @name: the name of the effect to remove
14826 * Removes the #ClutterEffect with the given name from the list
14827 * of effects applied to @self
14832 clutter_actor_remove_effect_by_name (ClutterActor *self,
14835 ClutterActorPrivate *priv;
14836 ClutterActorMeta *meta;
14838 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14839 g_return_if_fail (name != NULL);
14843 if (priv->effects == NULL)
14846 meta = _clutter_meta_group_get_meta (priv->effects, name);
14850 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14854 * clutter_actor_get_effects:
14855 * @self: a #ClutterActor
14857 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14859 * Return value: (transfer container) (element-type Clutter.Effect): a list
14860 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14861 * list are owned by Clutter and they should not be freed. You should
14862 * free the returned list using g_list_free() when done
14867 clutter_actor_get_effects (ClutterActor *self)
14869 ClutterActorPrivate *priv;
14871 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14875 if (priv->effects == NULL)
14878 return _clutter_meta_group_get_metas_no_internal (priv->effects);
14882 * clutter_actor_get_effect:
14883 * @self: a #ClutterActor
14884 * @name: the name of the effect to retrieve
14886 * Retrieves the #ClutterEffect with the given name in the list
14887 * of effects applied to @self
14889 * Return value: (transfer none): a #ClutterEffect for the given
14890 * name, or %NULL. The returned #ClutterEffect is owned by the
14891 * actor and it should not be unreferenced directly
14896 clutter_actor_get_effect (ClutterActor *self,
14899 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14900 g_return_val_if_fail (name != NULL, NULL);
14902 if (self->priv->effects == NULL)
14905 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14909 * clutter_actor_clear_effects:
14910 * @self: a #ClutterActor
14912 * Clears the list of effects applied to @self
14917 clutter_actor_clear_effects (ClutterActor *self)
14919 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14921 if (self->priv->effects == NULL)
14924 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14926 clutter_actor_queue_redraw (self);
14930 * clutter_actor_has_key_focus:
14931 * @self: a #ClutterActor
14933 * Checks whether @self is the #ClutterActor that has key focus
14935 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14940 clutter_actor_has_key_focus (ClutterActor *self)
14942 ClutterActor *stage;
14944 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14946 stage = _clutter_actor_get_stage_internal (self);
14950 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14954 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14955 ClutterPaintVolume *pv)
14957 ClutterActorPrivate *priv = self->priv;
14959 /* Actors are only expected to report a valid paint volume
14960 * while they have a valid allocation. */
14961 if (G_UNLIKELY (priv->needs_allocation))
14963 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
14964 "Actor needs allocation",
14965 _clutter_actor_get_debug_name (self));
14969 /* Check if there are any handlers connected to the paint
14970 * signal. If there are then all bets are off for what the paint
14971 * volume for this actor might possibly be!
14973 * XXX: It's expected that this is going to end up being quite a
14974 * costly check to have to do here, but we haven't come up with
14975 * another solution that can reliably catch paint signal handlers at
14976 * the right time to either avoid artefacts due to invalid stage
14977 * clipping or due to incorrect culling.
14979 * Previously we checked in clutter_actor_paint(), but at that time
14980 * we may already be using a stage clip that could be derived from
14981 * an invalid paint-volume. We used to try and handle that by
14982 * queuing a follow up, unclipped, redraw but still the previous
14983 * checking wasn't enough to catch invalid volumes involved in
14984 * culling (considering that containers may derive their volume from
14985 * children that haven't yet been painted)
14987 * Longer term, improved solutions could be:
14988 * - Disallow painting in the paint signal, only allow using it
14989 * for tracking when paints happen. We can add another API that
14990 * allows monkey patching the paint of arbitrary actors but in a
14991 * more controlled way and that also supports modifying the
14993 * - If we could be notified somehow when signal handlers are
14994 * connected we wouldn't have to poll for handlers like this.
14996 if (g_signal_has_handler_pending (self,
14997 actor_signals[PAINT],
15001 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15002 "Actor has \"paint\" signal handlers",
15003 _clutter_actor_get_debug_name (self));
15007 _clutter_paint_volume_init_static (pv, self);
15009 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15011 clutter_paint_volume_free (pv);
15012 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15013 "Actor failed to report a volume",
15014 _clutter_actor_get_debug_name (self));
15018 /* since effects can modify the paint volume, we allow them to actually
15019 * do this by making get_paint_volume() "context sensitive"
15021 if (priv->effects != NULL)
15023 if (priv->current_effect != NULL)
15025 const GList *effects, *l;
15027 /* if we are being called from within the paint sequence of
15028 * an actor, get the paint volume up to the current effect
15030 effects = _clutter_meta_group_peek_metas (priv->effects);
15032 l != NULL || (l != NULL && l->data != priv->current_effect);
15035 if (!_clutter_effect_get_paint_volume (l->data, pv))
15037 clutter_paint_volume_free (pv);
15038 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15039 "Effect (%s) failed to report a volume",
15040 _clutter_actor_get_debug_name (self),
15041 _clutter_actor_meta_get_debug_name (l->data));
15048 const GList *effects, *l;
15050 /* otherwise, get the cumulative volume */
15051 effects = _clutter_meta_group_peek_metas (priv->effects);
15052 for (l = effects; l != NULL; l = l->next)
15053 if (!_clutter_effect_get_paint_volume (l->data, pv))
15055 clutter_paint_volume_free (pv);
15056 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15057 "Effect (%s) failed to report a volume",
15058 _clutter_actor_get_debug_name (self),
15059 _clutter_actor_meta_get_debug_name (l->data));
15068 /* The public clutter_actor_get_paint_volume API returns a const
15069 * pointer since we return a pointer directly to the cached
15070 * PaintVolume associated with the actor and don't want the user to
15071 * inadvertently modify it, but for internal uses we sometimes need
15072 * access to the same PaintVolume but need to apply some book-keeping
15073 * modifications to it so we don't want a const pointer.
15075 static ClutterPaintVolume *
15076 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15078 ClutterActorPrivate *priv;
15082 if (priv->paint_volume_valid)
15083 clutter_paint_volume_free (&priv->paint_volume);
15085 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15087 priv->paint_volume_valid = TRUE;
15088 return &priv->paint_volume;
15092 priv->paint_volume_valid = FALSE;
15098 * clutter_actor_get_paint_volume:
15099 * @self: a #ClutterActor
15101 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15102 * when a paint volume can't be determined.
15104 * The paint volume is defined as the 3D space occupied by an actor
15105 * when being painted.
15107 * This function will call the <function>get_paint_volume()</function>
15108 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15109 * should not usually care about overriding the default implementation,
15110 * unless they are, for instance: painting outside their allocation, or
15111 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15114 * <note>2D actors overriding <function>get_paint_volume()</function>
15115 * ensure their volume has a depth of 0. (This will be true so long as
15116 * you don't call clutter_paint_volume_set_depth().)</note>
15118 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15119 * or %NULL if no volume could be determined. The returned pointer
15120 * is not guaranteed to be valid across multiple frames; if you want
15121 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15125 const ClutterPaintVolume *
15126 clutter_actor_get_paint_volume (ClutterActor *self)
15128 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15130 return _clutter_actor_get_paint_volume_mutable (self);
15134 * clutter_actor_get_transformed_paint_volume:
15135 * @self: a #ClutterActor
15136 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15137 * (or %NULL for the stage)
15139 * Retrieves the 3D paint volume of an actor like
15140 * clutter_actor_get_paint_volume() does (Please refer to the
15141 * documentation of clutter_actor_get_paint_volume() for more
15142 * details.) and it additionally transforms the paint volume into the
15143 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15144 * is passed for @relative_to_ancestor)
15146 * This can be used by containers that base their paint volume on
15147 * the volume of their children. Such containers can query the
15148 * transformed paint volume of all of its children and union them
15149 * together using clutter_paint_volume_union().
15151 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15152 * or %NULL if no volume could be determined. The returned pointer is
15153 * not guaranteed to be valid across multiple frames; if you wish to
15154 * keep it, you will have to copy it using clutter_paint_volume_copy().
15158 const ClutterPaintVolume *
15159 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15160 ClutterActor *relative_to_ancestor)
15162 const ClutterPaintVolume *volume;
15163 ClutterActor *stage;
15164 ClutterPaintVolume *transformed_volume;
15166 stage = _clutter_actor_get_stage_internal (self);
15167 if (G_UNLIKELY (stage == NULL))
15170 if (relative_to_ancestor == NULL)
15171 relative_to_ancestor = stage;
15173 volume = clutter_actor_get_paint_volume (self);
15174 if (volume == NULL)
15177 transformed_volume =
15178 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15180 _clutter_paint_volume_copy_static (volume, transformed_volume);
15182 _clutter_paint_volume_transform_relative (transformed_volume,
15183 relative_to_ancestor);
15185 return transformed_volume;
15189 * clutter_actor_get_paint_box:
15190 * @self: a #ClutterActor
15191 * @box: (out): return location for a #ClutterActorBox
15193 * Retrieves the paint volume of the passed #ClutterActor, and
15194 * transforms it into a 2D bounding box in stage coordinates.
15196 * This function is useful to determine the on screen area occupied by
15197 * the actor. The box is only an approximation and may often be
15198 * considerably larger due to the optimizations used to calculate the
15199 * box. The box is never smaller though, so it can reliably be used
15202 * There are times when a 2D paint box can't be determined, e.g.
15203 * because the actor isn't yet parented under a stage or because
15204 * the actor is unable to determine a paint volume.
15206 * Return value: %TRUE if a 2D paint box could be determined, else
15212 clutter_actor_get_paint_box (ClutterActor *self,
15213 ClutterActorBox *box)
15215 ClutterActor *stage;
15216 ClutterPaintVolume *pv;
15218 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15219 g_return_val_if_fail (box != NULL, FALSE);
15221 stage = _clutter_actor_get_stage_internal (self);
15222 if (G_UNLIKELY (!stage))
15225 pv = _clutter_actor_get_paint_volume_mutable (self);
15226 if (G_UNLIKELY (!pv))
15229 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15235 * clutter_actor_has_overlaps:
15236 * @self: A #ClutterActor
15238 * Asks the actor's implementation whether it may contain overlapping
15241 * For example; Clutter may use this to determine whether the painting
15242 * should be redirected to an offscreen buffer to correctly implement
15243 * the opacity property.
15245 * Custom actors can override the default response by implementing the
15246 * #ClutterActor <function>has_overlaps</function> virtual function. See
15247 * clutter_actor_set_offscreen_redirect() for more information.
15249 * Return value: %TRUE if the actor may have overlapping primitives, and
15255 clutter_actor_has_overlaps (ClutterActor *self)
15257 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15259 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15263 * clutter_actor_has_effects:
15264 * @self: A #ClutterActor
15266 * Returns whether the actor has any effects applied.
15268 * Return value: %TRUE if the actor has any effects,
15274 clutter_actor_has_effects (ClutterActor *self)
15276 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15278 if (self->priv->effects == NULL)
15281 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15285 * clutter_actor_has_constraints:
15286 * @self: A #ClutterActor
15288 * Returns whether the actor has any constraints applied.
15290 * Return value: %TRUE if the actor has any constraints,
15296 clutter_actor_has_constraints (ClutterActor *self)
15298 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15300 return self->priv->constraints != NULL;
15304 * clutter_actor_has_actions:
15305 * @self: A #ClutterActor
15307 * Returns whether the actor has any actions applied.
15309 * Return value: %TRUE if the actor has any actions,
15315 clutter_actor_has_actions (ClutterActor *self)
15317 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15319 return self->priv->actions != NULL;
15323 * clutter_actor_get_n_children:
15324 * @self: a #ClutterActor
15326 * Retrieves the number of children of @self.
15328 * Return value: the number of children of an actor
15333 clutter_actor_get_n_children (ClutterActor *self)
15335 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15337 return self->priv->n_children;
15341 * clutter_actor_get_child_at_index:
15342 * @self: a #ClutterActor
15343 * @index_: the position in the list of children
15345 * Retrieves the actor at the given @index_ inside the list of
15346 * children of @self.
15348 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15353 clutter_actor_get_child_at_index (ClutterActor *self,
15356 ClutterActor *iter;
15359 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15360 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15362 for (iter = self->priv->first_child, i = 0;
15363 iter != NULL && i < index_;
15364 iter = iter->priv->next_sibling, i += 1)
15371 * _clutter_actor_foreach_child:
15372 * @actor: The actor whos children you want to iterate
15373 * @callback: The function to call for each child
15374 * @user_data: Private data to pass to @callback
15376 * Calls a given @callback once for each child of the specified @actor and
15377 * passing the @user_data pointer each time.
15379 * Return value: returns %TRUE if all children were iterated, else
15380 * %FALSE if a callback broke out of iteration early.
15383 _clutter_actor_foreach_child (ClutterActor *self,
15384 ClutterForeachCallback callback,
15385 gpointer user_data)
15387 ClutterActorPrivate *priv = self->priv;
15388 ClutterActor *iter;
15391 for (cont = TRUE, iter = priv->first_child;
15392 cont && iter != NULL;
15393 iter = iter->priv->next_sibling)
15395 cont = callback (iter, user_data);
15402 /* For debugging purposes this gives us a simple way to print out
15403 * the scenegraph e.g in gdb using:
15405 * _clutter_actor_traverse (stage,
15407 * clutter_debug_print_actor_cb,
15412 static ClutterActorTraverseVisitFlags
15413 clutter_debug_print_actor_cb (ClutterActor *actor,
15417 g_print ("%*s%s:%p\n",
15419 _clutter_actor_get_debug_name (actor),
15422 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15427 _clutter_actor_traverse_breadth (ClutterActor *actor,
15428 ClutterTraverseCallback callback,
15429 gpointer user_data)
15431 GQueue *queue = g_queue_new ();
15432 ClutterActor dummy;
15433 int current_depth = 0;
15435 g_queue_push_tail (queue, actor);
15436 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15438 while ((actor = g_queue_pop_head (queue)))
15440 ClutterActorTraverseVisitFlags flags;
15442 if (actor == &dummy)
15445 g_queue_push_tail (queue, &dummy);
15449 flags = callback (actor, current_depth, user_data);
15450 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15452 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15454 ClutterActor *iter;
15456 for (iter = actor->priv->first_child;
15458 iter = iter->priv->next_sibling)
15460 g_queue_push_tail (queue, iter);
15465 g_queue_free (queue);
15468 static ClutterActorTraverseVisitFlags
15469 _clutter_actor_traverse_depth (ClutterActor *actor,
15470 ClutterTraverseCallback before_children_callback,
15471 ClutterTraverseCallback after_children_callback,
15473 gpointer user_data)
15475 ClutterActorTraverseVisitFlags flags;
15477 flags = before_children_callback (actor, current_depth, user_data);
15478 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15479 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15481 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15483 ClutterActor *iter;
15485 for (iter = actor->priv->first_child;
15487 iter = iter->priv->next_sibling)
15489 flags = _clutter_actor_traverse_depth (iter,
15490 before_children_callback,
15491 after_children_callback,
15495 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15496 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15500 if (after_children_callback)
15501 return after_children_callback (actor, current_depth, user_data);
15503 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15506 /* _clutter_actor_traverse:
15507 * @actor: The actor to start traversing the graph from
15508 * @flags: These flags may affect how the traversal is done
15509 * @before_children_callback: A function to call before visiting the
15510 * children of the current actor.
15511 * @after_children_callback: A function to call after visiting the
15512 * children of the current actor. (Ignored if
15513 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15514 * @user_data: The private data to pass to the callbacks
15516 * Traverses the scenegraph starting at the specified @actor and
15517 * descending through all its children and its children's children.
15518 * For each actor traversed @before_children_callback and
15519 * @after_children_callback are called with the specified
15520 * @user_data, before and after visiting that actor's children.
15522 * The callbacks can return flags that affect the ongoing traversal
15523 * such as by skipping over an actors children or bailing out of
15524 * any further traversing.
15527 _clutter_actor_traverse (ClutterActor *actor,
15528 ClutterActorTraverseFlags flags,
15529 ClutterTraverseCallback before_children_callback,
15530 ClutterTraverseCallback after_children_callback,
15531 gpointer user_data)
15533 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15534 _clutter_actor_traverse_breadth (actor,
15535 before_children_callback,
15537 else /* DEPTH_FIRST */
15538 _clutter_actor_traverse_depth (actor,
15539 before_children_callback,
15540 after_children_callback,
15541 0, /* start depth */
15546 on_layout_manager_changed (ClutterLayoutManager *manager,
15547 ClutterActor *self)
15549 clutter_actor_queue_relayout (self);
15553 * clutter_actor_set_layout_manager:
15554 * @self: a #ClutterActor
15555 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15557 * Sets the #ClutterLayoutManager delegate object that will be used to
15558 * lay out the children of @self.
15560 * The #ClutterActor will take a reference on the passed @manager which
15561 * will be released either when the layout manager is removed, or when
15562 * the actor is destroyed.
15567 clutter_actor_set_layout_manager (ClutterActor *self,
15568 ClutterLayoutManager *manager)
15570 ClutterActorPrivate *priv;
15572 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15573 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15577 if (priv->layout_manager != NULL)
15579 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15580 G_CALLBACK (on_layout_manager_changed),
15582 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15583 g_object_unref (priv->layout_manager);
15586 priv->layout_manager = manager;
15588 if (priv->layout_manager != NULL)
15590 g_object_ref_sink (priv->layout_manager);
15591 clutter_layout_manager_set_container (priv->layout_manager,
15592 CLUTTER_CONTAINER (self));
15593 g_signal_connect (priv->layout_manager, "layout-changed",
15594 G_CALLBACK (on_layout_manager_changed),
15598 clutter_actor_queue_relayout (self);
15600 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15604 * clutter_actor_get_layout_manager:
15605 * @self: a #ClutterActor
15607 * Retrieves the #ClutterLayoutManager used by @self.
15609 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15614 ClutterLayoutManager *
15615 clutter_actor_get_layout_manager (ClutterActor *self)
15617 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15619 return self->priv->layout_manager;
15622 static const ClutterLayoutInfo default_layout_info = {
15625 { 0, 0, 0, 0 }, /* margin */
15626 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15627 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15628 0.f, 0.f, /* min_width, natural_width */
15629 0.f, 0.f, /* natual_width, natural_height */
15633 layout_info_free (gpointer data)
15635 if (G_LIKELY (data != NULL))
15636 g_slice_free (ClutterLayoutInfo, data);
15640 * _clutter_actor_get_layout_info:
15641 * @self: a #ClutterActor
15643 * Retrieves a pointer to the ClutterLayoutInfo structure.
15645 * If the actor does not have a ClutterLayoutInfo associated to it, one
15646 * will be created and initialized to the default values.
15648 * This function should be used for setters.
15650 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15653 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15655 ClutterLayoutInfo *
15656 _clutter_actor_get_layout_info (ClutterActor *self)
15658 ClutterLayoutInfo *retval;
15660 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15661 if (retval == NULL)
15663 retval = g_slice_new (ClutterLayoutInfo);
15665 *retval = default_layout_info;
15667 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15676 * _clutter_actor_get_layout_info_or_defaults:
15677 * @self: a #ClutterActor
15679 * Retrieves the ClutterLayoutInfo structure associated to an actor.
15681 * If the actor does not have a ClutterLayoutInfo structure associated to it,
15682 * then the default structure will be returned.
15684 * This function should only be used for getters.
15686 * Return value: a const pointer to the ClutterLayoutInfo structure
15688 const ClutterLayoutInfo *
15689 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15691 const ClutterLayoutInfo *info;
15693 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15695 return &default_layout_info;
15701 * clutter_actor_set_x_align:
15702 * @self: a #ClutterActor
15703 * @x_align: the horizontal alignment policy
15705 * Sets the horizontal alignment policy of a #ClutterActor, in case the
15706 * actor received extra horizontal space.
15708 * See also the #ClutterActor:x-align property.
15713 clutter_actor_set_x_align (ClutterActor *self,
15714 ClutterActorAlign x_align)
15716 ClutterLayoutInfo *info;
15718 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15720 info = _clutter_actor_get_layout_info (self);
15722 if (info->x_align != x_align)
15724 info->x_align = x_align;
15726 clutter_actor_queue_relayout (self);
15728 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15733 * clutter_actor_get_x_align:
15734 * @self: a #ClutterActor
15736 * Retrieves the horizontal alignment policy set using
15737 * clutter_actor_set_x_align().
15739 * Return value: the horizontal alignment policy.
15744 clutter_actor_get_x_align (ClutterActor *self)
15746 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15748 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15752 * clutter_actor_set_y_align:
15753 * @self: a #ClutterActor
15754 * @y_align: the vertical alignment policy
15756 * Sets the vertical alignment policy of a #ClutterActor, in case the
15757 * actor received extra vertical space.
15759 * See also the #ClutterActor:y-align property.
15764 clutter_actor_set_y_align (ClutterActor *self,
15765 ClutterActorAlign y_align)
15767 ClutterLayoutInfo *info;
15769 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15771 info = _clutter_actor_get_layout_info (self);
15773 if (info->y_align != y_align)
15775 info->y_align = y_align;
15777 clutter_actor_queue_relayout (self);
15779 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15784 * clutter_actor_get_y_align:
15785 * @self: a #ClutterActor
15787 * Retrieves the vertical alignment policy set using
15788 * clutter_actor_set_y_align().
15790 * Return value: the vertical alignment policy.
15795 clutter_actor_get_y_align (ClutterActor *self)
15797 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15799 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15804 * clutter_margin_new:
15806 * Creates a new #ClutterMargin.
15808 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15809 * clutter_margin_free() to free the resources associated with it when
15815 clutter_margin_new (void)
15817 return g_slice_new0 (ClutterMargin);
15821 * clutter_margin_copy:
15822 * @margin_: a #ClutterMargin
15824 * Creates a new #ClutterMargin and copies the contents of @margin_ into
15825 * the newly created structure.
15827 * Return value: (transfer full): a copy of the #ClutterMargin.
15832 clutter_margin_copy (const ClutterMargin *margin_)
15834 if (G_LIKELY (margin_ != NULL))
15835 return g_slice_dup (ClutterMargin, margin_);
15841 * clutter_margin_free:
15842 * @margin_: a #ClutterMargin
15844 * Frees the resources allocated by clutter_margin_new() and
15845 * clutter_margin_copy().
15850 clutter_margin_free (ClutterMargin *margin_)
15852 if (G_LIKELY (margin_ != NULL))
15853 g_slice_free (ClutterMargin, margin_);
15856 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15857 clutter_margin_copy,
15858 clutter_margin_free)
15861 * clutter_actor_set_margin:
15862 * @self: a #ClutterActor
15863 * @margin: a #ClutterMargin
15865 * Sets all the components of the margin of a #ClutterActor.
15870 clutter_actor_set_margin (ClutterActor *self,
15871 const ClutterMargin *margin)
15873 ClutterLayoutInfo *info;
15877 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15878 g_return_if_fail (margin != NULL);
15880 obj = G_OBJECT (self);
15883 g_object_freeze_notify (obj);
15885 info = _clutter_actor_get_layout_info (self);
15887 if (info->margin.top != margin->top)
15889 info->margin.top = margin->top;
15890 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15894 if (info->margin.right != margin->right)
15896 info->margin.right = margin->right;
15897 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15901 if (info->margin.bottom != margin->bottom)
15903 info->margin.bottom = margin->bottom;
15904 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15908 if (info->margin.left != margin->left)
15910 info->margin.left = margin->left;
15911 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15916 clutter_actor_queue_relayout (self);
15918 g_object_thaw_notify (obj);
15922 * clutter_actor_get_margin:
15923 * @self: a #ClutterActor
15924 * @margin: (out caller-allocates): return location for a #ClutterMargin
15926 * Retrieves all the components of the margin of a #ClutterActor.
15931 clutter_actor_get_margin (ClutterActor *self,
15932 ClutterMargin *margin)
15934 const ClutterLayoutInfo *info;
15936 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15937 g_return_if_fail (margin != NULL);
15939 info = _clutter_actor_get_layout_info_or_defaults (self);
15941 *margin = info->margin;
15945 * clutter_actor_set_margin_top:
15946 * @self: a #ClutterActor
15947 * @margin: the top margin
15949 * Sets the margin from the top of a #ClutterActor.
15954 clutter_actor_set_margin_top (ClutterActor *self,
15957 ClutterLayoutInfo *info;
15959 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15960 g_return_if_fail (margin >= 0.f);
15962 info = _clutter_actor_get_layout_info (self);
15964 if (info->margin.top == margin)
15967 info->margin.top = margin;
15969 clutter_actor_queue_relayout (self);
15971 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
15975 * clutter_actor_get_margin_top:
15976 * @self: a #ClutterActor
15978 * Retrieves the top margin of a #ClutterActor.
15980 * Return value: the top margin
15985 clutter_actor_get_margin_top (ClutterActor *self)
15987 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
15989 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
15993 * clutter_actor_set_margin_bottom:
15994 * @self: a #ClutterActor
15995 * @margin: the bottom margin
15997 * Sets the margin from the bottom of a #ClutterActor.
16002 clutter_actor_set_margin_bottom (ClutterActor *self,
16005 ClutterLayoutInfo *info;
16007 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16008 g_return_if_fail (margin >= 0.f);
16010 info = _clutter_actor_get_layout_info (self);
16012 if (info->margin.bottom == margin)
16015 info->margin.bottom = margin;
16017 clutter_actor_queue_relayout (self);
16019 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16023 * clutter_actor_get_margin_bottom:
16024 * @self: a #ClutterActor
16026 * Retrieves the bottom margin of a #ClutterActor.
16028 * Return value: the bottom margin
16033 clutter_actor_get_margin_bottom (ClutterActor *self)
16035 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16037 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16041 * clutter_actor_set_margin_left:
16042 * @self: a #ClutterActor
16043 * @margin: the left margin
16045 * Sets the margin from the left of a #ClutterActor.
16050 clutter_actor_set_margin_left (ClutterActor *self,
16053 ClutterLayoutInfo *info;
16055 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16056 g_return_if_fail (margin >= 0.f);
16058 info = _clutter_actor_get_layout_info (self);
16060 if (info->margin.left == margin)
16063 info->margin.left = margin;
16065 clutter_actor_queue_relayout (self);
16067 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16071 * clutter_actor_get_margin_left:
16072 * @self: a #ClutterActor
16074 * Retrieves the left margin of a #ClutterActor.
16076 * Return value: the left margin
16081 clutter_actor_get_margin_left (ClutterActor *self)
16083 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16085 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16089 * clutter_actor_set_margin_right:
16090 * @self: a #ClutterActor
16091 * @margin: the right margin
16093 * Sets the margin from the right of a #ClutterActor.
16098 clutter_actor_set_margin_right (ClutterActor *self,
16101 ClutterLayoutInfo *info;
16103 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16104 g_return_if_fail (margin >= 0.f);
16106 info = _clutter_actor_get_layout_info (self);
16108 if (info->margin.right == margin)
16111 info->margin.right = margin;
16113 clutter_actor_queue_relayout (self);
16115 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16119 * clutter_actor_get_margin_right:
16120 * @self: a #ClutterActor
16122 * Retrieves the right margin of a #ClutterActor.
16124 * Return value: the right margin
16129 clutter_actor_get_margin_right (ClutterActor *self)
16131 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16133 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16137 clutter_actor_set_background_color_internal (ClutterActor *self,
16138 const ClutterColor *color)
16140 ClutterActorPrivate *priv = self->priv;
16143 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16146 obj = G_OBJECT (self);
16148 priv->bg_color = *color;
16149 priv->bg_color_set = TRUE;
16151 clutter_actor_queue_redraw (self);
16153 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16154 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16158 * clutter_actor_set_background_color:
16159 * @self: a #ClutterActor
16160 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16163 * Sets the background color of a #ClutterActor.
16165 * The background color will be used to cover the whole allocation of the
16166 * actor. The default background color of an actor is transparent.
16168 * To check whether an actor has a background color, you can use the
16169 * #ClutterActor:background-color-set actor property.
16171 * The #ClutterActor:background-color property is animatable.
16176 clutter_actor_set_background_color (ClutterActor *self,
16177 const ClutterColor *color)
16179 ClutterActorPrivate *priv;
16181 GParamSpec *bg_color_pspec;
16183 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16185 obj = G_OBJECT (self);
16191 priv->bg_color_set = FALSE;
16192 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16193 clutter_actor_queue_redraw (self);
16197 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16198 if (clutter_actor_get_easing_duration (self) != 0)
16200 ClutterTransition *transition;
16202 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16203 if (transition == NULL)
16205 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16208 clutter_timeline_start (CLUTTER_TIMELINE (transition));
16211 _clutter_actor_update_transition (self, bg_color_pspec, color);
16213 clutter_actor_queue_redraw (self);
16216 clutter_actor_set_background_color_internal (self, color);
16220 * clutter_actor_get_background_color:
16221 * @self: a #ClutterActor
16222 * @color: (out caller-allocates): return location for a #ClutterColor
16224 * Retrieves the color set using clutter_actor_set_background_color().
16229 clutter_actor_get_background_color (ClutterActor *self,
16230 ClutterColor *color)
16232 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16233 g_return_if_fail (color != NULL);
16235 *color = self->priv->bg_color;
16239 * clutter_actor_get_previous_sibling:
16240 * @self: a #ClutterActor
16242 * Retrieves the sibling of @self that comes before it in the list
16243 * of children of @self's parent.
16245 * The returned pointer is only valid until the scene graph changes; it
16246 * is not safe to modify the list of children of @self while iterating
16249 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16254 clutter_actor_get_previous_sibling (ClutterActor *self)
16256 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16258 return self->priv->prev_sibling;
16262 * clutter_actor_get_next_sibling:
16263 * @self: a #ClutterActor
16265 * Retrieves the sibling of @self that comes after it in the list
16266 * of children of @self's parent.
16268 * The returned pointer is only valid until the scene graph changes; it
16269 * is not safe to modify the list of children of @self while iterating
16272 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16277 clutter_actor_get_next_sibling (ClutterActor *self)
16279 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16281 return self->priv->next_sibling;
16285 * clutter_actor_get_first_child:
16286 * @self: a #ClutterActor
16288 * Retrieves the first child of @self.
16290 * The returned pointer is only valid until the scene graph changes; it
16291 * is not safe to modify the list of children of @self while iterating
16294 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16299 clutter_actor_get_first_child (ClutterActor *self)
16301 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16303 return self->priv->first_child;
16307 * clutter_actor_get_last_child:
16308 * @self: a #ClutterActor
16310 * Retrieves the last child of @self.
16312 * The returned pointer is only valid until the scene graph changes; it
16313 * is not safe to modify the list of children of @self while iterating
16316 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16321 clutter_actor_get_last_child (ClutterActor *self)
16323 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16325 return self->priv->last_child;
16328 /* easy way to have properly named fields instead of the dummy ones
16329 * we use in the public structure
16331 typedef struct _RealActorIter
16333 ClutterActor *root; /* dummy1 */
16334 ClutterActor *current; /* dummy2 */
16335 gpointer padding_1; /* dummy3 */
16336 gint age; /* dummy4 */
16337 gpointer padding_2; /* dummy5 */
16341 * clutter_actor_iter_init:
16342 * @iter: a #ClutterActorIter
16343 * @root: a #ClutterActor
16345 * Initializes a #ClutterActorIter, which can then be used to iterate
16346 * efficiently over a section of the scene graph, and associates it
16349 * Modifying the scene graph section that contains @root will invalidate
16353 * ClutterActorIter iter;
16354 * ClutterActor *child;
16356 * clutter_actor_iter_init (&iter, container);
16357 * while (clutter_actor_iter_next (&iter, &child))
16359 * /* do something with child */
16366 clutter_actor_iter_init (ClutterActorIter *iter,
16367 ClutterActor *root)
16369 RealActorIter *ri = (RealActorIter *) iter;
16371 g_return_if_fail (iter != NULL);
16372 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16375 ri->current = NULL;
16376 ri->age = root->priv->age;
16380 * clutter_actor_iter_next:
16381 * @iter: a #ClutterActorIter
16382 * @child: (out): return location for a #ClutterActor
16384 * Advances the @iter and retrieves the next child of the root #ClutterActor
16385 * that was used to initialize the #ClutterActorIterator.
16387 * If the iterator can advance, this function returns %TRUE and sets the
16390 * If the iterator cannot advance, this function returns %FALSE, and
16391 * the contents of @child are undefined.
16393 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16398 clutter_actor_iter_next (ClutterActorIter *iter,
16399 ClutterActor **child)
16401 RealActorIter *ri = (RealActorIter *) iter;
16403 g_return_val_if_fail (iter != NULL, FALSE);
16404 g_return_val_if_fail (ri->root != NULL, FALSE);
16405 #ifndef G_DISABLE_ASSERT
16406 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16409 if (ri->current == NULL)
16410 ri->current = ri->root->priv->first_child;
16412 ri->current = ri->current->priv->next_sibling;
16415 *child = ri->current;
16417 return ri->current != NULL;
16421 * clutter_actor_iter_prev:
16422 * @iter: a #ClutterActorIter
16423 * @child: (out): return location for a #ClutterActor
16425 * Advances the @iter and retrieves the previous child of the root
16426 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16428 * If the iterator can advance, this function returns %TRUE and sets the
16431 * If the iterator cannot advance, this function returns %FALSE, and
16432 * the contents of @child are undefined.
16434 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16439 clutter_actor_iter_prev (ClutterActorIter *iter,
16440 ClutterActor **child)
16442 RealActorIter *ri = (RealActorIter *) iter;
16444 g_return_val_if_fail (iter != NULL, FALSE);
16445 g_return_val_if_fail (ri->root != NULL, FALSE);
16446 #ifndef G_DISABLE_ASSERT
16447 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16450 if (ri->current == NULL)
16451 ri->current = ri->root->priv->last_child;
16453 ri->current = ri->current->priv->prev_sibling;
16456 *child = ri->current;
16458 return ri->current != NULL;
16462 * clutter_actor_iter_remove:
16463 * @iter: a #ClutterActorIter
16465 * Safely removes the #ClutterActor currently pointer to by the iterator
16468 * This function can only be called after clutter_actor_iter_next() or
16469 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16470 * than once for the same actor.
16472 * This function will call clutter_actor_remove_child() internally.
16477 clutter_actor_iter_remove (ClutterActorIter *iter)
16479 RealActorIter *ri = (RealActorIter *) iter;
16482 g_return_if_fail (iter != NULL);
16483 g_return_if_fail (ri->root != NULL);
16484 #ifndef G_DISABLE_ASSERT
16485 g_return_if_fail (ri->age == ri->root->priv->age);
16487 g_return_if_fail (ri->current != NULL);
16493 ri->current = cur->priv->prev_sibling;
16495 clutter_actor_remove_child_internal (ri->root, cur,
16496 REMOVE_CHILD_DEFAULT_FLAGS);
16503 * clutter_actor_iter_destroy:
16504 * @iter: a #ClutterActorIter
16506 * Safely destroys the #ClutterActor currently pointer to by the iterator
16509 * This function can only be called after clutter_actor_iter_next() or
16510 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16511 * than once for the same actor.
16513 * This function will call clutter_actor_destroy() internally.
16518 clutter_actor_iter_destroy (ClutterActorIter *iter)
16520 RealActorIter *ri = (RealActorIter *) iter;
16523 g_return_if_fail (iter != NULL);
16524 g_return_if_fail (ri->root != NULL);
16525 #ifndef G_DISABLE_ASSERT
16526 g_return_if_fail (ri->age == ri->root->priv->age);
16528 g_return_if_fail (ri->current != NULL);
16534 ri->current = cur->priv->prev_sibling;
16536 clutter_actor_destroy (cur);
16542 static const ClutterAnimationInfo default_animation_info = {
16543 NULL, /* transitions */
16545 NULL, /* cur_state */
16549 clutter_animation_info_free (gpointer data)
16553 ClutterAnimationInfo *info = data;
16555 if (info->transitions != NULL)
16556 g_hash_table_unref (info->transitions);
16558 if (info->states != NULL)
16559 g_array_unref (info->states);
16561 g_slice_free (ClutterAnimationInfo, info);
16565 const ClutterAnimationInfo *
16566 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16568 const ClutterAnimationInfo *res;
16569 GObject *obj = G_OBJECT (self);
16571 res = g_object_get_qdata (obj, quark_actor_animation_info);
16575 return &default_animation_info;
16578 ClutterAnimationInfo *
16579 _clutter_actor_get_animation_info (ClutterActor *self)
16581 GObject *obj = G_OBJECT (self);
16582 ClutterAnimationInfo *res;
16584 res = g_object_get_qdata (obj, quark_actor_animation_info);
16587 res = g_slice_new (ClutterAnimationInfo);
16589 *res = default_animation_info;
16591 g_object_set_qdata_full (obj, quark_actor_animation_info,
16593 clutter_animation_info_free);
16599 ClutterTransition *
16600 _clutter_actor_get_transition (ClutterActor *actor,
16603 const ClutterAnimationInfo *info;
16605 info = _clutter_actor_get_animation_info_or_defaults (actor);
16607 if (info->transitions == NULL)
16610 return g_hash_table_lookup (info->transitions, pspec->name);
16613 typedef struct _TransitionClosure
16615 ClutterActor *actor;
16616 ClutterTransition *transition;
16617 GParamSpec *property;
16618 gulong completed_id;
16619 } TransitionClosure;
16622 on_transition_completed (ClutterTransition *transition,
16623 TransitionClosure *clos)
16625 ClutterAnimationInfo *info;
16627 info = _clutter_actor_get_animation_info (clos->actor);
16629 g_hash_table_remove (info->transitions, clos->property->name);
16631 g_signal_handler_disconnect (transition, clos->completed_id);
16633 g_slice_free (TransitionClosure, clos);
16637 _clutter_actor_update_transition (ClutterActor *actor,
16641 ClutterTransition *transition;
16642 ClutterInterval *interval;
16643 const ClutterAnimationInfo *info;
16646 GValue initial = G_VALUE_INIT;
16647 GValue final = G_VALUE_INIT;
16648 char *error = NULL;
16650 info = _clutter_actor_get_animation_info_or_defaults (actor);
16652 if (info->transitions == NULL)
16655 transition = g_hash_table_lookup (info->transitions, pspec->name);
16656 if (transition == NULL)
16659 va_start (var_args, pspec);
16661 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16663 g_value_init (&initial, ptype);
16664 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16668 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16671 g_critical ("%s: %s", G_STRLOC, error);
16676 interval = clutter_transition_get_interval (transition);
16677 clutter_interval_set_initial_value (interval, &initial);
16678 clutter_interval_set_final_value (interval, &final);
16680 clutter_timeline_rewind (CLUTTER_TIMELINE (transition));
16683 g_value_unset (&initial);
16684 g_value_unset (&final);
16690 * _clutter_actor_create_transition:
16691 * @actor: a #ClutterActor
16692 * @pspec: the property used for the transition
16693 * @...: initial and final state
16695 * Creates a #ClutterTransition for the property represented by @pspec.
16697 * Return value: a #ClutterTransition
16699 ClutterTransition *
16700 _clutter_actor_create_transition (ClutterActor *actor,
16704 ClutterAnimationInfo *info;
16705 ClutterTransition *res = NULL;
16706 gboolean call_restore = FALSE;
16709 info = _clutter_actor_get_animation_info (actor);
16711 if (info->states == NULL)
16713 clutter_actor_save_easing_state (actor);
16714 call_restore = TRUE;
16717 if (info->transitions == NULL)
16718 info->transitions = g_hash_table_new (g_str_hash, g_str_equal);
16720 va_start (var_args, pspec);
16722 res = g_hash_table_lookup (info->transitions, pspec->name);
16725 ClutterInterval *interval;
16726 GValue initial = G_VALUE_INIT;
16727 GValue final = G_VALUE_INIT;
16730 TransitionClosure *clos;
16732 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16734 G_VALUE_COLLECT_INIT (&initial, ptype,
16739 g_critical ("%s: %s", G_STRLOC, error);
16744 G_VALUE_COLLECT_INIT (&final, ptype,
16750 g_critical ("%s: %s", G_STRLOC, error);
16751 g_value_unset (&initial);
16756 interval = clutter_interval_new_with_values (ptype, &initial, &final);
16758 g_value_unset (&initial);
16759 g_value_unset (&final);
16761 res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
16764 clutter_transition_set_interval (res, interval);
16765 clutter_transition_set_remove_on_complete (res, TRUE);
16767 clutter_timeline_set_duration (CLUTTER_TIMELINE (res),
16768 info->cur_state->easing_duration);
16769 clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (res),
16770 info->cur_state->easing_mode);
16772 clos = g_slice_new (TransitionClosure);
16773 clos->actor = actor;
16774 clos->transition = res;
16775 clos->property = pspec;
16776 clos->completed_id =
16777 g_signal_connect (res, "completed",
16778 G_CALLBACK (on_transition_completed),
16781 g_hash_table_insert (info->transitions, (gpointer) pspec->name, res);
16786 clutter_actor_restore_easing_state (actor);
16794 * clutter_actor_set_easing_duration:
16795 * @self: a #ClutterActor
16796 * @msecs: the duration of the easing, or %NULL
16798 * Sets the duration of the tweening for animatable properties
16799 * of @self for the current easing state.
16801 * Calling this function will implicitly call
16802 * clutter_actor_save_easing_state() if no previous call to
16803 * that function was made.
16808 clutter_actor_set_easing_duration (ClutterActor *self,
16811 ClutterAnimationInfo *info;
16813 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16815 info = _clutter_actor_get_animation_info (self);
16817 if (info->states == NULL)
16818 clutter_actor_save_easing_state (self);
16820 if (info->cur_state->easing_duration != msecs)
16821 info->cur_state->easing_duration = msecs;
16825 * clutter_actor_get_easing_duration:
16826 * @self: a #ClutterActor
16828 * Retrieves the duration of the tweening for animatable
16829 * properties of @self for the current easing state.
16831 * Return value: the duration of the tweening, in milliseconds
16836 clutter_actor_get_easing_duration (ClutterActor *self)
16838 const ClutterAnimationInfo *info;
16840 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
16842 info = _clutter_actor_get_animation_info_or_defaults (self);
16844 if (info->cur_state != NULL)
16845 return info->cur_state->easing_duration;
16851 * clutter_actor_set_easing_mode:
16852 * @self: a #ClutterActor
16853 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
16855 * Sets the easing mode for the tweening of animatable properties
16858 * Calling this function will implicitly call
16859 * clutter_actor_save_easing_state() if no previous calls to
16860 * that function were made.
16865 clutter_actor_set_easing_mode (ClutterActor *self,
16866 ClutterAnimationMode mode)
16868 ClutterAnimationInfo *info;
16870 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16871 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
16872 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
16874 info = _clutter_actor_get_animation_info (self);
16876 if (info->states == NULL)
16877 clutter_actor_save_easing_state (self);
16879 if (info->cur_state->easing_mode != mode)
16880 info->cur_state->easing_mode = mode;
16884 * clutter_actor_get_easing_mode:
16885 * @self: a #ClutterActor
16887 * Retrieves the easing mode for the tweening of animatable properties
16888 * of @self for the current easing state.
16890 * Return value: an easing mode
16894 ClutterAnimationMode
16895 clutter_actor_get_easing_mode (ClutterActor *self)
16897 const ClutterAnimationInfo *info;
16899 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
16901 info = _clutter_actor_get_animation_info_or_defaults (self);
16903 if (info->cur_state != NULL)
16904 return info->cur_state->easing_mode;
16906 return CLUTTER_EASE_OUT_CUBIC;
16910 * clutter_actor_get_transition:
16911 * @self: a #ClutterActor
16912 * @name: the name of the transition
16914 * Retrieves the #ClutterTransition of a #ClutterActor by using the
16915 * transition @name.
16917 * Transitions created for animatable properties use the name of the
16918 * property itself, for instance the code below:
16921 * clutter_actor_set_easing_duration (actor, 1000);
16922 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
16924 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
16925 * g_signal_connect (transition, "completed",
16926 * G_CALLBACK (on_transition_complete),
16930 * will call the <function>on_transition_complete</function> callback when
16931 * the transition is complete.
16933 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
16934 * was found to match the passed name; the returned instance is owned
16935 * by Clutter and it should not be freed
16939 ClutterTransition *
16940 clutter_actor_get_transition (ClutterActor *self,
16943 const ClutterAnimationInfo *info;
16945 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16946 g_return_val_if_fail (name != NULL, NULL);
16948 info = _clutter_actor_get_animation_info_or_defaults (self);
16950 if (info->transitions == NULL)
16953 return g_hash_table_lookup (info->transitions, name);
16957 * clutter_actor_save_easing_state:
16958 * @self: a #ClutterActor
16960 * Saves the current easing state for animatable properties, and creates
16961 * a new state with the default values for easing mode and duration.
16966 clutter_actor_save_easing_state (ClutterActor *self)
16968 ClutterAnimationInfo *info;
16971 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16973 info = _clutter_actor_get_animation_info (self);
16975 if (info->states == NULL)
16976 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
16978 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
16979 new_state.easing_duration = 250;
16981 g_array_append_val (info->states, new_state);
16983 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
16987 * clutter_actor_restore_easing_state:
16988 * @self: a #ClutterActor
16990 * Restores the easing state as it was prior to a call to
16991 * clutter_actor_save_easing_state().
16996 clutter_actor_restore_easing_state (ClutterActor *self)
16998 ClutterAnimationInfo *info;
17000 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17002 info = _clutter_actor_get_animation_info (self);
17004 if (info->states == NULL)
17006 g_critical ("The function clutter_actor_restore_easing_state() has "
17007 "called without a previous call to "
17008 "clutter_actor_save_easing_state().");
17012 g_array_remove_index (info->states, info->states->len - 1);
17013 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);