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 * <para>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-nodes.h"
392 #include "clutter-paint-node-private.h"
393 #include "clutter-paint-volume-private.h"
394 #include "clutter-private.h"
395 #include "clutter-profile.h"
396 #include "clutter-property-transition.h"
397 #include "clutter-scriptable.h"
398 #include "clutter-script-private.h"
399 #include "clutter-stage-private.h"
400 #include "clutter-timeline.h"
401 #include "clutter-transition.h"
402 #include "clutter-units.h"
404 #include "deprecated/clutter-actor.h"
405 #include "deprecated/clutter-behaviour.h"
406 #include "deprecated/clutter-container.h"
408 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
409 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
411 /* Internal enum used to control mapped state update. This is a hint
412 * which indicates when to do something other than just enforce
416 MAP_STATE_CHECK, /* just enforce invariants. */
417 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
418 * used when about to unparent.
420 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
421 * used to set mapped on toplevels.
423 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
424 * used just before unmapping parent.
428 /* 3 entries should be a good compromise, few layout managers
429 * will ask for 3 different preferred size in each allocation cycle */
430 #define N_CACHED_SIZE_REQUESTS 3
432 struct _ClutterActorPrivate
435 ClutterRequestMode request_mode;
437 /* our cached size requests for different width / height */
438 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
439 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
441 /* An age of 0 means the entry is not set */
442 guint cached_height_age;
443 guint cached_width_age;
445 /* the bounding box of the actor, relative to the parent's
448 ClutterActorBox allocation;
449 ClutterAllocationFlags allocation_flags;
451 /* clip, in actor coordinates */
452 cairo_rectangle_t clip;
454 /* the cached transformation matrix; see apply_transform() */
455 CoglMatrix transform;
458 gint opacity_override;
460 ClutterOffscreenRedirect offscreen_redirect;
462 /* This is an internal effect used to implement the
463 offscreen-redirect property */
464 ClutterEffect *flatten_effect;
467 ClutterActor *parent;
468 ClutterActor *prev_sibling;
469 ClutterActor *next_sibling;
470 ClutterActor *first_child;
471 ClutterActor *last_child;
475 /* tracks whenever the children of an actor are changed; the
476 * age is incremented by 1 whenever an actor is added or
477 * removed. the age is not incremented when the first or the
478 * last child pointers are changed, or when grandchildren of
479 * an actor are changed.
483 gchar *name; /* a non-unique name, used for debugging */
484 guint32 id; /* unique id, used for backward compatibility */
486 gint32 pick_id; /* per-stage unique id, used for picking */
488 /* a back-pointer to the Pango context that we can use
489 * to create pre-configured PangoLayout
491 PangoContext *pango_context;
493 /* the text direction configured for this child - either by
494 * application code, or by the actor's parent
496 ClutterTextDirection text_direction;
498 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
502 ClutterMetaGroup *actions;
503 ClutterMetaGroup *constraints;
504 ClutterMetaGroup *effects;
506 /* delegate object used to allocate the children of this actor */
507 ClutterLayoutManager *layout_manager;
509 /* used when painting, to update the paint volume */
510 ClutterEffect *current_effect;
512 /* This is used to store an effect which needs to be redrawn. A
513 redraw can be queued to start from a particular effect. This is
514 used by parametrised effects that can cache an image of the
515 actor. If a parameter of the effect changes then it only needs to
516 redraw the cached image, not the actual actor. The pointer is
517 only valid if is_dirty == TRUE. If the pointer is NULL then the
518 whole actor is dirty. */
519 ClutterEffect *effect_to_redraw;
521 /* This is used when painting effects to implement the
522 clutter_actor_continue_paint() function. It points to the node in
523 the list of effects that is next in the chain */
524 const GList *next_effect_to_paint;
526 ClutterPaintVolume paint_volume;
528 /* NB: This volume isn't relative to this actor, it is in eye
529 * coordinates so that it can remain valid after the actor changes.
531 ClutterPaintVolume last_paint_volume;
533 ClutterStageQueueRedrawEntry *queue_redraw_entry;
535 ClutterColor bg_color;
539 /* fixed position and sizes */
540 guint position_set : 1;
541 guint min_width_set : 1;
542 guint min_height_set : 1;
543 guint natural_width_set : 1;
544 guint natural_height_set : 1;
545 /* cached request is invalid (implies allocation is too) */
546 guint needs_width_request : 1;
547 /* cached request is invalid (implies allocation is too) */
548 guint needs_height_request : 1;
549 /* cached allocation is invalid (request has changed, probably) */
550 guint needs_allocation : 1;
551 guint show_on_set_parent : 1;
553 guint clip_to_allocation : 1;
554 guint enable_model_view_transform : 1;
555 guint enable_paint_unmapped : 1;
556 guint has_pointer : 1;
557 guint propagated_one_redraw : 1;
558 guint paint_volume_valid : 1;
559 guint last_paint_volume_valid : 1;
560 guint in_clone_paint : 1;
561 guint transform_valid : 1;
562 /* This is TRUE if anything has queued a redraw since we were last
563 painted. In this case effect_to_redraw will point to an effect
564 the redraw was queued from or it will be NULL if the redraw was
565 queued without an effect. */
567 guint bg_color_set : 1;
576 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
577 * when set they force a size request, when gotten they
578 * get the allocation if the allocation is valid, and the
586 /* Then the rest of these size-related properties are the "actual"
587 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
592 PROP_FIXED_POSITION_SET,
601 PROP_NATURAL_WIDTH_SET,
604 PROP_NATURAL_HEIGHT_SET,
608 /* Allocation properties are read-only */
615 PROP_CLIP_TO_ALLOCATION,
619 PROP_OFFSCREEN_REDIRECT,
632 PROP_ROTATION_ANGLE_X,
633 PROP_ROTATION_ANGLE_Y,
634 PROP_ROTATION_ANGLE_Z,
635 PROP_ROTATION_CENTER_X,
636 PROP_ROTATION_CENTER_Y,
637 PROP_ROTATION_CENTER_Z,
638 /* This property only makes sense for the z rotation because the
639 others would depend on the actor having a size along the
641 PROP_ROTATION_CENTER_Z_GRAVITY,
647 PROP_SHOW_ON_SET_PARENT,
665 PROP_BACKGROUND_COLOR,
666 PROP_BACKGROUND_COLOR_SET,
674 static GParamSpec *obj_props[PROP_LAST];
693 BUTTON_RELEASE_EVENT,
705 static guint actor_signals[LAST_SIGNAL] = { 0, };
707 static void clutter_container_iface_init (ClutterContainerIface *iface);
708 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
709 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
710 static void atk_implementor_iface_init (AtkImplementorIface *iface);
712 /* These setters are all static for now, maybe they should be in the
713 * public API, but they are perhaps obscure enough to leave only as
716 static void clutter_actor_set_min_width (ClutterActor *self,
718 static void clutter_actor_set_min_height (ClutterActor *self,
720 static void clutter_actor_set_natural_width (ClutterActor *self,
721 gfloat natural_width);
722 static void clutter_actor_set_natural_height (ClutterActor *self,
723 gfloat natural_height);
724 static void clutter_actor_set_min_width_set (ClutterActor *self,
725 gboolean use_min_width);
726 static void clutter_actor_set_min_height_set (ClutterActor *self,
727 gboolean use_min_height);
728 static void clutter_actor_set_natural_width_set (ClutterActor *self,
729 gboolean use_natural_width);
730 static void clutter_actor_set_natural_height_set (ClutterActor *self,
731 gboolean use_natural_height);
732 static void clutter_actor_update_map_state (ClutterActor *self,
733 MapStateChange change);
734 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
736 /* Helper routines for managing anchor coords */
737 static void clutter_anchor_coord_get_units (ClutterActor *self,
738 const AnchorCoord *coord,
742 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
747 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
748 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
749 ClutterGravity gravity);
751 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
753 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
755 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
756 ClutterActor *ancestor,
759 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
761 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
763 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
764 const ClutterColor *color);
766 static void on_layout_manager_changed (ClutterLayoutManager *manager,
769 /* Helper macro which translates by the anchor coord, applies the
770 given transformation and then translates back */
771 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
772 gfloat _tx, _ty, _tz; \
773 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
774 cogl_matrix_translate ((m), _tx, _ty, _tz); \
776 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
778 static GQuark quark_shader_data = 0;
779 static GQuark quark_actor_layout_info = 0;
780 static GQuark quark_actor_transform_info = 0;
781 static GQuark quark_actor_animation_info = 0;
783 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
785 G_TYPE_INITIALLY_UNOWNED,
786 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
787 clutter_container_iface_init)
788 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
789 clutter_scriptable_iface_init)
790 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
791 clutter_animatable_iface_init)
792 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
793 atk_implementor_iface_init));
796 * clutter_actor_get_debug_name:
797 * @actor: a #ClutterActor
799 * Retrieves a printable name of @actor for debugging messages
801 * Return value: a string with a printable name
804 _clutter_actor_get_debug_name (ClutterActor *actor)
806 return actor->priv->name != NULL ? actor->priv->name
807 : G_OBJECT_TYPE_NAME (actor);
810 #ifdef CLUTTER_ENABLE_DEBUG
811 /* XXX - this is for debugging only, remove once working (or leave
812 * in only in some debug mode). Should leave it for a little while
813 * until we're confident in the new map/realize/visible handling.
816 clutter_actor_verify_map_state (ClutterActor *self)
818 ClutterActorPrivate *priv = self->priv;
820 if (CLUTTER_ACTOR_IS_REALIZED (self))
822 /* all bets are off during reparent when we're potentially realized,
823 * but should not be according to invariants
825 if (!CLUTTER_ACTOR_IN_REPARENT (self))
827 if (priv->parent == NULL)
829 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
833 g_warning ("Realized non-toplevel actor '%s' should "
835 _clutter_actor_get_debug_name (self));
837 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
839 g_warning ("Realized actor %s has an unrealized parent %s",
840 _clutter_actor_get_debug_name (self),
841 _clutter_actor_get_debug_name (priv->parent));
846 if (CLUTTER_ACTOR_IS_MAPPED (self))
848 if (!CLUTTER_ACTOR_IS_REALIZED (self))
849 g_warning ("Actor '%s' is mapped but not realized",
850 _clutter_actor_get_debug_name (self));
852 /* remaining bets are off during reparent when we're potentially
853 * mapped, but should not be according to invariants
855 if (!CLUTTER_ACTOR_IN_REPARENT (self))
857 if (priv->parent == NULL)
859 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
861 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
862 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
864 g_warning ("Toplevel actor '%s' is mapped "
866 _clutter_actor_get_debug_name (self));
871 g_warning ("Mapped actor '%s' should have a parent",
872 _clutter_actor_get_debug_name (self));
877 ClutterActor *iter = self;
879 /* check for the enable_paint_unmapped flag on the actor
880 * and parents; if the flag is enabled at any point of this
881 * branch of the scene graph then all the later checks
886 if (iter->priv->enable_paint_unmapped)
889 iter = iter->priv->parent;
892 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
894 g_warning ("Actor '%s' should not be mapped if parent '%s'"
896 _clutter_actor_get_debug_name (self),
897 _clutter_actor_get_debug_name (priv->parent));
900 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
902 g_warning ("Actor '%s' should not be mapped if parent '%s'"
904 _clutter_actor_get_debug_name (self),
905 _clutter_actor_get_debug_name (priv->parent));
908 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
910 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
911 g_warning ("Actor '%s' is mapped but its non-toplevel "
912 "parent '%s' is not mapped",
913 _clutter_actor_get_debug_name (self),
914 _clutter_actor_get_debug_name (priv->parent));
921 #endif /* CLUTTER_ENABLE_DEBUG */
924 clutter_actor_set_mapped (ClutterActor *self,
927 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
932 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
933 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
937 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
938 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
942 /* this function updates the mapped and realized states according to
943 * invariants, in the appropriate order.
946 clutter_actor_update_map_state (ClutterActor *self,
947 MapStateChange change)
951 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
953 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
955 /* the mapped flag on top-level actors must be set by the
956 * per-backend implementation because it might be asynchronous.
958 * That is, the MAPPED flag on toplevels currently tracks the X
959 * server mapped-ness of the window, while the expected behavior
960 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
961 * This creates some weird complexity by breaking the invariant
962 * that if we're visible and all ancestors shown then we are
963 * also mapped - instead, we are mapped if all ancestors
964 * _possibly excepting_ the stage are mapped. The stage
965 * will map/unmap for example when it is minimized or
966 * moved to another workspace.
968 * So, the only invariant on the stage is that if visible it
969 * should be realized, and that it has to be visible to be
972 if (CLUTTER_ACTOR_IS_VISIBLE (self))
973 clutter_actor_realize (self);
977 case MAP_STATE_CHECK:
980 case MAP_STATE_MAKE_MAPPED:
981 g_assert (!was_mapped);
982 clutter_actor_set_mapped (self, TRUE);
985 case MAP_STATE_MAKE_UNMAPPED:
986 g_assert (was_mapped);
987 clutter_actor_set_mapped (self, FALSE);
990 case MAP_STATE_MAKE_UNREALIZED:
991 /* we only use MAKE_UNREALIZED in unparent,
992 * and unparenting a stage isn't possible.
993 * If someone wants to just unrealize a stage
994 * then clutter_actor_unrealize() doesn't
995 * go through this codepath.
997 g_warning ("Trying to force unrealize stage is not allowed");
1001 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1002 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1003 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1005 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1006 "it is somehow still mapped",
1007 _clutter_actor_get_debug_name (self));
1012 ClutterActorPrivate *priv = self->priv;
1013 ClutterActor *parent = priv->parent;
1014 gboolean should_be_mapped;
1015 gboolean may_be_realized;
1016 gboolean must_be_realized;
1018 should_be_mapped = FALSE;
1019 may_be_realized = TRUE;
1020 must_be_realized = FALSE;
1022 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1024 may_be_realized = FALSE;
1028 /* Maintain invariant that if parent is mapped, and we are
1029 * visible, then we are mapped ... unless parent is a
1030 * stage, in which case we map regardless of parent's map
1031 * state but do require stage to be visible and realized.
1033 * If parent is realized, that does not force us to be
1034 * realized; but if parent is unrealized, that does force
1035 * us to be unrealized.
1037 * The reason we don't force children to realize with
1038 * parents is _clutter_actor_rerealize(); if we require that
1039 * a realized parent means children are realized, then to
1040 * unrealize an actor we would have to unrealize its
1041 * parents, which would end up meaning unrealizing and
1042 * hiding the entire stage. So we allow unrealizing a
1043 * child (as long as that child is not mapped) while that
1044 * child still has a realized parent.
1046 * Also, if we unrealize from leaf nodes to root, and
1047 * realize from root to leaf, the invariants are never
1048 * violated if we allow children to be unrealized
1049 * while parents are realized.
1051 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1052 * to force us to unmap, even though parent is still
1053 * mapped. This is because we're unmapping from leaf nodes
1056 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1057 change != MAP_STATE_MAKE_UNMAPPED)
1059 gboolean parent_is_visible_realized_toplevel;
1061 parent_is_visible_realized_toplevel =
1062 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1063 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1064 CLUTTER_ACTOR_IS_REALIZED (parent));
1066 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1067 parent_is_visible_realized_toplevel)
1069 must_be_realized = TRUE;
1070 should_be_mapped = TRUE;
1074 /* if the actor has been set to be painted even if unmapped
1075 * then we should map it and check for realization as well;
1076 * this is an override for the branch of the scene graph
1077 * which begins with this node
1079 if (priv->enable_paint_unmapped)
1081 if (priv->parent == NULL)
1082 g_warning ("Attempting to map an unparented actor '%s'",
1083 _clutter_actor_get_debug_name (self));
1085 should_be_mapped = TRUE;
1086 must_be_realized = TRUE;
1089 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1090 may_be_realized = FALSE;
1093 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1096 g_warning ("Attempting to map a child that does not "
1097 "meet the necessary invariants: the actor '%s' "
1099 _clutter_actor_get_debug_name (self));
1101 g_warning ("Attempting to map a child that does not "
1102 "meet the necessary invariants: the actor '%s' "
1103 "is parented to an unmapped actor '%s'",
1104 _clutter_actor_get_debug_name (self),
1105 _clutter_actor_get_debug_name (priv->parent));
1108 /* If in reparent, we temporarily suspend unmap and unrealize.
1110 * We want to go in the order "realize, map" and "unmap, unrealize"
1114 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1115 clutter_actor_set_mapped (self, FALSE);
1118 if (must_be_realized)
1119 clutter_actor_realize (self);
1121 /* if we must be realized then we may be, presumably */
1122 g_assert (!(must_be_realized && !may_be_realized));
1125 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1126 clutter_actor_unrealize_not_hiding (self);
1129 if (should_be_mapped)
1131 if (!must_be_realized)
1132 g_warning ("Somehow we think actor '%s' should be mapped but "
1133 "not realized, which isn't allowed",
1134 _clutter_actor_get_debug_name (self));
1136 /* realization is allowed to fail (though I don't know what
1137 * an app is supposed to do about that - shouldn't it just
1138 * be a g_error? anyway, we have to avoid mapping if this
1141 if (CLUTTER_ACTOR_IS_REALIZED (self))
1142 clutter_actor_set_mapped (self, TRUE);
1146 #ifdef CLUTTER_ENABLE_DEBUG
1147 /* check all invariants were kept */
1148 clutter_actor_verify_map_state (self);
1153 clutter_actor_real_map (ClutterActor *self)
1155 ClutterActorPrivate *priv = self->priv;
1156 ClutterActor *stage, *iter;
1158 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1160 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1161 _clutter_actor_get_debug_name (self));
1163 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1165 stage = _clutter_actor_get_stage_internal (self);
1166 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1168 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1170 _clutter_actor_get_debug_name (self));
1172 /* notify on parent mapped before potentially mapping
1173 * children, so apps see a top-down notification.
1175 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1177 for (iter = self->priv->first_child;
1179 iter = iter->priv->next_sibling)
1181 clutter_actor_map (iter);
1186 * clutter_actor_map:
1187 * @self: A #ClutterActor
1189 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1190 * and realizes its children if they are visible. Does nothing if the
1191 * actor is not visible.
1193 * Calling this function is strongly disencouraged: the default
1194 * implementation of #ClutterActorClass.map() will map all the children
1195 * of an actor when mapping its parent.
1197 * When overriding map, it is mandatory to chain up to the parent
1203 clutter_actor_map (ClutterActor *self)
1205 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1207 if (CLUTTER_ACTOR_IS_MAPPED (self))
1210 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1213 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1217 clutter_actor_real_unmap (ClutterActor *self)
1219 ClutterActorPrivate *priv = self->priv;
1222 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1224 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1225 _clutter_actor_get_debug_name (self));
1227 for (iter = self->priv->first_child;
1229 iter = iter->priv->next_sibling)
1231 clutter_actor_unmap (iter);
1234 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1236 /* clear the contents of the last paint volume, so that hiding + moving +
1237 * showing will not result in the wrong area being repainted
1239 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1240 priv->last_paint_volume_valid = TRUE;
1242 /* notify on parent mapped after potentially unmapping
1243 * children, so apps see a bottom-up notification.
1245 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1247 /* relinquish keyboard focus if we were unmapped while owning it */
1248 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1250 ClutterStage *stage;
1252 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1255 _clutter_stage_release_pick_id (stage, priv->pick_id);
1259 if (stage != NULL &&
1260 clutter_stage_get_key_focus (stage) == self)
1262 clutter_stage_set_key_focus (stage, NULL);
1268 * clutter_actor_unmap:
1269 * @self: A #ClutterActor
1271 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1272 * unmaps its children if they were mapped.
1274 * Calling this function is not encouraged: the default #ClutterActor
1275 * implementation of #ClutterActorClass.unmap() will also unmap any
1276 * eventual children by default when their parent is unmapped.
1278 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1279 * chain up to the parent implementation.
1281 * <note>It is important to note that the implementation of the
1282 * #ClutterActorClass.unmap() virtual function may be called after
1283 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1284 * implementation, but it is guaranteed to be called before the
1285 * #GObjectClass.finalize() implementation.</note>
1290 clutter_actor_unmap (ClutterActor *self)
1292 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1294 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1297 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1301 clutter_actor_real_show (ClutterActor *self)
1303 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1305 ClutterActorPrivate *priv = self->priv;
1307 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1309 /* we notify on the "visible" flag in the clutter_actor_show()
1310 * wrapper so the entire show signal emission completes first
1313 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1315 /* we queue a relayout unless the actor is inside a
1316 * container that explicitly told us not to
1318 if (priv->parent != NULL &&
1319 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1321 /* While an actor is hidden the parent may not have
1322 * allocated/requested so we need to start from scratch
1323 * and avoid the short-circuiting in
1324 * clutter_actor_queue_relayout().
1326 priv->needs_width_request = FALSE;
1327 priv->needs_height_request = FALSE;
1328 priv->needs_allocation = FALSE;
1329 clutter_actor_queue_relayout (self);
1335 set_show_on_set_parent (ClutterActor *self,
1338 ClutterActorPrivate *priv = self->priv;
1340 set_show = !!set_show;
1342 if (priv->show_on_set_parent == set_show)
1345 if (priv->parent == NULL)
1347 priv->show_on_set_parent = set_show;
1348 g_object_notify_by_pspec (G_OBJECT (self),
1349 obj_props[PROP_SHOW_ON_SET_PARENT]);
1354 * clutter_actor_show:
1355 * @self: A #ClutterActor
1357 * Flags an actor to be displayed. An actor that isn't shown will not
1358 * be rendered on the stage.
1360 * Actors are visible by default.
1362 * If this function is called on an actor without a parent, the
1363 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1367 clutter_actor_show (ClutterActor *self)
1369 ClutterActorPrivate *priv;
1371 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1373 /* simple optimization */
1374 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1376 /* we still need to set the :show-on-set-parent property, in
1377 * case show() is called on an unparented actor
1379 set_show_on_set_parent (self, TRUE);
1383 #ifdef CLUTTER_ENABLE_DEBUG
1384 clutter_actor_verify_map_state (self);
1389 g_object_freeze_notify (G_OBJECT (self));
1391 set_show_on_set_parent (self, TRUE);
1393 g_signal_emit (self, actor_signals[SHOW], 0);
1394 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1396 if (priv->parent != NULL)
1397 clutter_actor_queue_redraw (priv->parent);
1399 g_object_thaw_notify (G_OBJECT (self));
1403 * clutter_actor_show_all:
1404 * @self: a #ClutterActor
1406 * Calls clutter_actor_show() on all children of an actor (if any).
1410 * Deprecated: 1.10: Actors are visible by default
1413 clutter_actor_show_all (ClutterActor *self)
1415 ClutterActorClass *klass;
1417 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1419 klass = CLUTTER_ACTOR_GET_CLASS (self);
1420 if (klass->show_all)
1421 klass->show_all (self);
1425 clutter_actor_real_hide (ClutterActor *self)
1427 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1429 ClutterActorPrivate *priv = self->priv;
1431 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1433 /* we notify on the "visible" flag in the clutter_actor_hide()
1434 * wrapper so the entire hide signal emission completes first
1437 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1439 /* we queue a relayout unless the actor is inside a
1440 * container that explicitly told us not to
1442 if (priv->parent != NULL &&
1443 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1444 clutter_actor_queue_relayout (priv->parent);
1449 * clutter_actor_hide:
1450 * @self: A #ClutterActor
1452 * Flags an actor to be hidden. A hidden actor will not be
1453 * rendered on the stage.
1455 * Actors are visible by default.
1457 * If this function is called on an actor without a parent, the
1458 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1462 clutter_actor_hide (ClutterActor *self)
1464 ClutterActorPrivate *priv;
1466 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1468 /* simple optimization */
1469 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1471 /* we still need to set the :show-on-set-parent property, in
1472 * case hide() is called on an unparented actor
1474 set_show_on_set_parent (self, FALSE);
1478 #ifdef CLUTTER_ENABLE_DEBUG
1479 clutter_actor_verify_map_state (self);
1484 g_object_freeze_notify (G_OBJECT (self));
1486 set_show_on_set_parent (self, FALSE);
1488 g_signal_emit (self, actor_signals[HIDE], 0);
1489 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1491 if (priv->parent != NULL)
1492 clutter_actor_queue_redraw (priv->parent);
1494 g_object_thaw_notify (G_OBJECT (self));
1498 * clutter_actor_hide_all:
1499 * @self: a #ClutterActor
1501 * Calls clutter_actor_hide() on all child actors (if any).
1505 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1506 * prevent its children from being painted as well.
1509 clutter_actor_hide_all (ClutterActor *self)
1511 ClutterActorClass *klass;
1513 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1515 klass = CLUTTER_ACTOR_GET_CLASS (self);
1516 if (klass->hide_all)
1517 klass->hide_all (self);
1521 * clutter_actor_realize:
1522 * @self: A #ClutterActor
1524 * Realization informs the actor that it is attached to a stage. It
1525 * can use this to allocate resources if it wanted to delay allocation
1526 * until it would be rendered. However it is perfectly acceptable for
1527 * an actor to create resources before being realized because Clutter
1528 * only ever has a single rendering context so that actor is free to
1529 * be moved from one stage to another.
1531 * This function does nothing if the actor is already realized.
1533 * Because a realized actor must have realized parent actors, calling
1534 * clutter_actor_realize() will also realize all parents of the actor.
1536 * This function does not realize child actors, except in the special
1537 * case that realizing the stage, when the stage is visible, will
1538 * suddenly map (and thus realize) the children of the stage.
1541 clutter_actor_realize (ClutterActor *self)
1543 ClutterActorPrivate *priv;
1545 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1549 #ifdef CLUTTER_ENABLE_DEBUG
1550 clutter_actor_verify_map_state (self);
1553 if (CLUTTER_ACTOR_IS_REALIZED (self))
1556 /* To be realized, our parent actors must be realized first.
1557 * This will only succeed if we're inside a toplevel.
1559 if (priv->parent != NULL)
1560 clutter_actor_realize (priv->parent);
1562 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1564 /* toplevels can be realized at any time */
1568 /* "Fail" the realization if parent is missing or unrealized;
1569 * this should really be a g_warning() not some kind of runtime
1570 * failure; how can an app possibly recover? Instead it's a bug
1571 * in the app and the app should get an explanatory warning so
1572 * someone can fix it. But for now it's too hard to fix this
1573 * because e.g. ClutterTexture needs reworking.
1575 if (priv->parent == NULL ||
1576 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1580 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1582 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1583 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1585 g_signal_emit (self, actor_signals[REALIZE], 0);
1587 /* Stage actor is allowed to unset the realized flag again in its
1588 * default signal handler, though that is a pathological situation.
1591 /* If realization "failed" we'll have to update child state. */
1592 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1596 clutter_actor_real_unrealize (ClutterActor *self)
1598 /* we must be unmapped (implying our children are also unmapped) */
1599 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1603 * clutter_actor_unrealize:
1604 * @self: A #ClutterActor
1606 * Unrealization informs the actor that it may be being destroyed or
1607 * moved to another stage. The actor may want to destroy any
1608 * underlying graphics resources at this point. However it is
1609 * perfectly acceptable for it to retain the resources until the actor
1610 * is destroyed because Clutter only ever uses a single rendering
1611 * context and all of the graphics resources are valid on any stage.
1613 * Because mapped actors must be realized, actors may not be
1614 * unrealized if they are mapped. This function hides the actor to be
1615 * sure it isn't mapped, an application-visible side effect that you
1616 * may not be expecting.
1618 * This function should not be called by application code.
1621 clutter_actor_unrealize (ClutterActor *self)
1623 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1624 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1626 /* This function should not really be in the public API, because
1627 * there isn't a good reason to call it. ClutterActor will already
1628 * unrealize things for you when it's important to do so.
1630 * If you were using clutter_actor_unrealize() in a dispose
1631 * implementation, then don't, just chain up to ClutterActor's
1634 * If you were using clutter_actor_unrealize() to implement
1635 * unrealizing children of your container, then don't, ClutterActor
1636 * will already take care of that.
1638 * If you were using clutter_actor_unrealize() to re-realize to
1639 * create your resources in a different way, then use
1640 * _clutter_actor_rerealize() (inside Clutter) or just call your
1641 * code that recreates your resources directly (outside Clutter).
1644 #ifdef CLUTTER_ENABLE_DEBUG
1645 clutter_actor_verify_map_state (self);
1648 clutter_actor_hide (self);
1650 clutter_actor_unrealize_not_hiding (self);
1653 static ClutterActorTraverseVisitFlags
1654 unrealize_actor_before_children_cb (ClutterActor *self,
1658 /* If an actor is already unrealized we know its children have also
1659 * already been unrealized... */
1660 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1661 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1663 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1665 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1668 static ClutterActorTraverseVisitFlags
1669 unrealize_actor_after_children_cb (ClutterActor *self,
1673 /* We want to unset the realized flag only _after_
1674 * child actors are unrealized, to maintain invariants.
1676 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1677 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1678 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1682 * clutter_actor_unrealize_not_hiding:
1683 * @self: A #ClutterActor
1685 * Unrealization informs the actor that it may be being destroyed or
1686 * moved to another stage. The actor may want to destroy any
1687 * underlying graphics resources at this point. However it is
1688 * perfectly acceptable for it to retain the resources until the actor
1689 * is destroyed because Clutter only ever uses a single rendering
1690 * context and all of the graphics resources are valid on any stage.
1692 * Because mapped actors must be realized, actors may not be
1693 * unrealized if they are mapped. You must hide the actor or one of
1694 * its parents before attempting to unrealize.
1696 * This function is separate from clutter_actor_unrealize() because it
1697 * does not automatically hide the actor.
1698 * Actors need not be hidden to be unrealized, they just need to
1699 * be unmapped. In fact we don't want to mess up the application's
1700 * setting of the "visible" flag, so hiding is very undesirable.
1702 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1703 * backward compatibility.
1706 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1708 _clutter_actor_traverse (self,
1709 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1710 unrealize_actor_before_children_cb,
1711 unrealize_actor_after_children_cb,
1716 * _clutter_actor_rerealize:
1717 * @self: A #ClutterActor
1718 * @callback: Function to call while unrealized
1719 * @data: data for callback
1721 * If an actor is already unrealized, this just calls the callback.
1723 * If it is realized, it unrealizes temporarily, calls the callback,
1724 * and then re-realizes the actor.
1726 * As a side effect, leaves all children of the actor unrealized if
1727 * the actor was realized but not showing. This is because when we
1728 * unrealize the actor temporarily we must unrealize its children
1729 * (e.g. children of a stage can't be realized if stage window is
1730 * gone). And we aren't clever enough to save the realization state of
1731 * all children. In most cases this should not matter, because
1732 * the children will automatically realize when they next become mapped.
1735 _clutter_actor_rerealize (ClutterActor *self,
1736 ClutterCallback callback,
1739 gboolean was_mapped;
1740 gboolean was_showing;
1741 gboolean was_realized;
1743 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1745 #ifdef CLUTTER_ENABLE_DEBUG
1746 clutter_actor_verify_map_state (self);
1749 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1750 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1751 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1753 /* Must be unmapped to unrealize. Note we only have to hide this
1754 * actor if it was mapped (if all parents were showing). If actor
1755 * is merely visible (but not mapped), then that's fine, we can
1759 clutter_actor_hide (self);
1761 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1763 /* unrealize self and all children */
1764 clutter_actor_unrealize_not_hiding (self);
1766 if (callback != NULL)
1768 (* callback) (self, data);
1772 clutter_actor_show (self); /* will realize only if mapping implies it */
1773 else if (was_realized)
1774 clutter_actor_realize (self); /* realize self and all parents */
1778 clutter_actor_real_pick (ClutterActor *self,
1779 const ClutterColor *color)
1781 /* the default implementation is just to paint a rectangle
1782 * with the same size of the actor using the passed color
1784 if (clutter_actor_should_pick_paint (self))
1786 ClutterActorBox box = { 0, };
1787 float width, height;
1789 clutter_actor_get_allocation_box (self, &box);
1791 width = box.x2 - box.x1;
1792 height = box.y2 - box.y1;
1794 cogl_set_source_color4ub (color->red,
1799 cogl_rectangle (0, 0, width, height);
1802 /* XXX - this thoroughly sucks, but we need to maintain compatibility
1803 * with existing container classes that override the pick() virtual
1804 * and chain up to the default implementation - otherwise we'll end up
1805 * painting our children twice.
1807 * this has to go away for 2.0; hopefully along the pick() itself.
1809 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1813 for (iter = self->priv->first_child;
1815 iter = iter->priv->next_sibling)
1816 clutter_actor_paint (iter);
1821 * clutter_actor_should_pick_paint:
1822 * @self: A #ClutterActor
1824 * Should be called inside the implementation of the
1825 * #ClutterActor::pick virtual function in order to check whether
1826 * the actor should paint itself in pick mode or not.
1828 * This function should never be called directly by applications.
1830 * Return value: %TRUE if the actor should paint its silhouette,
1834 clutter_actor_should_pick_paint (ClutterActor *self)
1836 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1838 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1839 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1840 CLUTTER_ACTOR_IS_REACTIVE (self)))
1847 clutter_actor_real_get_preferred_width (ClutterActor *self,
1849 gfloat *min_width_p,
1850 gfloat *natural_width_p)
1852 ClutterActorPrivate *priv = self->priv;
1854 if (priv->n_children != 0 &&
1855 priv->layout_manager != NULL)
1857 ClutterContainer *container = CLUTTER_CONTAINER (self);
1859 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1860 "for the preferred width",
1861 G_OBJECT_TYPE_NAME (priv->layout_manager),
1862 priv->layout_manager);
1864 clutter_layout_manager_get_preferred_width (priv->layout_manager,
1873 /* Default implementation is always 0x0, usually an actor
1874 * using this default is relying on someone to set the
1877 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1882 if (natural_width_p)
1883 *natural_width_p = 0;
1887 clutter_actor_real_get_preferred_height (ClutterActor *self,
1889 gfloat *min_height_p,
1890 gfloat *natural_height_p)
1892 ClutterActorPrivate *priv = self->priv;
1894 if (priv->n_children != 0 &&
1895 priv->layout_manager != NULL)
1897 ClutterContainer *container = CLUTTER_CONTAINER (self);
1899 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1900 "for the preferred height",
1901 G_OBJECT_TYPE_NAME (priv->layout_manager),
1902 priv->layout_manager);
1904 clutter_layout_manager_get_preferred_height (priv->layout_manager,
1912 /* Default implementation is always 0x0, usually an actor
1913 * using this default is relying on someone to set the
1916 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
1921 if (natural_height_p)
1922 *natural_height_p = 0;
1926 clutter_actor_store_old_geometry (ClutterActor *self,
1927 ClutterActorBox *box)
1929 *box = self->priv->allocation;
1933 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
1934 const ClutterActorBox *old)
1936 ClutterActorPrivate *priv = self->priv;
1937 GObject *obj = G_OBJECT (self);
1939 g_object_freeze_notify (obj);
1941 /* to avoid excessive requisition or allocation cycles we
1942 * use the cached values.
1944 * - if we don't have an allocation we assume that we need
1946 * - if we don't have a width or a height request we notify
1948 * - if we have a valid allocation then we check the old
1949 * bounding box with the current allocation and we notify
1952 if (priv->needs_allocation)
1954 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1955 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1956 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1957 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1959 else if (priv->needs_width_request || priv->needs_height_request)
1961 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1962 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1967 gfloat widthu, heightu;
1969 xu = priv->allocation.x1;
1970 yu = priv->allocation.y1;
1971 widthu = priv->allocation.x2 - priv->allocation.x1;
1972 heightu = priv->allocation.y2 - priv->allocation.y1;
1975 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
1978 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
1980 if (widthu != (old->x2 - old->x1))
1981 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
1983 if (heightu != (old->y2 - old->y1))
1984 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
1987 g_object_thaw_notify (obj);
1991 * clutter_actor_set_allocation_internal:
1992 * @self: a #ClutterActor
1993 * @box: a #ClutterActorBox
1994 * @flags: allocation flags
1996 * Stores the allocation of @self.
1998 * This function only performs basic storage and property notification.
2000 * This function should be called by clutter_actor_set_allocation()
2001 * and by the default implementation of #ClutterActorClass.allocate().
2003 * Return value: %TRUE if the allocation of the #ClutterActor has been
2004 * changed, and %FALSE otherwise
2006 static inline gboolean
2007 clutter_actor_set_allocation_internal (ClutterActor *self,
2008 const ClutterActorBox *box,
2009 ClutterAllocationFlags flags)
2011 ClutterActorPrivate *priv = self->priv;
2013 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2014 gboolean flags_changed;
2016 ClutterActorBox old_alloc = { 0, };
2018 obj = G_OBJECT (self);
2020 g_object_freeze_notify (obj);
2022 clutter_actor_store_old_geometry (self, &old_alloc);
2024 x1_changed = priv->allocation.x1 != box->x1;
2025 y1_changed = priv->allocation.y1 != box->y1;
2026 x2_changed = priv->allocation.x2 != box->x2;
2027 y2_changed = priv->allocation.y2 != box->y2;
2029 flags_changed = priv->allocation_flags != flags;
2031 priv->allocation = *box;
2032 priv->allocation_flags = flags;
2034 /* allocation is authoritative */
2035 priv->needs_width_request = FALSE;
2036 priv->needs_height_request = FALSE;
2037 priv->needs_allocation = FALSE;
2039 if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2041 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2042 _clutter_actor_get_debug_name (self));
2044 priv->transform_valid = FALSE;
2046 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2053 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2055 g_object_thaw_notify (obj);
2060 static void clutter_actor_real_allocate (ClutterActor *self,
2061 const ClutterActorBox *box,
2062 ClutterAllocationFlags flags);
2065 clutter_actor_maybe_layout_children (ClutterActor *self,
2066 const ClutterActorBox *allocation,
2067 ClutterAllocationFlags flags)
2069 ClutterActorPrivate *priv = self->priv;
2071 /* this is going to be a bit hard to follow, so let's put an explanation
2074 * we want ClutterActor to have a default layout manager if the actor was
2075 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2077 * we also want any subclass of ClutterActor that does not override the
2078 * ::allocate() virtual function to delegate to a layout manager.
2080 * finally, we want to allow people subclassing ClutterActor and overriding
2081 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2083 * on the other hand, we want existing actor subclasses overriding the
2084 * ::allocate() virtual function and chaining up to the parent's
2085 * implementation to continue working without allocating their children
2086 * twice, or without entering an allocation loop.
2088 * for the first two points, we check if the class of the actor is
2089 * overridding the ::allocate() virtual function; if it isn't, then we
2090 * follow through with checking whether we have children and a layout
2091 * manager, and eventually calling clutter_layout_manager_allocate().
2093 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2094 * allocation flags that we got passed, and if it is present, we continue
2095 * with the check above.
2097 * if neither of these two checks yields a positive result, we just
2098 * assume that the ::allocate() virtual function that resulted in this
2099 * function being called will also allocate the children of the actor.
2102 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2105 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2111 if (priv->n_children != 0 &&
2112 priv->layout_manager != NULL)
2114 ClutterContainer *container = CLUTTER_CONTAINER (self);
2115 ClutterAllocationFlags children_flags;
2116 ClutterActorBox children_box;
2118 /* normalize the box passed to the layout manager */
2119 children_box.x1 = children_box.y1 = 0.f;
2120 children_box.x2 = (allocation->x2 - allocation->x1);
2121 children_box.y2 = (allocation->y2 - allocation->y1);
2123 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2124 * the actor's children, since it refers only to the current
2125 * actor's allocation.
2127 children_flags = flags;
2128 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2130 CLUTTER_NOTE (LAYOUT,
2131 "Allocating %d children of %s "
2132 "at { %.2f, %.2f - %.2f x %.2f } "
2135 _clutter_actor_get_debug_name (self),
2138 (allocation->x2 - allocation->x1),
2139 (allocation->y2 - allocation->y1),
2140 G_OBJECT_TYPE_NAME (priv->layout_manager));
2142 clutter_layout_manager_allocate (priv->layout_manager,
2150 clutter_actor_real_allocate (ClutterActor *self,
2151 const ClutterActorBox *box,
2152 ClutterAllocationFlags flags)
2154 ClutterActorPrivate *priv = self->priv;
2157 g_object_freeze_notify (G_OBJECT (self));
2159 changed = clutter_actor_set_allocation_internal (self, box, flags);
2161 /* we allocate our children before we notify changes in our geometry,
2162 * so that people connecting to properties will be able to get valid
2163 * data out of the sub-tree of the scene graph that has this actor at
2166 clutter_actor_maybe_layout_children (self, box, flags);
2170 ClutterActorBox signal_box = priv->allocation;
2171 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2173 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2178 g_object_thaw_notify (G_OBJECT (self));
2182 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2183 ClutterActor *origin)
2185 /* no point in queuing a redraw on a destroyed actor */
2186 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2189 /* NB: We can't bail out early here if the actor is hidden in case
2190 * the actor bas been cloned. In this case the clone will need to
2191 * receive the signal so it can queue its own redraw.
2194 /* calls klass->queue_redraw in default handler */
2195 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2199 clutter_actor_real_queue_redraw (ClutterActor *self,
2200 ClutterActor *origin)
2202 ClutterActor *parent;
2204 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2205 _clutter_actor_get_debug_name (self),
2206 origin != NULL ? _clutter_actor_get_debug_name (origin)
2209 /* no point in queuing a redraw on a destroyed actor */
2210 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2213 /* If the queue redraw is coming from a child then the actor has
2214 become dirty and any queued effect is no longer valid */
2217 self->priv->is_dirty = TRUE;
2218 self->priv->effect_to_redraw = NULL;
2221 /* If the actor isn't visible, we still had to emit the signal
2222 * to allow for a ClutterClone, but the appearance of the parent
2223 * won't change so we don't have to propagate up the hierarchy.
2225 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2228 /* Although we could determine here that a full stage redraw
2229 * has already been queued and immediately bail out, we actually
2230 * guarantee that we will propagate a queue-redraw signal to our
2231 * parent at least once so that it's possible to implement a
2232 * container that tracks which of its children have queued a
2235 if (self->priv->propagated_one_redraw)
2237 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2238 if (stage != NULL &&
2239 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2243 self->priv->propagated_one_redraw = TRUE;
2245 /* notify parents, if they are all visible eventually we'll
2246 * queue redraw on the stage, which queues the redraw idle.
2248 parent = clutter_actor_get_parent (self);
2251 /* this will go up recursively */
2252 _clutter_actor_signal_queue_redraw (parent, origin);
2257 clutter_actor_real_queue_relayout (ClutterActor *self)
2259 ClutterActorPrivate *priv = self->priv;
2261 /* no point in queueing a redraw on a destroyed actor */
2262 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2265 priv->needs_width_request = TRUE;
2266 priv->needs_height_request = TRUE;
2267 priv->needs_allocation = TRUE;
2269 /* reset the cached size requests */
2270 memset (priv->width_requests, 0,
2271 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2272 memset (priv->height_requests, 0,
2273 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2275 /* We need to go all the way up the hierarchy */
2276 if (priv->parent != NULL)
2277 _clutter_actor_queue_only_relayout (priv->parent);
2281 * clutter_actor_apply_relative_transform_to_point:
2282 * @self: A #ClutterActor
2283 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2284 * default #ClutterStage
2285 * @point: A point as #ClutterVertex
2286 * @vertex: (out caller-allocates): The translated #ClutterVertex
2288 * Transforms @point in coordinates relative to the actor into
2289 * ancestor-relative coordinates using the relevant transform
2290 * stack (i.e. scale, rotation, etc).
2292 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2293 * this case, the coordinates returned will be the coordinates on
2294 * the stage before the projection is applied. This is different from
2295 * the behaviour of clutter_actor_apply_transform_to_point().
2300 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2301 ClutterActor *ancestor,
2302 const ClutterVertex *point,
2303 ClutterVertex *vertex)
2308 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2309 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2310 g_return_if_fail (point != NULL);
2311 g_return_if_fail (vertex != NULL);
2316 if (ancestor == NULL)
2317 ancestor = _clutter_actor_get_stage_internal (self);
2319 if (ancestor == NULL)
2325 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2326 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2330 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2331 const ClutterVertex *vertices_in,
2332 ClutterVertex *vertices_out,
2335 ClutterActor *stage;
2336 CoglMatrix modelview;
2337 CoglMatrix projection;
2340 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2342 stage = _clutter_actor_get_stage_internal (self);
2344 /* We really can't do anything meaningful in this case so don't try
2345 * to do any transform */
2349 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2350 * that gets us to stage coordinates, we want to go all the way to eye
2352 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2354 /* Fetch the projection and viewport */
2355 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2356 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2362 _clutter_util_fully_transform_vertices (&modelview,
2373 * clutter_actor_apply_transform_to_point:
2374 * @self: A #ClutterActor
2375 * @point: A point as #ClutterVertex
2376 * @vertex: (out caller-allocates): The translated #ClutterVertex
2378 * Transforms @point in coordinates relative to the actor
2379 * into screen-relative coordinates with the current actor
2380 * transformation (i.e. scale, rotation, etc)
2385 clutter_actor_apply_transform_to_point (ClutterActor *self,
2386 const ClutterVertex *point,
2387 ClutterVertex *vertex)
2389 g_return_if_fail (point != NULL);
2390 g_return_if_fail (vertex != NULL);
2391 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2395 * _clutter_actor_get_relative_transformation_matrix:
2396 * @self: The actor whose coordinate space you want to transform from.
2397 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2398 * or %NULL if you want to transform all the way to eye coordinates.
2399 * @matrix: A #CoglMatrix to store the transformation
2401 * This gets a transformation @matrix that will transform coordinates from the
2402 * coordinate space of @self into the coordinate space of @ancestor.
2404 * For example if you need a matrix that can transform the local actor
2405 * coordinates of @self into stage coordinates you would pass the actor's stage
2406 * pointer as the @ancestor.
2408 * If you pass %NULL then the transformation will take you all the way through
2409 * to eye coordinates. This can be useful if you want to extract the entire
2410 * modelview transform that Clutter applies before applying the projection
2411 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2412 * using cogl_set_modelview_matrix() for example then you would want a matrix
2413 * that transforms into eye coordinates.
2415 * <note><para>This function explicitly initializes the given @matrix. If you just
2416 * want clutter to multiply a relative transformation with an existing matrix
2417 * you can use clutter_actor_apply_relative_transformation_matrix()
2418 * instead.</para></note>
2421 /* XXX: We should consider caching the stage relative modelview along with
2422 * the actor itself */
2424 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2425 ClutterActor *ancestor,
2428 cogl_matrix_init_identity (matrix);
2430 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2433 /* Project the given @box into stage window coordinates, writing the
2434 * transformed vertices to @verts[]. */
2436 _clutter_actor_transform_and_project_box (ClutterActor *self,
2437 const ClutterActorBox *box,
2438 ClutterVertex verts[])
2440 ClutterVertex box_vertices[4];
2442 box_vertices[0].x = box->x1;
2443 box_vertices[0].y = box->y1;
2444 box_vertices[0].z = 0;
2445 box_vertices[1].x = box->x2;
2446 box_vertices[1].y = box->y1;
2447 box_vertices[1].z = 0;
2448 box_vertices[2].x = box->x1;
2449 box_vertices[2].y = box->y2;
2450 box_vertices[2].z = 0;
2451 box_vertices[3].x = box->x2;
2452 box_vertices[3].y = box->y2;
2453 box_vertices[3].z = 0;
2456 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2460 * clutter_actor_get_allocation_vertices:
2461 * @self: A #ClutterActor
2462 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2463 * against, or %NULL to use the #ClutterStage
2464 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2465 * location for an array of 4 #ClutterVertex in which to store the result
2467 * Calculates the transformed coordinates of the four corners of the
2468 * actor in the plane of @ancestor. The returned vertices relate to
2469 * the #ClutterActorBox coordinates as follows:
2471 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2472 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2473 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2474 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2477 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2478 * this case, the coordinates returned will be the coordinates on
2479 * the stage before the projection is applied. This is different from
2480 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2485 clutter_actor_get_allocation_vertices (ClutterActor *self,
2486 ClutterActor *ancestor,
2487 ClutterVertex verts[])
2489 ClutterActorPrivate *priv;
2490 ClutterActorBox box;
2491 ClutterVertex vertices[4];
2492 CoglMatrix modelview;
2494 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2495 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2497 if (ancestor == NULL)
2498 ancestor = _clutter_actor_get_stage_internal (self);
2500 /* Fallback to a NOP transform if the actor isn't parented under a
2502 if (ancestor == NULL)
2507 /* if the actor needs to be allocated we force a relayout, so that
2508 * we will have valid values to use in the transformations */
2509 if (priv->needs_allocation)
2511 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2513 _clutter_stage_maybe_relayout (stage);
2516 box.x1 = box.y1 = 0;
2517 /* The result isn't really meaningful in this case but at
2518 * least try to do something *vaguely* reasonable... */
2519 clutter_actor_get_size (self, &box.x2, &box.y2);
2523 clutter_actor_get_allocation_box (self, &box);
2525 vertices[0].x = box.x1;
2526 vertices[0].y = box.y1;
2528 vertices[1].x = box.x2;
2529 vertices[1].y = box.y1;
2531 vertices[2].x = box.x1;
2532 vertices[2].y = box.y2;
2534 vertices[3].x = box.x2;
2535 vertices[3].y = box.y2;
2538 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2541 cogl_matrix_transform_points (&modelview,
2543 sizeof (ClutterVertex),
2545 sizeof (ClutterVertex),
2551 * clutter_actor_get_abs_allocation_vertices:
2552 * @self: A #ClutterActor
2553 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2554 * of 4 #ClutterVertex where to store the result.
2556 * Calculates the transformed screen coordinates of the four corners of
2557 * the actor; the returned vertices relate to the #ClutterActorBox
2558 * coordinates as follows:
2560 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2561 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2562 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2563 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2569 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2570 ClutterVertex verts[])
2572 ClutterActorPrivate *priv;
2573 ClutterActorBox actor_space_allocation;
2575 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2579 /* if the actor needs to be allocated we force a relayout, so that
2580 * the actor allocation box will be valid for
2581 * _clutter_actor_transform_and_project_box()
2583 if (priv->needs_allocation)
2585 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2586 /* There's nothing meaningful we can do now */
2590 _clutter_stage_maybe_relayout (stage);
2593 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2594 * own coordinate space... */
2595 actor_space_allocation.x1 = 0;
2596 actor_space_allocation.y1 = 0;
2597 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2598 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2599 _clutter_actor_transform_and_project_box (self,
2600 &actor_space_allocation,
2605 clutter_actor_real_apply_transform (ClutterActor *self,
2608 ClutterActorPrivate *priv = self->priv;
2610 if (!priv->transform_valid)
2612 CoglMatrix *transform = &priv->transform;
2613 const ClutterTransformInfo *info;
2615 info = _clutter_actor_get_transform_info_or_defaults (self);
2617 cogl_matrix_init_identity (transform);
2619 cogl_matrix_translate (transform,
2620 priv->allocation.x1,
2621 priv->allocation.y1,
2625 cogl_matrix_translate (transform, 0, 0, info->depth);
2628 * because the rotation involves translations, we must scale
2629 * before applying the rotations (if we apply the scale after
2630 * the rotations, the translations included in the rotation are
2631 * not scaled and so the entire object will move on the screen
2632 * as a result of rotating it).
2634 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2636 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2637 &info->scale_center,
2638 cogl_matrix_scale (transform,
2645 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2647 cogl_matrix_rotate (transform,
2652 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2654 cogl_matrix_rotate (transform,
2659 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2661 cogl_matrix_rotate (transform,
2665 if (!clutter_anchor_coord_is_zero (&info->anchor))
2669 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2670 cogl_matrix_translate (transform, -x, -y, -z);
2673 priv->transform_valid = TRUE;
2676 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2679 /* Applies the transforms associated with this actor to the given
2682 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2685 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2689 * clutter_actor_apply_relative_transformation_matrix:
2690 * @self: The actor whose coordinate space you want to transform from.
2691 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2692 * or %NULL if you want to transform all the way to eye coordinates.
2693 * @matrix: A #CoglMatrix to apply the transformation too.
2695 * This multiplies a transform with @matrix that will transform coordinates
2696 * from the coordinate space of @self into the coordinate space of @ancestor.
2698 * For example if you need a matrix that can transform the local actor
2699 * coordinates of @self into stage coordinates you would pass the actor's stage
2700 * pointer as the @ancestor.
2702 * If you pass %NULL then the transformation will take you all the way through
2703 * to eye coordinates. This can be useful if you want to extract the entire
2704 * modelview transform that Clutter applies before applying the projection
2705 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2706 * using cogl_set_modelview_matrix() for example then you would want a matrix
2707 * that transforms into eye coordinates.
2709 * <note>This function doesn't initialize the given @matrix, it simply
2710 * multiplies the requested transformation matrix with the existing contents of
2711 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2712 * before calling this function, or you can use
2713 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2716 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2717 ClutterActor *ancestor,
2720 ClutterActor *parent;
2722 /* Note we terminate before ever calling stage->apply_transform()
2723 * since that would conceptually be relative to the underlying
2724 * window OpenGL coordinates so we'd need a special @ancestor
2725 * value to represent the fake parent of the stage. */
2726 if (self == ancestor)
2729 parent = clutter_actor_get_parent (self);
2732 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2735 _clutter_actor_apply_modelview_transform (self, matrix);
2739 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2740 ClutterPaintVolume *pv,
2742 const CoglColor *color)
2744 static CoglPipeline *outline = NULL;
2745 CoglPrimitive *prim;
2746 ClutterVertex line_ends[12 * 2];
2749 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2750 /* XXX: at some point we'll query this from the stage but we can't
2751 * do that until the osx backend uses Cogl natively. */
2752 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2754 if (outline == NULL)
2755 outline = cogl_pipeline_new (ctx);
2757 _clutter_paint_volume_complete (pv);
2759 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2762 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2763 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2764 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2765 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2770 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2771 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2772 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2773 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2775 /* Lines connecting front face to back face */
2776 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2777 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2778 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2779 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2782 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2784 (CoglVertexP3 *)line_ends);
2786 cogl_pipeline_set_color (outline, color);
2787 cogl_framebuffer_draw_primitive (fb, outline, prim);
2788 cogl_object_unref (prim);
2792 PangoLayout *layout;
2793 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2794 pango_layout_set_text (layout, label, -1);
2795 cogl_pango_render_layout (layout,
2800 g_object_unref (layout);
2805 _clutter_actor_draw_paint_volume (ClutterActor *self)
2807 ClutterPaintVolume *pv;
2810 pv = _clutter_actor_get_paint_volume_mutable (self);
2813 gfloat width, height;
2814 ClutterPaintVolume fake_pv;
2816 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2817 _clutter_paint_volume_init_static (&fake_pv, stage);
2819 clutter_actor_get_size (self, &width, &height);
2820 clutter_paint_volume_set_width (&fake_pv, width);
2821 clutter_paint_volume_set_height (&fake_pv, height);
2823 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2824 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2825 _clutter_actor_get_debug_name (self),
2828 clutter_paint_volume_free (&fake_pv);
2832 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2833 _clutter_actor_draw_paint_volume_full (self, pv,
2834 _clutter_actor_get_debug_name (self),
2840 _clutter_actor_paint_cull_result (ClutterActor *self,
2842 ClutterCullResult result)
2844 ClutterPaintVolume *pv;
2849 if (result == CLUTTER_CULL_RESULT_IN)
2850 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2851 else if (result == CLUTTER_CULL_RESULT_OUT)
2852 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2854 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2857 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2859 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2860 _clutter_actor_draw_paint_volume_full (self, pv,
2861 _clutter_actor_get_debug_name (self),
2865 PangoLayout *layout;
2867 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2868 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2869 cogl_set_source_color (&color);
2871 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2872 pango_layout_set_text (layout, label, -1);
2873 cogl_pango_render_layout (layout,
2879 g_object_unref (layout);
2883 static int clone_paint_level = 0;
2886 _clutter_actor_push_clone_paint (void)
2888 clone_paint_level++;
2892 _clutter_actor_pop_clone_paint (void)
2894 clone_paint_level--;
2898 in_clone_paint (void)
2900 return clone_paint_level > 0;
2903 /* Returns TRUE if the actor can be ignored */
2904 /* FIXME: we should return a ClutterCullResult, and
2905 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
2906 * means there's no point in trying to cull descendants of the current
2909 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
2911 ClutterActorPrivate *priv = self->priv;
2912 ClutterActor *stage;
2913 const ClutterPlane *stage_clip;
2915 if (!priv->last_paint_volume_valid)
2917 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2918 "->last_paint_volume_valid == FALSE",
2919 _clutter_actor_get_debug_name (self));
2923 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
2926 stage = _clutter_actor_get_stage_internal (self);
2927 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
2928 if (G_UNLIKELY (!stage_clip))
2930 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2931 "No stage clip set",
2932 _clutter_actor_get_debug_name (self));
2936 if (cogl_get_draw_framebuffer () !=
2937 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
2939 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
2940 "Current framebuffer doesn't correspond to stage",
2941 _clutter_actor_get_debug_name (self));
2946 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
2951 _clutter_actor_update_last_paint_volume (ClutterActor *self)
2953 ClutterActorPrivate *priv = self->priv;
2954 const ClutterPaintVolume *pv;
2956 if (priv->last_paint_volume_valid)
2958 clutter_paint_volume_free (&priv->last_paint_volume);
2959 priv->last_paint_volume_valid = FALSE;
2962 pv = clutter_actor_get_paint_volume (self);
2965 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
2966 "Actor failed to report a paint volume",
2967 _clutter_actor_get_debug_name (self));
2971 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
2973 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
2974 NULL); /* eye coordinates */
2976 priv->last_paint_volume_valid = TRUE;
2979 static inline gboolean
2980 actor_has_shader_data (ClutterActor *self)
2982 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
2986 _clutter_actor_get_pick_id (ClutterActor *self)
2988 if (self->priv->pick_id < 0)
2991 return self->priv->pick_id;
2994 /* This is the same as clutter_actor_add_effect except that it doesn't
2995 queue a redraw and it doesn't notify on the effect property */
2997 _clutter_actor_add_effect_internal (ClutterActor *self,
2998 ClutterEffect *effect)
3000 ClutterActorPrivate *priv = self->priv;
3002 if (priv->effects == NULL)
3004 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3005 priv->effects->actor = self;
3008 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3011 /* This is the same as clutter_actor_remove_effect except that it doesn't
3012 queue a redraw and it doesn't notify on the effect property */
3014 _clutter_actor_remove_effect_internal (ClutterActor *self,
3015 ClutterEffect *effect)
3017 ClutterActorPrivate *priv = self->priv;
3019 if (priv->effects == NULL)
3022 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3026 needs_flatten_effect (ClutterActor *self)
3028 ClutterActorPrivate *priv = self->priv;
3030 if (G_UNLIKELY (clutter_paint_debug_flags &
3031 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3034 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3036 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3038 if (clutter_actor_get_paint_opacity (self) < 255 &&
3039 clutter_actor_has_overlaps (self))
3047 add_or_remove_flatten_effect (ClutterActor *self)
3049 ClutterActorPrivate *priv = self->priv;
3051 /* Add or remove the flatten effect depending on the
3052 offscreen-redirect property. */
3053 if (needs_flatten_effect (self))
3055 if (priv->flatten_effect == NULL)
3057 ClutterActorMeta *actor_meta;
3060 priv->flatten_effect = _clutter_flatten_effect_new ();
3061 /* Keep a reference to the effect so that we can queue
3063 g_object_ref_sink (priv->flatten_effect);
3065 /* Set the priority of the effect to high so that it will
3066 always be applied to the actor first. It uses an internal
3067 priority so that it won't be visible to applications */
3068 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3069 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3070 _clutter_actor_meta_set_priority (actor_meta, priority);
3072 /* This will add the effect without queueing a redraw */
3073 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3078 if (priv->flatten_effect != NULL)
3080 /* Destroy the effect so that it will lose its fbo cache of
3082 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3083 g_object_unref (priv->flatten_effect);
3084 priv->flatten_effect = NULL;
3090 clutter_actor_paint_node (ClutterActor *actor,
3091 ClutterPaintNode *root)
3093 ClutterActorPrivate *priv = actor->priv;
3095 if (priv->bg_color_set)
3097 ClutterPaintNode *node;
3098 ClutterColor bg_color;
3100 bg_color = priv->bg_color;
3101 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3102 * priv->bg_color.alpha
3105 node = clutter_color_node_new (&bg_color);
3106 clutter_paint_node_set_name (node, "backgroundColor");
3107 clutter_paint_node_add_rectangle (node, &priv->allocation);
3108 clutter_paint_node_add_child (root, node);
3109 clutter_paint_node_unref (node);
3112 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3113 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3115 if (clutter_paint_node_get_n_children (root) == 0)
3118 _clutter_paint_node_paint (root);
3122 clutter_actor_real_paint (ClutterActor *actor)
3124 ClutterActorPrivate *priv = actor->priv;
3127 for (iter = priv->first_child;
3129 iter = iter->priv->next_sibling)
3131 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3132 _clutter_actor_get_debug_name (iter),
3133 _clutter_actor_get_debug_name (actor),
3134 iter->priv->allocation.x1,
3135 iter->priv->allocation.y1,
3136 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3137 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3139 clutter_actor_paint (iter);
3144 * clutter_actor_paint:
3145 * @self: A #ClutterActor
3147 * Renders the actor to display.
3149 * This function should not be called directly by applications.
3150 * Call clutter_actor_queue_redraw() to queue paints, instead.
3152 * This function is context-aware, and will either cause a
3153 * regular paint or a pick paint.
3155 * This function will emit the #ClutterActor::paint signal or
3156 * the #ClutterActor::pick signal, depending on the context.
3158 * This function does not paint the actor if the actor is set to 0,
3159 * unless it is performing a pick paint.
3162 clutter_actor_paint (ClutterActor *self)
3164 ClutterActorPrivate *priv;
3165 ClutterPickMode pick_mode;
3166 gboolean clip_set = FALSE;
3167 gboolean shader_applied = FALSE;
3169 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3170 "Actor real-paint counter",
3171 "Increments each time any actor is painted",
3172 0 /* no application private data */);
3173 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3174 "Actor pick-paint counter",
3175 "Increments each time any actor is painted "
3177 0 /* no application private data */);
3179 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3181 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3186 pick_mode = _clutter_context_get_pick_mode ();
3188 if (pick_mode == CLUTTER_PICK_NONE)
3189 priv->propagated_one_redraw = FALSE;
3191 /* It's an important optimization that we consider painting of
3192 * actors with 0 opacity to be a NOP... */
3193 if (pick_mode == CLUTTER_PICK_NONE &&
3194 /* ignore top-levels, since they might be transparent */
3195 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3196 /* Use the override opacity if its been set */
3197 ((priv->opacity_override >= 0) ?
3198 priv->opacity_override : priv->opacity) == 0)
3201 /* if we aren't paintable (not in a toplevel with all
3202 * parents paintable) then do nothing.
3204 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3207 /* mark that we are in the paint process */
3208 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3212 if (priv->enable_model_view_transform)
3216 /* XXX: It could be better to cache the modelview with the actor
3217 * instead of progressively building up the transformations on
3218 * the matrix stack every time we paint. */
3219 cogl_get_modelview_matrix (&matrix);
3220 _clutter_actor_apply_modelview_transform (self, &matrix);
3222 #ifdef CLUTTER_ENABLE_DEBUG
3223 /* Catch when out-of-band transforms have been made by actors not as part
3224 * of an apply_transform vfunc... */
3225 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3227 CoglMatrix expected_matrix;
3229 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3232 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3234 GString *buf = g_string_sized_new (1024);
3235 ClutterActor *parent;
3238 while (parent != NULL)
3240 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3242 if (parent->priv->parent != NULL)
3243 g_string_append (buf, "->");
3245 parent = parent->priv->parent;
3248 g_warning ("Unexpected transform found when painting actor "
3249 "\"%s\". This will be caused by one of the actor's "
3250 "ancestors (%s) using the Cogl API directly to transform "
3251 "children instead of using ::apply_transform().",
3252 _clutter_actor_get_debug_name (self),
3255 g_string_free (buf, TRUE);
3258 #endif /* CLUTTER_ENABLE_DEBUG */
3260 cogl_set_modelview_matrix (&matrix);
3265 cogl_clip_push_rectangle (priv->clip.x,
3267 priv->clip.x + priv->clip.width,
3268 priv->clip.y + priv->clip.height);
3271 else if (priv->clip_to_allocation)
3273 gfloat width, height;
3275 width = priv->allocation.x2 - priv->allocation.x1;
3276 height = priv->allocation.y2 - priv->allocation.y1;
3278 cogl_clip_push_rectangle (0, 0, width, height);
3282 if (pick_mode == CLUTTER_PICK_NONE)
3284 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3286 /* We check whether we need to add the flatten effect before
3287 each paint so that we can avoid having a mechanism for
3288 applications to notify when the value of the
3289 has_overlaps virtual changes. */
3290 add_or_remove_flatten_effect (self);
3293 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3295 /* We save the current paint volume so that the next time the
3296 * actor queues a redraw we can constrain the redraw to just
3297 * cover the union of the new bounding box and the old.
3299 * We also fetch the current paint volume to perform culling so
3300 * we can avoid painting actors outside the current clip region.
3302 * If we are painting inside a clone, we should neither update
3303 * the paint volume or use it to cull painting, since the paint
3304 * box represents the location of the source actor on the
3307 * XXX: We are starting to do a lot of vertex transforms on
3308 * the CPU in a typical paint, so at some point we should
3309 * audit these and consider caching some things.
3311 * NB: We don't perform culling while picking at this point because
3312 * clutter-stage.c doesn't setup the clipping planes appropriately.
3314 * NB: We don't want to update the last-paint-volume during picking
3315 * because the last-paint-volume is used to determine the old screen
3316 * space location of an actor that has moved so we can know the
3317 * minimal region to redraw to clear an old view of the actor. If we
3318 * update this during picking then by the time we come around to
3319 * paint then the last-paint-volume would likely represent the new
3320 * actor position not the old.
3322 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3325 /* annoyingly gcc warns if uninitialized even though
3326 * the initialization is redundant :-( */
3327 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3329 if (G_LIKELY ((clutter_paint_debug_flags &
3330 (CLUTTER_DEBUG_DISABLE_CULLING |
3331 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3332 (CLUTTER_DEBUG_DISABLE_CULLING |
3333 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3334 _clutter_actor_update_last_paint_volume (self);
3336 success = cull_actor (self, &result);
3338 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3339 _clutter_actor_paint_cull_result (self, success, result);
3340 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3344 if (priv->effects == NULL)
3346 if (pick_mode == CLUTTER_PICK_NONE &&
3347 actor_has_shader_data (self))
3349 _clutter_actor_shader_pre_paint (self, FALSE);
3350 shader_applied = TRUE;
3353 priv->next_effect_to_paint = NULL;
3356 priv->next_effect_to_paint =
3357 _clutter_meta_group_peek_metas (priv->effects);
3359 clutter_actor_continue_paint (self);
3362 _clutter_actor_shader_post_paint (self);
3364 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3365 pick_mode == CLUTTER_PICK_NONE))
3366 _clutter_actor_draw_paint_volume (self);
3369 /* If we make it here then the actor has run through a complete
3370 paint run including all the effects so it's no longer dirty */
3371 if (pick_mode == CLUTTER_PICK_NONE)
3372 priv->is_dirty = FALSE;
3379 /* paint sequence complete */
3380 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3384 * clutter_actor_continue_paint:
3385 * @self: A #ClutterActor
3387 * Run the next stage of the paint sequence. This function should only
3388 * be called within the implementation of the ‘run’ virtual of a
3389 * #ClutterEffect. It will cause the run method of the next effect to
3390 * be applied, or it will paint the actual actor if the current effect
3391 * is the last effect in the chain.
3396 clutter_actor_continue_paint (ClutterActor *self)
3398 ClutterActorPrivate *priv;
3400 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3401 /* This should only be called from with in the ‘run’ implementation
3402 of a ClutterEffect */
3403 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3407 /* Skip any effects that are disabled */
3408 while (priv->next_effect_to_paint &&
3409 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3410 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3412 /* If this has come from the last effect then we'll just paint the
3414 if (priv->next_effect_to_paint == NULL)
3416 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3418 ClutterPaintNode *dummy;
3420 /* XXX - this will go away in 2.0, when we can get rid of this
3421 * stuff and switch to a pure retained render tree of PaintNodes
3422 * for the entire frame, starting from the Stage.
3424 dummy = _clutter_dummy_node_new ();
3425 clutter_paint_node_set_name (dummy, "Root");
3426 clutter_actor_paint_node (self, dummy);
3428 if (clutter_paint_node_get_n_children (dummy) != 0)
3430 #ifdef CLUTTER_ENABLE_DEBUG
3431 if (CLUTTER_HAS_DEBUG (PAINT))
3433 /* dump the tree only if we have one */
3434 _clutter_paint_node_dump_tree (dummy);
3436 #endif /* CLUTTER_ENABLE_DEBUG */
3438 _clutter_paint_node_paint (dummy);
3441 clutter_paint_node_unref (dummy);
3443 g_signal_emit (self, actor_signals[PAINT], 0);
3447 ClutterColor col = { 0, };
3449 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3451 /* Actor will then paint silhouette of itself in supplied
3452 * color. See clutter_stage_get_actor_at_pos() for where
3453 * picking is enabled.
3455 g_signal_emit (self, actor_signals[PICK], 0, &col);
3460 ClutterEffect *old_current_effect;
3461 ClutterEffectPaintFlags run_flags = 0;
3463 /* Cache the current effect so that we can put it back before
3465 old_current_effect = priv->current_effect;
3467 priv->current_effect = priv->next_effect_to_paint->data;
3468 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3470 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3474 /* If there's an effect queued with this redraw then all
3475 effects up to that one will be considered dirty. It
3476 is expected the queued effect will paint the cached
3477 image and not call clutter_actor_continue_paint again
3478 (although it should work ok if it does) */
3479 if (priv->effect_to_redraw == NULL ||
3480 priv->current_effect != priv->effect_to_redraw)
3481 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3484 _clutter_effect_paint (priv->current_effect, run_flags);
3488 /* We can't determine when an actor has been modified since
3489 its last pick so lets just assume it has always been
3491 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3493 _clutter_effect_pick (priv->current_effect, run_flags);
3496 priv->current_effect = old_current_effect;
3500 static ClutterActorTraverseVisitFlags
3501 invalidate_queue_redraw_entry (ClutterActor *self,
3505 ClutterActorPrivate *priv = self->priv;
3507 if (priv->queue_redraw_entry != NULL)
3509 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3510 priv->queue_redraw_entry = NULL;
3513 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3517 remove_child (ClutterActor *self,
3518 ClutterActor *child)
3520 ClutterActor *prev_sibling, *next_sibling;
3522 prev_sibling = child->priv->prev_sibling;
3523 next_sibling = child->priv->next_sibling;
3525 if (prev_sibling != NULL)
3526 prev_sibling->priv->next_sibling = next_sibling;
3528 if (next_sibling != NULL)
3529 next_sibling->priv->prev_sibling = prev_sibling;
3531 if (self->priv->first_child == child)
3532 self->priv->first_child = next_sibling;
3534 if (self->priv->last_child == child)
3535 self->priv->last_child = prev_sibling;
3537 child->priv->parent = NULL;
3538 child->priv->prev_sibling = NULL;
3539 child->priv->next_sibling = NULL;
3543 REMOVE_CHILD_DESTROY_META = 1 << 0,
3544 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3545 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3546 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3547 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3548 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3550 /* default flags for public API */
3551 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3552 REMOVE_CHILD_EMIT_PARENT_SET |
3553 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3554 REMOVE_CHILD_CHECK_STATE |
3555 REMOVE_CHILD_FLUSH_QUEUE |
3556 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3558 /* flags for legacy/deprecated API */
3559 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3560 REMOVE_CHILD_FLUSH_QUEUE |
3561 REMOVE_CHILD_EMIT_PARENT_SET |
3562 REMOVE_CHILD_NOTIFY_FIRST_LAST
3563 } ClutterActorRemoveChildFlags;
3566 * clutter_actor_remove_child_internal:
3567 * @self: a #ClutterActor
3568 * @child: the child of @self that has to be removed
3569 * @flags: control the removal operations
3571 * Removes @child from the list of children of @self.
3574 clutter_actor_remove_child_internal (ClutterActor *self,
3575 ClutterActor *child,
3576 ClutterActorRemoveChildFlags flags)
3578 ClutterActor *old_first, *old_last;
3579 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3580 gboolean flush_queue;
3581 gboolean notify_first_last;
3582 gboolean was_mapped;
3584 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3585 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3586 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3587 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3588 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3589 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3591 g_object_freeze_notify (G_OBJECT (self));
3594 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3598 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3600 /* we need to unrealize *before* we set parent_actor to NULL,
3601 * because in an unrealize method actors are dissociating from the
3602 * stage, which means they need to be able to
3603 * clutter_actor_get_stage().
3605 * yhis should unmap and unrealize, unless we're reparenting.
3607 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3614 /* We take this opportunity to invalidate any queue redraw entry
3615 * associated with the actor and descendants since we won't be able to
3616 * determine the appropriate stage after this.
3618 * we do this after we updated the mapped state because actors might
3619 * end up queueing redraws inside their mapped/unmapped virtual
3620 * functions, and if we invalidate the redraw entry we could end up
3621 * with an inconsistent state and weird memory corruption. see
3624 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3625 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3627 _clutter_actor_traverse (child,
3629 invalidate_queue_redraw_entry,
3634 old_first = self->priv->first_child;
3635 old_last = self->priv->last_child;
3637 remove_child (self, child);
3639 self->priv->n_children -= 1;
3641 self->priv->age += 1;
3643 /* clutter_actor_reparent() will emit ::parent-set for us */
3644 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3645 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3647 /* if the child was mapped then we need to relayout ourselves to account
3648 * for the removed child
3651 clutter_actor_queue_relayout (self);
3653 /* we need to emit the signal before dropping the reference */
3654 if (emit_actor_removed)
3655 g_signal_emit_by_name (self, "actor-removed", child);
3657 if (notify_first_last)
3659 if (old_first != self->priv->first_child)
3660 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3662 if (old_last != self->priv->last_child)
3663 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3666 g_object_thaw_notify (G_OBJECT (self));
3668 /* remove the reference we acquired in clutter_actor_add_child() */
3669 g_object_unref (child);
3672 static const ClutterTransformInfo default_transform_info = {
3673 0.0, { 0, }, /* rotation-x */
3674 0.0, { 0, }, /* rotation-y */
3675 0.0, { 0, }, /* rotation-z */
3677 1.0, 1.0, { 0, }, /* scale */
3679 { 0, }, /* anchor */
3685 * _clutter_actor_get_transform_info_or_defaults:
3686 * @self: a #ClutterActor
3688 * Retrieves the ClutterTransformInfo structure associated to an actor.
3690 * If the actor does not have a ClutterTransformInfo structure associated
3691 * to it, then the default structure will be returned.
3693 * This function should only be used for getters.
3695 * Return value: a const pointer to the ClutterTransformInfo structure
3697 const ClutterTransformInfo *
3698 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3700 ClutterTransformInfo *info;
3702 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3706 return &default_transform_info;
3710 clutter_transform_info_free (gpointer data)
3713 g_slice_free (ClutterTransformInfo, data);
3717 * _clutter_actor_get_transform_info:
3718 * @self: a #ClutterActor
3720 * Retrieves a pointer to the ClutterTransformInfo structure.
3722 * If the actor does not have a ClutterTransformInfo associated to it, one
3723 * will be created and initialized to the default values.
3725 * This function should be used for setters.
3727 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3730 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3733 ClutterTransformInfo *
3734 _clutter_actor_get_transform_info (ClutterActor *self)
3736 ClutterTransformInfo *info;
3738 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3741 info = g_slice_new (ClutterTransformInfo);
3743 *info = default_transform_info;
3745 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3747 clutter_transform_info_free);
3754 * clutter_actor_set_rotation_angle_internal:
3755 * @self: a #ClutterActor
3756 * @axis: the axis of the angle to change
3757 * @angle: the angle of rotation
3759 * Sets the rotation angle on the given axis without affecting the
3760 * rotation center point.
3763 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3764 ClutterRotateAxis axis,
3767 GObject *obj = G_OBJECT (self);
3768 ClutterTransformInfo *info;
3770 info = _clutter_actor_get_transform_info (self);
3772 g_object_freeze_notify (obj);
3776 case CLUTTER_X_AXIS:
3777 info->rx_angle = angle;
3778 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3781 case CLUTTER_Y_AXIS:
3782 info->ry_angle = angle;
3783 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3786 case CLUTTER_Z_AXIS:
3787 info->rz_angle = angle;
3788 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3792 self->priv->transform_valid = FALSE;
3794 g_object_thaw_notify (obj);
3796 clutter_actor_queue_redraw (self);
3800 clutter_actor_set_rotation_angle (ClutterActor *self,
3801 ClutterRotateAxis axis,
3804 ClutterTransformInfo *info;
3806 info = _clutter_actor_get_transform_info (self);
3808 if (clutter_actor_get_easing_duration (self) != 0)
3810 ClutterTransition *transition;
3811 GParamSpec *pspec = NULL;
3812 double *cur_angle_p = NULL;
3816 case CLUTTER_X_AXIS:
3817 cur_angle_p = &info->rx_angle;
3818 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3821 case CLUTTER_Y_AXIS:
3822 cur_angle_p = &info->ry_angle;
3823 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3826 case CLUTTER_Z_AXIS:
3827 cur_angle_p = &info->rz_angle;
3828 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3832 g_assert (pspec != NULL);
3833 g_assert (cur_angle_p != NULL);
3835 transition = _clutter_actor_get_transition (self, pspec);
3836 if (transition == NULL)
3838 transition = _clutter_actor_create_transition (self, pspec,
3841 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3844 _clutter_actor_update_transition (self, pspec, angle);
3846 self->priv->transform_valid = FALSE;
3847 clutter_actor_queue_redraw (self);
3850 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3854 * clutter_actor_set_rotation_center_internal:
3855 * @self: a #ClutterActor
3856 * @axis: the axis of the center to change
3857 * @center: the coordinates of the rotation center
3859 * Sets the rotation center on the given axis without affecting the
3863 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3864 ClutterRotateAxis axis,
3865 const ClutterVertex *center)
3867 GObject *obj = G_OBJECT (self);
3868 ClutterTransformInfo *info;
3869 ClutterVertex v = { 0, 0, 0 };
3871 info = _clutter_actor_get_transform_info (self);
3876 g_object_freeze_notify (obj);
3880 case CLUTTER_X_AXIS:
3881 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3882 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
3885 case CLUTTER_Y_AXIS:
3886 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
3887 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
3890 case CLUTTER_Z_AXIS:
3891 /* if the previously set rotation center was fractional, then
3892 * setting explicit coordinates will have to notify the
3893 * :rotation-center-z-gravity property as well
3895 if (info->rz_center.is_fractional)
3896 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
3898 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
3899 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
3903 self->priv->transform_valid = FALSE;
3905 g_object_thaw_notify (obj);
3907 clutter_actor_queue_redraw (self);
3911 clutter_actor_animate_scale_factor (ClutterActor *self,
3916 ClutterTransition *transition;
3918 transition = _clutter_actor_get_transition (self, pspec);
3919 if (transition == NULL)
3921 transition = _clutter_actor_create_transition (self, pspec,
3924 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3927 _clutter_actor_update_transition (self, pspec, new_factor);
3930 self->priv->transform_valid = FALSE;
3931 clutter_actor_queue_redraw (self);
3935 clutter_actor_set_scale_factor_internal (ClutterActor *self,
3939 GObject *obj = G_OBJECT (self);
3940 ClutterTransformInfo *info;
3942 info = _clutter_actor_get_transform_info (self);
3944 if (pspec == obj_props[PROP_SCALE_X])
3945 info->scale_x = factor;
3947 info->scale_y = factor;
3949 self->priv->transform_valid = FALSE;
3950 clutter_actor_queue_redraw (self);
3951 g_object_notify_by_pspec (obj, pspec);
3955 clutter_actor_set_scale_factor (ClutterActor *self,
3956 ClutterRotateAxis axis,
3959 GObject *obj = G_OBJECT (self);
3960 ClutterTransformInfo *info;
3963 info = _clutter_actor_get_transform_info (self);
3965 g_object_freeze_notify (obj);
3969 case CLUTTER_X_AXIS:
3970 pspec = obj_props[PROP_SCALE_X];
3972 if (clutter_actor_get_easing_duration (self) != 0)
3973 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
3975 clutter_actor_set_scale_factor_internal (self, factor, pspec);
3978 case CLUTTER_Y_AXIS:
3979 pspec = obj_props[PROP_SCALE_Y];
3981 if (clutter_actor_get_easing_duration (self) != 0)
3982 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
3984 clutter_actor_set_scale_factor_internal (self, factor, pspec);
3988 g_assert_not_reached ();
3991 g_object_thaw_notify (obj);
3995 clutter_actor_set_scale_center (ClutterActor *self,
3996 ClutterRotateAxis axis,
3999 GObject *obj = G_OBJECT (self);
4000 ClutterTransformInfo *info;
4001 gfloat center_x, center_y;
4003 info = _clutter_actor_get_transform_info (self);
4005 g_object_freeze_notify (obj);
4007 /* get the current scale center coordinates */
4008 clutter_anchor_coord_get_units (self, &info->scale_center,
4013 /* we need to notify this too, because setting explicit coordinates will
4014 * change the gravity as a side effect
4016 if (info->scale_center.is_fractional)
4017 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4021 case CLUTTER_X_AXIS:
4022 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4023 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4026 case CLUTTER_Y_AXIS:
4027 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4028 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4032 g_assert_not_reached ();
4035 self->priv->transform_valid = FALSE;
4037 clutter_actor_queue_redraw (self);
4039 g_object_thaw_notify (obj);
4043 clutter_actor_set_anchor_coord (ClutterActor *self,
4044 ClutterRotateAxis axis,
4047 GObject *obj = G_OBJECT (self);
4048 ClutterTransformInfo *info;
4049 gfloat anchor_x, anchor_y;
4051 info = _clutter_actor_get_transform_info (self);
4053 g_object_freeze_notify (obj);
4055 clutter_anchor_coord_get_units (self, &info->anchor,
4060 if (info->anchor.is_fractional)
4061 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4065 case CLUTTER_X_AXIS:
4066 clutter_anchor_coord_set_units (&info->anchor,
4070 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4073 case CLUTTER_Y_AXIS:
4074 clutter_anchor_coord_set_units (&info->anchor,
4078 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4082 g_assert_not_reached ();
4085 self->priv->transform_valid = FALSE;
4087 clutter_actor_queue_redraw (self);
4089 g_object_thaw_notify (obj);
4093 clutter_actor_set_property (GObject *object,
4095 const GValue *value,
4098 ClutterActor *actor = CLUTTER_ACTOR (object);
4099 ClutterActorPrivate *priv = actor->priv;
4104 clutter_actor_set_x (actor, g_value_get_float (value));
4108 clutter_actor_set_y (actor, g_value_get_float (value));
4112 clutter_actor_set_width (actor, g_value_get_float (value));
4116 clutter_actor_set_height (actor, g_value_get_float (value));
4120 clutter_actor_set_x (actor, g_value_get_float (value));
4124 clutter_actor_set_y (actor, g_value_get_float (value));
4127 case PROP_FIXED_POSITION_SET:
4128 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4131 case PROP_MIN_WIDTH:
4132 clutter_actor_set_min_width (actor, g_value_get_float (value));
4135 case PROP_MIN_HEIGHT:
4136 clutter_actor_set_min_height (actor, g_value_get_float (value));
4139 case PROP_NATURAL_WIDTH:
4140 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4143 case PROP_NATURAL_HEIGHT:
4144 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4147 case PROP_MIN_WIDTH_SET:
4148 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4151 case PROP_MIN_HEIGHT_SET:
4152 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4155 case PROP_NATURAL_WIDTH_SET:
4156 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4159 case PROP_NATURAL_HEIGHT_SET:
4160 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4163 case PROP_REQUEST_MODE:
4164 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4168 clutter_actor_set_depth (actor, g_value_get_float (value));
4172 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4175 case PROP_OFFSCREEN_REDIRECT:
4176 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4180 clutter_actor_set_name (actor, g_value_get_string (value));
4184 if (g_value_get_boolean (value) == TRUE)
4185 clutter_actor_show (actor);
4187 clutter_actor_hide (actor);
4191 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4192 g_value_get_double (value));
4196 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4197 g_value_get_double (value));
4200 case PROP_SCALE_CENTER_X:
4201 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4202 g_value_get_float (value));
4205 case PROP_SCALE_CENTER_Y:
4206 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4207 g_value_get_float (value));
4210 case PROP_SCALE_GRAVITY:
4212 const ClutterTransformInfo *info;
4213 ClutterGravity gravity;
4215 info = _clutter_actor_get_transform_info_or_defaults (actor);
4216 gravity = g_value_get_enum (value);
4218 clutter_actor_set_scale_with_gravity (actor,
4227 const ClutterGeometry *geom = g_value_get_boxed (value);
4229 clutter_actor_set_clip (actor,
4231 geom->width, geom->height);
4235 case PROP_CLIP_TO_ALLOCATION:
4236 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4240 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4243 case PROP_ROTATION_ANGLE_X:
4244 clutter_actor_set_rotation_angle (actor,
4246 g_value_get_double (value));
4249 case PROP_ROTATION_ANGLE_Y:
4250 clutter_actor_set_rotation_angle (actor,
4252 g_value_get_double (value));
4255 case PROP_ROTATION_ANGLE_Z:
4256 clutter_actor_set_rotation_angle (actor,
4258 g_value_get_double (value));
4261 case PROP_ROTATION_CENTER_X:
4262 clutter_actor_set_rotation_center_internal (actor,
4264 g_value_get_boxed (value));
4267 case PROP_ROTATION_CENTER_Y:
4268 clutter_actor_set_rotation_center_internal (actor,
4270 g_value_get_boxed (value));
4273 case PROP_ROTATION_CENTER_Z:
4274 clutter_actor_set_rotation_center_internal (actor,
4276 g_value_get_boxed (value));
4279 case PROP_ROTATION_CENTER_Z_GRAVITY:
4281 const ClutterTransformInfo *info;
4283 info = _clutter_actor_get_transform_info_or_defaults (actor);
4284 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4285 g_value_get_enum (value));
4290 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4291 g_value_get_float (value));
4295 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4296 g_value_get_float (value));
4299 case PROP_ANCHOR_GRAVITY:
4300 clutter_actor_set_anchor_point_from_gravity (actor,
4301 g_value_get_enum (value));
4304 case PROP_SHOW_ON_SET_PARENT:
4305 priv->show_on_set_parent = g_value_get_boolean (value);
4308 case PROP_TEXT_DIRECTION:
4309 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4313 clutter_actor_add_action (actor, g_value_get_object (value));
4316 case PROP_CONSTRAINTS:
4317 clutter_actor_add_constraint (actor, g_value_get_object (value));
4321 clutter_actor_add_effect (actor, g_value_get_object (value));
4324 case PROP_LAYOUT_MANAGER:
4325 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4329 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4333 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4336 case PROP_MARGIN_TOP:
4337 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4340 case PROP_MARGIN_BOTTOM:
4341 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4344 case PROP_MARGIN_LEFT:
4345 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4348 case PROP_MARGIN_RIGHT:
4349 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4352 case PROP_BACKGROUND_COLOR:
4353 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4357 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4363 clutter_actor_get_property (GObject *object,
4368 ClutterActor *actor = CLUTTER_ACTOR (object);
4369 ClutterActorPrivate *priv = actor->priv;
4374 g_value_set_float (value, clutter_actor_get_x (actor));
4378 g_value_set_float (value, clutter_actor_get_y (actor));
4382 g_value_set_float (value, clutter_actor_get_width (actor));
4386 g_value_set_float (value, clutter_actor_get_height (actor));
4391 const ClutterLayoutInfo *info;
4393 info = _clutter_actor_get_layout_info_or_defaults (actor);
4394 g_value_set_float (value, info->fixed_x);
4400 const ClutterLayoutInfo *info;
4402 info = _clutter_actor_get_layout_info_or_defaults (actor);
4403 g_value_set_float (value, info->fixed_y);
4407 case PROP_FIXED_POSITION_SET:
4408 g_value_set_boolean (value, priv->position_set);
4411 case PROP_MIN_WIDTH:
4413 const ClutterLayoutInfo *info;
4415 info = _clutter_actor_get_layout_info_or_defaults (actor);
4416 g_value_set_float (value, info->min_width);
4420 case PROP_MIN_HEIGHT:
4422 const ClutterLayoutInfo *info;
4424 info = _clutter_actor_get_layout_info_or_defaults (actor);
4425 g_value_set_float (value, info->min_height);
4429 case PROP_NATURAL_WIDTH:
4431 const ClutterLayoutInfo *info;
4433 info = _clutter_actor_get_layout_info_or_defaults (actor);
4434 g_value_set_float (value, info->natural_width);
4438 case PROP_NATURAL_HEIGHT:
4440 const ClutterLayoutInfo *info;
4442 info = _clutter_actor_get_layout_info_or_defaults (actor);
4443 g_value_set_float (value, info->natural_height);
4447 case PROP_MIN_WIDTH_SET:
4448 g_value_set_boolean (value, priv->min_width_set);
4451 case PROP_MIN_HEIGHT_SET:
4452 g_value_set_boolean (value, priv->min_height_set);
4455 case PROP_NATURAL_WIDTH_SET:
4456 g_value_set_boolean (value, priv->natural_width_set);
4459 case PROP_NATURAL_HEIGHT_SET:
4460 g_value_set_boolean (value, priv->natural_height_set);
4463 case PROP_REQUEST_MODE:
4464 g_value_set_enum (value, priv->request_mode);
4467 case PROP_ALLOCATION:
4468 g_value_set_boxed (value, &priv->allocation);
4472 g_value_set_float (value, clutter_actor_get_depth (actor));
4476 g_value_set_uint (value, priv->opacity);
4479 case PROP_OFFSCREEN_REDIRECT:
4480 g_value_set_enum (value, priv->offscreen_redirect);
4484 g_value_set_string (value, priv->name);
4488 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4492 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4496 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4500 g_value_set_boolean (value, priv->has_clip);
4505 ClutterGeometry clip;
4507 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4508 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4509 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4510 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4512 g_value_set_boxed (value, &clip);
4516 case PROP_CLIP_TO_ALLOCATION:
4517 g_value_set_boolean (value, priv->clip_to_allocation);
4522 const ClutterTransformInfo *info;
4524 info = _clutter_actor_get_transform_info_or_defaults (actor);
4525 g_value_set_double (value, info->scale_x);
4531 const ClutterTransformInfo *info;
4533 info = _clutter_actor_get_transform_info_or_defaults (actor);
4534 g_value_set_double (value, info->scale_y);
4538 case PROP_SCALE_CENTER_X:
4542 clutter_actor_get_scale_center (actor, ¢er, NULL);
4544 g_value_set_float (value, center);
4548 case PROP_SCALE_CENTER_Y:
4552 clutter_actor_get_scale_center (actor, NULL, ¢er);
4554 g_value_set_float (value, center);
4558 case PROP_SCALE_GRAVITY:
4559 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4563 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4566 case PROP_ROTATION_ANGLE_X:
4568 const ClutterTransformInfo *info;
4570 info = _clutter_actor_get_transform_info_or_defaults (actor);
4571 g_value_set_double (value, info->rx_angle);
4575 case PROP_ROTATION_ANGLE_Y:
4577 const ClutterTransformInfo *info;
4579 info = _clutter_actor_get_transform_info_or_defaults (actor);
4580 g_value_set_double (value, info->ry_angle);
4584 case PROP_ROTATION_ANGLE_Z:
4586 const ClutterTransformInfo *info;
4588 info = _clutter_actor_get_transform_info_or_defaults (actor);
4589 g_value_set_double (value, info->rz_angle);
4593 case PROP_ROTATION_CENTER_X:
4595 ClutterVertex center;
4597 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4602 g_value_set_boxed (value, ¢er);
4606 case PROP_ROTATION_CENTER_Y:
4608 ClutterVertex center;
4610 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4615 g_value_set_boxed (value, ¢er);
4619 case PROP_ROTATION_CENTER_Z:
4621 ClutterVertex center;
4623 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4628 g_value_set_boxed (value, ¢er);
4632 case PROP_ROTATION_CENTER_Z_GRAVITY:
4633 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4638 const ClutterTransformInfo *info;
4641 info = _clutter_actor_get_transform_info_or_defaults (actor);
4642 clutter_anchor_coord_get_units (actor, &info->anchor,
4646 g_value_set_float (value, anchor_x);
4652 const ClutterTransformInfo *info;
4655 info = _clutter_actor_get_transform_info_or_defaults (actor);
4656 clutter_anchor_coord_get_units (actor, &info->anchor,
4660 g_value_set_float (value, anchor_y);
4664 case PROP_ANCHOR_GRAVITY:
4665 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4668 case PROP_SHOW_ON_SET_PARENT:
4669 g_value_set_boolean (value, priv->show_on_set_parent);
4672 case PROP_TEXT_DIRECTION:
4673 g_value_set_enum (value, priv->text_direction);
4676 case PROP_HAS_POINTER:
4677 g_value_set_boolean (value, priv->has_pointer);
4680 case PROP_LAYOUT_MANAGER:
4681 g_value_set_object (value, priv->layout_manager);
4686 const ClutterLayoutInfo *info;
4688 info = _clutter_actor_get_layout_info_or_defaults (actor);
4689 g_value_set_enum (value, info->x_align);
4695 const ClutterLayoutInfo *info;
4697 info = _clutter_actor_get_layout_info_or_defaults (actor);
4698 g_value_set_enum (value, info->y_align);
4702 case PROP_MARGIN_TOP:
4704 const ClutterLayoutInfo *info;
4706 info = _clutter_actor_get_layout_info_or_defaults (actor);
4707 g_value_set_float (value, info->margin.top);
4711 case PROP_MARGIN_BOTTOM:
4713 const ClutterLayoutInfo *info;
4715 info = _clutter_actor_get_layout_info_or_defaults (actor);
4716 g_value_set_float (value, info->margin.bottom);
4720 case PROP_MARGIN_LEFT:
4722 const ClutterLayoutInfo *info;
4724 info = _clutter_actor_get_layout_info_or_defaults (actor);
4725 g_value_set_float (value, info->margin.left);
4729 case PROP_MARGIN_RIGHT:
4731 const ClutterLayoutInfo *info;
4733 info = _clutter_actor_get_layout_info_or_defaults (actor);
4734 g_value_set_float (value, info->margin.right);
4738 case PROP_BACKGROUND_COLOR_SET:
4739 g_value_set_boolean (value, priv->bg_color_set);
4742 case PROP_BACKGROUND_COLOR:
4743 g_value_set_boxed (value, &priv->bg_color);
4746 case PROP_FIRST_CHILD:
4747 g_value_set_object (value, priv->first_child);
4750 case PROP_LAST_CHILD:
4751 g_value_set_object (value, priv->last_child);
4755 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4761 clutter_actor_dispose (GObject *object)
4763 ClutterActor *self = CLUTTER_ACTOR (object);
4764 ClutterActorPrivate *priv = self->priv;
4766 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4768 g_type_name (G_OBJECT_TYPE (self)),
4771 g_signal_emit (self, actor_signals[DESTROY], 0);
4773 /* avoid recursing when called from clutter_actor_destroy() */
4774 if (priv->parent != NULL)
4776 ClutterActor *parent = priv->parent;
4778 /* go through the Container implementation unless this
4779 * is an internal child and has been marked as such.
4781 * removing the actor from its parent will reset the
4782 * realized and mapped states.
4784 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4785 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4787 clutter_actor_remove_child_internal (parent, self,
4788 REMOVE_CHILD_LEGACY_FLAGS);
4791 /* parent must be gone at this point */
4792 g_assert (priv->parent == NULL);
4794 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4796 /* can't be mapped or realized with no parent */
4797 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4798 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4801 g_clear_object (&priv->pango_context);
4802 g_clear_object (&priv->actions);
4803 g_clear_object (&priv->constraints);
4804 g_clear_object (&priv->effects);
4805 g_clear_object (&priv->flatten_effect);
4807 if (priv->layout_manager != NULL)
4809 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4810 g_object_unref (priv->layout_manager);
4811 priv->layout_manager = NULL;
4814 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4818 clutter_actor_finalize (GObject *object)
4820 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4822 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4823 priv->name != NULL ? priv->name : "<none>",
4825 g_type_name (G_OBJECT_TYPE (object)));
4827 _clutter_context_release_id (priv->id);
4829 g_free (priv->name);
4831 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
4836 * clutter_actor_get_accessible:
4837 * @self: a #ClutterActor
4839 * Returns the accessible object that describes the actor to an
4840 * assistive technology.
4842 * If no class-specific #AtkObject implementation is available for the
4843 * actor instance in question, it will inherit an #AtkObject
4844 * implementation from the first ancestor class for which such an
4845 * implementation is defined.
4847 * The documentation of the <ulink
4848 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
4849 * library contains more information about accessible objects and
4852 * Returns: (transfer none): the #AtkObject associated with @actor
4855 clutter_actor_get_accessible (ClutterActor *self)
4857 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
4859 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
4863 clutter_actor_real_get_accessible (ClutterActor *actor)
4865 return atk_gobject_accessible_for_object (G_OBJECT (actor));
4869 _clutter_actor_ref_accessible (AtkImplementor *implementor)
4871 AtkObject *accessible;
4873 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
4874 if (accessible != NULL)
4875 g_object_ref (accessible);
4881 atk_implementor_iface_init (AtkImplementorIface *iface)
4883 iface->ref_accessible = _clutter_actor_ref_accessible;
4887 clutter_actor_update_default_paint_volume (ClutterActor *self,
4888 ClutterPaintVolume *volume)
4890 ClutterActorPrivate *priv = self->priv;
4891 gboolean res = FALSE;
4893 /* we start from the allocation */
4894 clutter_paint_volume_set_width (volume,
4895 priv->allocation.x2 - priv->allocation.x1);
4896 clutter_paint_volume_set_height (volume,
4897 priv->allocation.y2 - priv->allocation.y1);
4899 /* if the actor has a clip set then we have a pretty definite
4900 * size for the paint volume: the actor cannot possibly paint
4901 * outside the clip region.
4903 if (priv->clip_to_allocation)
4905 /* the allocation has already been set, so we just flip the
4912 ClutterActor *child;
4914 if (priv->has_clip &&
4915 priv->clip.width >= 0 &&
4916 priv->clip.height >= 0)
4918 ClutterVertex origin;
4920 origin.x = priv->clip.x;
4921 origin.y = priv->clip.y;
4924 clutter_paint_volume_set_origin (volume, &origin);
4925 clutter_paint_volume_set_width (volume, priv->clip.width);
4926 clutter_paint_volume_set_height (volume, priv->clip.height);
4931 /* if we don't have children we just bail out here... */
4932 if (priv->n_children == 0)
4935 /* ...but if we have children then we ask for their paint volume in
4936 * our coordinates. if any of our children replies that it doesn't
4937 * have a paint volume, we bail out
4939 for (child = priv->first_child;
4941 child = child->priv->next_sibling)
4943 const ClutterPaintVolume *child_volume;
4945 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
4946 if (child_volume == NULL)
4952 clutter_paint_volume_union (volume, child_volume);
4962 clutter_actor_real_get_paint_volume (ClutterActor *self,
4963 ClutterPaintVolume *volume)
4965 ClutterActorClass *klass;
4968 klass = CLUTTER_ACTOR_GET_CLASS (self);
4970 /* XXX - this thoroughly sucks, but we don't want to penalize users
4971 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
4972 * redraw. This should go away in 2.0.
4974 if (klass->paint == clutter_actor_real_paint &&
4975 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
4981 /* this is the default return value: we cannot know if a class
4982 * is going to paint outside its allocation, so we take the
4983 * conservative approach.
4988 if (clutter_actor_update_default_paint_volume (self, volume))
4995 * clutter_actor_get_default_paint_volume:
4996 * @self: a #ClutterActor
4998 * Retrieves the default paint volume for @self.
5000 * This function provides the same #ClutterPaintVolume that would be
5001 * computed by the default implementation inside #ClutterActor of the
5002 * #ClutterActorClass.get_paint_volume() virtual function.
5004 * This function should only be used by #ClutterActor subclasses that
5005 * cannot chain up to the parent implementation when computing their
5008 * Return value: (transfer none): a pointer to the default
5009 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5010 * the actor could not compute a valid paint volume. The returned value
5011 * is not guaranteed to be stable across multiple frames, so if you
5012 * want to retain it, you will need to copy it using
5013 * clutter_paint_volume_copy().
5017 const ClutterPaintVolume *
5018 clutter_actor_get_default_paint_volume (ClutterActor *self)
5020 ClutterPaintVolume volume;
5021 ClutterPaintVolume *res;
5023 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5026 _clutter_paint_volume_init_static (&volume, self);
5027 if (clutter_actor_update_default_paint_volume (self, &volume))
5029 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5033 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5034 _clutter_paint_volume_copy_static (&volume, res);
5038 clutter_paint_volume_free (&volume);
5044 clutter_actor_real_has_overlaps (ClutterActor *self)
5046 /* By default we'll assume that all actors need an offscreen redirect to get
5047 * the correct opacity. Actors such as ClutterTexture that would never need
5048 * an offscreen redirect can override this to return FALSE. */
5053 clutter_actor_real_destroy (ClutterActor *actor)
5055 ClutterActorIter iter;
5057 clutter_actor_iter_init (&iter, actor);
5058 while (clutter_actor_iter_next (&iter, NULL))
5059 clutter_actor_iter_destroy (&iter);
5063 clutter_actor_constructor (GType gtype,
5065 GObjectConstructParam *props)
5067 GObjectClass *gobject_class;
5071 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5072 retval = gobject_class->constructor (gtype, n_props, props);
5073 self = CLUTTER_ACTOR (retval);
5075 if (self->priv->layout_manager == NULL)
5077 ClutterLayoutManager *default_layout;
5079 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5081 default_layout = clutter_fixed_layout_new ();
5082 clutter_actor_set_layout_manager (self, default_layout);
5089 clutter_actor_class_init (ClutterActorClass *klass)
5091 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5093 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5094 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5095 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5096 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5098 object_class->constructor = clutter_actor_constructor;
5099 object_class->set_property = clutter_actor_set_property;
5100 object_class->get_property = clutter_actor_get_property;
5101 object_class->dispose = clutter_actor_dispose;
5102 object_class->finalize = clutter_actor_finalize;
5104 klass->show = clutter_actor_real_show;
5105 klass->show_all = clutter_actor_show;
5106 klass->hide = clutter_actor_real_hide;
5107 klass->hide_all = clutter_actor_hide;
5108 klass->map = clutter_actor_real_map;
5109 klass->unmap = clutter_actor_real_unmap;
5110 klass->unrealize = clutter_actor_real_unrealize;
5111 klass->pick = clutter_actor_real_pick;
5112 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5113 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5114 klass->allocate = clutter_actor_real_allocate;
5115 klass->queue_redraw = clutter_actor_real_queue_redraw;
5116 klass->queue_relayout = clutter_actor_real_queue_relayout;
5117 klass->apply_transform = clutter_actor_real_apply_transform;
5118 klass->get_accessible = clutter_actor_real_get_accessible;
5119 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5120 klass->has_overlaps = clutter_actor_real_has_overlaps;
5121 klass->paint = clutter_actor_real_paint;
5122 klass->destroy = clutter_actor_real_destroy;
5124 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5129 * X coordinate of the actor in pixels. If written, forces a fixed
5130 * position for the actor. If read, returns the fixed position if any,
5131 * otherwise the allocation if available, otherwise 0.
5133 * The #ClutterActor:x property is animatable.
5136 g_param_spec_float ("x",
5138 P_("X coordinate of the actor"),
5139 -G_MAXFLOAT, G_MAXFLOAT,
5142 G_PARAM_STATIC_STRINGS |
5143 CLUTTER_PARAM_ANIMATABLE);
5148 * Y coordinate of the actor in pixels. If written, forces a fixed
5149 * position for the actor. If read, returns the fixed position if
5150 * any, otherwise the allocation if available, otherwise 0.
5152 * The #ClutterActor:y property is animatable.
5155 g_param_spec_float ("y",
5157 P_("Y coordinate of the actor"),
5158 -G_MAXFLOAT, G_MAXFLOAT,
5161 G_PARAM_STATIC_STRINGS |
5162 CLUTTER_PARAM_ANIMATABLE);
5165 * ClutterActor:width:
5167 * Width of the actor (in pixels). If written, forces the minimum and
5168 * natural size request of the actor to the given width. If read, returns
5169 * the allocated width if available, otherwise the width request.
5171 * The #ClutterActor:width property is animatable.
5173 obj_props[PROP_WIDTH] =
5174 g_param_spec_float ("width",
5176 P_("Width of the actor"),
5180 G_PARAM_STATIC_STRINGS |
5181 CLUTTER_PARAM_ANIMATABLE);
5184 * ClutterActor:height:
5186 * Height of the actor (in pixels). If written, forces the minimum and
5187 * natural size request of the actor to the given height. If read, returns
5188 * the allocated height if available, otherwise the height request.
5190 * The #ClutterActor:height property is animatable.
5192 obj_props[PROP_HEIGHT] =
5193 g_param_spec_float ("height",
5195 P_("Height of the actor"),
5199 G_PARAM_STATIC_STRINGS |
5200 CLUTTER_PARAM_ANIMATABLE);
5203 * ClutterActor:fixed-x:
5205 * The fixed X position of the actor in pixels.
5207 * Writing this property sets #ClutterActor:fixed-position-set
5208 * property as well, as a side effect
5212 obj_props[PROP_FIXED_X] =
5213 g_param_spec_float ("fixed-x",
5215 P_("Forced X position of the actor"),
5216 -G_MAXFLOAT, G_MAXFLOAT,
5218 CLUTTER_PARAM_READWRITE);
5221 * ClutterActor:fixed-y:
5223 * The fixed Y position of the actor in pixels.
5225 * Writing this property sets the #ClutterActor:fixed-position-set
5226 * property as well, as a side effect
5230 obj_props[PROP_FIXED_Y] =
5231 g_param_spec_float ("fixed-y",
5233 P_("Forced Y position of the actor"),
5234 -G_MAXFLOAT, G_MAXFLOAT,
5236 CLUTTER_PARAM_READWRITE);
5239 * ClutterActor:fixed-position-set:
5241 * This flag controls whether the #ClutterActor:fixed-x and
5242 * #ClutterActor:fixed-y properties are used
5246 obj_props[PROP_FIXED_POSITION_SET] =
5247 g_param_spec_boolean ("fixed-position-set",
5248 P_("Fixed position set"),
5249 P_("Whether to use fixed positioning for the actor"),
5251 CLUTTER_PARAM_READWRITE);
5254 * ClutterActor:min-width:
5256 * A forced minimum width request for the actor, in pixels
5258 * Writing this property sets the #ClutterActor:min-width-set property
5259 * as well, as a side effect.
5261 *This property overrides the usual width request of the actor.
5265 obj_props[PROP_MIN_WIDTH] =
5266 g_param_spec_float ("min-width",
5268 P_("Forced minimum width request for the actor"),
5271 CLUTTER_PARAM_READWRITE);
5274 * ClutterActor:min-height:
5276 * A forced minimum height request for the actor, in pixels
5278 * Writing this property sets the #ClutterActor:min-height-set property
5279 * as well, as a side effect. This property overrides the usual height
5280 * request of the actor.
5284 obj_props[PROP_MIN_HEIGHT] =
5285 g_param_spec_float ("min-height",
5287 P_("Forced minimum height request for the actor"),
5290 CLUTTER_PARAM_READWRITE);
5293 * ClutterActor:natural-width:
5295 * A forced natural width request for the actor, in pixels
5297 * Writing this property sets the #ClutterActor:natural-width-set
5298 * property as well, as a side effect. This property overrides the
5299 * usual width request of the actor
5303 obj_props[PROP_NATURAL_WIDTH] =
5304 g_param_spec_float ("natural-width",
5305 P_("Natural Width"),
5306 P_("Forced natural width request for the actor"),
5309 CLUTTER_PARAM_READWRITE);
5312 * ClutterActor:natural-height:
5314 * A forced natural height request for the actor, in pixels
5316 * Writing this property sets the #ClutterActor:natural-height-set
5317 * property as well, as a side effect. This property overrides the
5318 * usual height request of the actor
5322 obj_props[PROP_NATURAL_HEIGHT] =
5323 g_param_spec_float ("natural-height",
5324 P_("Natural Height"),
5325 P_("Forced natural height request for the actor"),
5328 CLUTTER_PARAM_READWRITE);
5331 * ClutterActor:min-width-set:
5333 * This flag controls whether the #ClutterActor:min-width property
5338 obj_props[PROP_MIN_WIDTH_SET] =
5339 g_param_spec_boolean ("min-width-set",
5340 P_("Minimum width set"),
5341 P_("Whether to use the min-width property"),
5343 CLUTTER_PARAM_READWRITE);
5346 * ClutterActor:min-height-set:
5348 * This flag controls whether the #ClutterActor:min-height property
5353 obj_props[PROP_MIN_HEIGHT_SET] =
5354 g_param_spec_boolean ("min-height-set",
5355 P_("Minimum height set"),
5356 P_("Whether to use the min-height property"),
5358 CLUTTER_PARAM_READWRITE);
5361 * ClutterActor:natural-width-set:
5363 * This flag controls whether the #ClutterActor:natural-width property
5368 obj_props[PROP_NATURAL_WIDTH_SET] =
5369 g_param_spec_boolean ("natural-width-set",
5370 P_("Natural width set"),
5371 P_("Whether to use the natural-width property"),
5373 CLUTTER_PARAM_READWRITE);
5376 * ClutterActor:natural-height-set:
5378 * This flag controls whether the #ClutterActor:natural-height property
5383 obj_props[PROP_NATURAL_HEIGHT_SET] =
5384 g_param_spec_boolean ("natural-height-set",
5385 P_("Natural height set"),
5386 P_("Whether to use the natural-height property"),
5388 CLUTTER_PARAM_READWRITE);
5391 * ClutterActor:allocation:
5393 * The allocation for the actor, in pixels
5395 * This is property is read-only, but you might monitor it to know when an
5396 * actor moves or resizes
5400 obj_props[PROP_ALLOCATION] =
5401 g_param_spec_boxed ("allocation",
5403 P_("The actor's allocation"),
5404 CLUTTER_TYPE_ACTOR_BOX,
5405 CLUTTER_PARAM_READABLE);
5408 * ClutterActor:request-mode:
5410 * Request mode for the #ClutterActor. The request mode determines the
5411 * type of geometry management used by the actor, either height for width
5412 * (the default) or width for height.
5414 * For actors implementing height for width, the parent container should get
5415 * the preferred width first, and then the preferred height for that width.
5417 * For actors implementing width for height, the parent container should get
5418 * the preferred height first, and then the preferred width for that height.
5423 * ClutterRequestMode mode;
5424 * gfloat natural_width, min_width;
5425 * gfloat natural_height, min_height;
5427 * mode = clutter_actor_get_request_mode (child);
5428 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5430 * clutter_actor_get_preferred_width (child, -1,
5432 * &natural_width);
5433 * clutter_actor_get_preferred_height (child, natural_width,
5435 * &natural_height);
5439 * clutter_actor_get_preferred_height (child, -1,
5441 * &natural_height);
5442 * clutter_actor_get_preferred_width (child, natural_height,
5444 * &natural_width);
5448 * will retrieve the minimum and natural width and height depending on the
5449 * preferred request mode of the #ClutterActor "child".
5451 * The clutter_actor_get_preferred_size() function will implement this
5456 obj_props[PROP_REQUEST_MODE] =
5457 g_param_spec_enum ("request-mode",
5459 P_("The actor's request mode"),
5460 CLUTTER_TYPE_REQUEST_MODE,
5461 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5462 CLUTTER_PARAM_READWRITE);
5465 * ClutterActor:depth:
5467 * The position of the actor on the Z axis.
5469 * The #ClutterActor:depth property is relative to the parent's
5472 * The #ClutterActor:depth property is animatable.
5476 obj_props[PROP_DEPTH] =
5477 g_param_spec_float ("depth",
5479 P_("Position on the Z axis"),
5480 -G_MAXFLOAT, G_MAXFLOAT,
5483 G_PARAM_STATIC_STRINGS |
5484 CLUTTER_PARAM_ANIMATABLE);
5487 * ClutterActor:opacity:
5489 * Opacity of an actor, between 0 (fully transparent) and
5490 * 255 (fully opaque)
5492 * The #ClutterActor:opacity property is animatable.
5494 obj_props[PROP_OPACITY] =
5495 g_param_spec_uint ("opacity",
5497 P_("Opacity of an actor"),
5501 G_PARAM_STATIC_STRINGS |
5502 CLUTTER_PARAM_ANIMATABLE);
5505 * ClutterActor:offscreen-redirect:
5507 * Determines the conditions in which the actor will be redirected
5508 * to an offscreen framebuffer while being painted. For example this
5509 * can be used to cache an actor in a framebuffer or for improved
5510 * handling of transparent actors. See
5511 * clutter_actor_set_offscreen_redirect() for details.
5515 obj_props[PROP_OFFSCREEN_REDIRECT] =
5516 g_param_spec_flags ("offscreen-redirect",
5517 P_("Offscreen redirect"),
5518 P_("Flags controlling when to flatten the actor into a single image"),
5519 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5521 CLUTTER_PARAM_READWRITE);
5524 * ClutterActor:visible:
5526 * Whether the actor is set to be visible or not
5528 * See also #ClutterActor:mapped
5530 obj_props[PROP_VISIBLE] =
5531 g_param_spec_boolean ("visible",
5533 P_("Whether the actor is visible or not"),
5535 CLUTTER_PARAM_READWRITE);
5538 * ClutterActor:mapped:
5540 * Whether the actor is mapped (will be painted when the stage
5541 * to which it belongs is mapped)
5545 obj_props[PROP_MAPPED] =
5546 g_param_spec_boolean ("mapped",
5548 P_("Whether the actor will be painted"),
5550 CLUTTER_PARAM_READABLE);
5553 * ClutterActor:realized:
5555 * Whether the actor has been realized
5559 obj_props[PROP_REALIZED] =
5560 g_param_spec_boolean ("realized",
5562 P_("Whether the actor has been realized"),
5564 CLUTTER_PARAM_READABLE);
5567 * ClutterActor:reactive:
5569 * Whether the actor is reactive to events or not
5571 * Only reactive actors will emit event-related signals
5575 obj_props[PROP_REACTIVE] =
5576 g_param_spec_boolean ("reactive",
5578 P_("Whether the actor is reactive to events"),
5580 CLUTTER_PARAM_READWRITE);
5583 * ClutterActor:has-clip:
5585 * Whether the actor has the #ClutterActor:clip property set or not
5587 obj_props[PROP_HAS_CLIP] =
5588 g_param_spec_boolean ("has-clip",
5590 P_("Whether the actor has a clip set"),
5592 CLUTTER_PARAM_READABLE);
5595 * ClutterActor:clip:
5597 * The clip region for the actor, in actor-relative coordinates
5599 * Every part of the actor outside the clip region will not be
5602 obj_props[PROP_CLIP] =
5603 g_param_spec_boxed ("clip",
5605 P_("The clip region for the actor"),
5606 CLUTTER_TYPE_GEOMETRY,
5607 CLUTTER_PARAM_READWRITE);
5610 * ClutterActor:name:
5612 * The name of the actor
5616 obj_props[PROP_NAME] =
5617 g_param_spec_string ("name",
5619 P_("Name of the actor"),
5621 CLUTTER_PARAM_READWRITE);
5624 * ClutterActor:scale-x:
5626 * The horizontal scale of the actor.
5628 * The #ClutterActor:scale-x property is animatable.
5632 obj_props[PROP_SCALE_X] =
5633 g_param_spec_double ("scale-x",
5635 P_("Scale factor on the X axis"),
5639 G_PARAM_STATIC_STRINGS |
5640 CLUTTER_PARAM_ANIMATABLE);
5643 * ClutterActor:scale-y:
5645 * The vertical scale of the actor.
5647 * The #ClutterActor:scale-y property is animatable.
5651 obj_props[PROP_SCALE_Y] =
5652 g_param_spec_double ("scale-y",
5654 P_("Scale factor on the Y axis"),
5658 G_PARAM_STATIC_STRINGS |
5659 CLUTTER_PARAM_ANIMATABLE);
5662 * ClutterActor:scale-center-x:
5664 * The horizontal center point for scaling
5668 obj_props[PROP_SCALE_CENTER_X] =
5669 g_param_spec_float ("scale-center-x",
5670 P_("Scale Center X"),
5671 P_("Horizontal scale center"),
5672 -G_MAXFLOAT, G_MAXFLOAT,
5674 CLUTTER_PARAM_READWRITE);
5677 * ClutterActor:scale-center-y:
5679 * The vertical center point for scaling
5683 obj_props[PROP_SCALE_CENTER_Y] =
5684 g_param_spec_float ("scale-center-y",
5685 P_("Scale Center Y"),
5686 P_("Vertical scale center"),
5687 -G_MAXFLOAT, G_MAXFLOAT,
5689 CLUTTER_PARAM_READWRITE);
5692 * ClutterActor:scale-gravity:
5694 * The center point for scaling expressed as a #ClutterGravity
5698 obj_props[PROP_SCALE_GRAVITY] =
5699 g_param_spec_enum ("scale-gravity",
5700 P_("Scale Gravity"),
5701 P_("The center of scaling"),
5702 CLUTTER_TYPE_GRAVITY,
5703 CLUTTER_GRAVITY_NONE,
5704 CLUTTER_PARAM_READWRITE);
5707 * ClutterActor:rotation-angle-x:
5709 * The rotation angle on the X axis.
5711 * The #ClutterActor:rotation-angle-x property is animatable.
5715 obj_props[PROP_ROTATION_ANGLE_X] =
5716 g_param_spec_double ("rotation-angle-x",
5717 P_("Rotation Angle X"),
5718 P_("The rotation angle on the X axis"),
5719 -G_MAXDOUBLE, G_MAXDOUBLE,
5722 G_PARAM_STATIC_STRINGS |
5723 CLUTTER_PARAM_ANIMATABLE);
5726 * ClutterActor:rotation-angle-y:
5728 * The rotation angle on the Y axis
5730 * The #ClutterActor:rotation-angle-y property is animatable.
5734 obj_props[PROP_ROTATION_ANGLE_Y] =
5735 g_param_spec_double ("rotation-angle-y",
5736 P_("Rotation Angle Y"),
5737 P_("The rotation angle on the Y axis"),
5738 -G_MAXDOUBLE, G_MAXDOUBLE,
5741 G_PARAM_STATIC_STRINGS |
5742 CLUTTER_PARAM_ANIMATABLE);
5745 * ClutterActor:rotation-angle-z:
5747 * The rotation angle on the Z axis
5749 * The #ClutterActor:rotation-angle-z property is animatable.
5753 obj_props[PROP_ROTATION_ANGLE_Z] =
5754 g_param_spec_double ("rotation-angle-z",
5755 P_("Rotation Angle Z"),
5756 P_("The rotation angle on the Z axis"),
5757 -G_MAXDOUBLE, G_MAXDOUBLE,
5760 G_PARAM_STATIC_STRINGS |
5761 CLUTTER_PARAM_ANIMATABLE);
5764 * ClutterActor:rotation-center-x:
5766 * The rotation center on the X axis.
5770 obj_props[PROP_ROTATION_CENTER_X] =
5771 g_param_spec_boxed ("rotation-center-x",
5772 P_("Rotation Center X"),
5773 P_("The rotation center on the X axis"),
5774 CLUTTER_TYPE_VERTEX,
5775 CLUTTER_PARAM_READWRITE);
5778 * ClutterActor:rotation-center-y:
5780 * The rotation center on the Y axis.
5784 obj_props[PROP_ROTATION_CENTER_Y] =
5785 g_param_spec_boxed ("rotation-center-y",
5786 P_("Rotation Center Y"),
5787 P_("The rotation center on the Y axis"),
5788 CLUTTER_TYPE_VERTEX,
5789 CLUTTER_PARAM_READWRITE);
5792 * ClutterActor:rotation-center-z:
5794 * The rotation center on the Z axis.
5798 obj_props[PROP_ROTATION_CENTER_Z] =
5799 g_param_spec_boxed ("rotation-center-z",
5800 P_("Rotation Center Z"),
5801 P_("The rotation center on the Z axis"),
5802 CLUTTER_TYPE_VERTEX,
5803 CLUTTER_PARAM_READWRITE);
5806 * ClutterActor:rotation-center-z-gravity:
5808 * The rotation center on the Z axis expressed as a #ClutterGravity.
5812 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5813 g_param_spec_enum ("rotation-center-z-gravity",
5814 P_("Rotation Center Z Gravity"),
5815 P_("Center point for rotation around the Z axis"),
5816 CLUTTER_TYPE_GRAVITY,
5817 CLUTTER_GRAVITY_NONE,
5818 CLUTTER_PARAM_READWRITE);
5821 * ClutterActor:anchor-x:
5823 * The X coordinate of an actor's anchor point, relative to
5824 * the actor coordinate space, in pixels
5828 obj_props[PROP_ANCHOR_X] =
5829 g_param_spec_float ("anchor-x",
5831 P_("X coordinate of the anchor point"),
5832 -G_MAXFLOAT, G_MAXFLOAT,
5834 CLUTTER_PARAM_READWRITE);
5837 * ClutterActor:anchor-y:
5839 * The Y coordinate of an actor's anchor point, relative to
5840 * the actor coordinate space, in pixels
5844 obj_props[PROP_ANCHOR_Y] =
5845 g_param_spec_float ("anchor-y",
5847 P_("Y coordinate of the anchor point"),
5848 -G_MAXFLOAT, G_MAXFLOAT,
5850 CLUTTER_PARAM_READWRITE);
5853 * ClutterActor:anchor-gravity:
5855 * The anchor point expressed as a #ClutterGravity
5859 obj_props[PROP_ANCHOR_GRAVITY] =
5860 g_param_spec_enum ("anchor-gravity",
5861 P_("Anchor Gravity"),
5862 P_("The anchor point as a ClutterGravity"),
5863 CLUTTER_TYPE_GRAVITY,
5864 CLUTTER_GRAVITY_NONE,
5865 CLUTTER_PARAM_READWRITE);
5868 * ClutterActor:show-on-set-parent:
5870 * If %TRUE, the actor is automatically shown when parented.
5872 * Calling clutter_actor_hide() on an actor which has not been
5873 * parented will set this property to %FALSE as a side effect.
5877 obj_props[PROP_SHOW_ON_SET_PARENT] =
5878 g_param_spec_boolean ("show-on-set-parent",
5879 P_("Show on set parent"),
5880 P_("Whether the actor is shown when parented"),
5882 CLUTTER_PARAM_READWRITE);
5885 * ClutterActor:clip-to-allocation:
5887 * Whether the clip region should track the allocated area
5890 * This property is ignored if a clip area has been explicitly
5891 * set using clutter_actor_set_clip().
5895 obj_props[PROP_CLIP_TO_ALLOCATION] =
5896 g_param_spec_boolean ("clip-to-allocation",
5897 P_("Clip to Allocation"),
5898 P_("Sets the clip region to track the actor's allocation"),
5900 CLUTTER_PARAM_READWRITE);
5903 * ClutterActor:text-direction:
5905 * The direction of the text inside a #ClutterActor.
5909 obj_props[PROP_TEXT_DIRECTION] =
5910 g_param_spec_enum ("text-direction",
5911 P_("Text Direction"),
5912 P_("Direction of the text"),
5913 CLUTTER_TYPE_TEXT_DIRECTION,
5914 CLUTTER_TEXT_DIRECTION_LTR,
5915 CLUTTER_PARAM_READWRITE);
5918 * ClutterActor:has-pointer:
5920 * Whether the actor contains the pointer of a #ClutterInputDevice
5925 obj_props[PROP_HAS_POINTER] =
5926 g_param_spec_boolean ("has-pointer",
5928 P_("Whether the actor contains the pointer of an input device"),
5930 CLUTTER_PARAM_READABLE);
5933 * ClutterActor:actions:
5935 * Adds a #ClutterAction to the actor
5939 obj_props[PROP_ACTIONS] =
5940 g_param_spec_object ("actions",
5942 P_("Adds an action to the actor"),
5943 CLUTTER_TYPE_ACTION,
5944 CLUTTER_PARAM_WRITABLE);
5947 * ClutterActor:constraints:
5949 * Adds a #ClutterConstraint to the actor
5953 obj_props[PROP_CONSTRAINTS] =
5954 g_param_spec_object ("constraints",
5956 P_("Adds a constraint to the actor"),
5957 CLUTTER_TYPE_CONSTRAINT,
5958 CLUTTER_PARAM_WRITABLE);
5961 * ClutterActor:effect:
5963 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
5967 obj_props[PROP_EFFECT] =
5968 g_param_spec_object ("effect",
5970 P_("Add an effect to be applied on the actor"),
5971 CLUTTER_TYPE_EFFECT,
5972 CLUTTER_PARAM_WRITABLE);
5975 * ClutterActor:layout-manager:
5977 * A delegate object for controlling the layout of the children of
5982 obj_props[PROP_LAYOUT_MANAGER] =
5983 g_param_spec_object ("layout-manager",
5984 P_("Layout Manager"),
5985 P_("The object controlling the layout of an actor's children"),
5986 CLUTTER_TYPE_LAYOUT_MANAGER,
5987 CLUTTER_PARAM_READWRITE);
5991 * ClutterActor:x-align:
5993 * The alignment of an actor on the X axis, if the actor has been given
5994 * extra space for its allocation.
5998 obj_props[PROP_X_ALIGN] =
5999 g_param_spec_enum ("x-align",
6001 P_("The alignment of the actor on the X axis within its allocation"),
6002 CLUTTER_TYPE_ACTOR_ALIGN,
6003 CLUTTER_ACTOR_ALIGN_FILL,
6004 CLUTTER_PARAM_READWRITE);
6007 * ClutterActor:y-align:
6009 * The alignment of an actor on the Y axis, if the actor has been given
6010 * extra space for its allocation.
6014 obj_props[PROP_Y_ALIGN] =
6015 g_param_spec_enum ("y-align",
6017 P_("The alignment of the actor on the Y axis within its allocation"),
6018 CLUTTER_TYPE_ACTOR_ALIGN,
6019 CLUTTER_ACTOR_ALIGN_FILL,
6020 CLUTTER_PARAM_READWRITE);
6023 * ClutterActor:margin-top:
6025 * The margin (in pixels) from the top of the actor.
6027 * This property adds a margin to the actor's preferred size; the margin
6028 * will be automatically taken into account when allocating the actor.
6032 obj_props[PROP_MARGIN_TOP] =
6033 g_param_spec_float ("margin-top",
6035 P_("Extra space at the top"),
6038 CLUTTER_PARAM_READWRITE);
6041 * ClutterActor:margin-bottom:
6043 * The margin (in pixels) from the bottom of the actor.
6045 * This property adds a margin to the actor's preferred size; the margin
6046 * will be automatically taken into account when allocating the actor.
6050 obj_props[PROP_MARGIN_BOTTOM] =
6051 g_param_spec_float ("margin-bottom",
6052 P_("Margin Bottom"),
6053 P_("Extra space at the bottom"),
6056 CLUTTER_PARAM_READWRITE);
6059 * ClutterActor:margin-left:
6061 * The margin (in pixels) from the left of the actor.
6063 * This property adds a margin to the actor's preferred size; the margin
6064 * will be automatically taken into account when allocating the actor.
6068 obj_props[PROP_MARGIN_LEFT] =
6069 g_param_spec_float ("margin-left",
6071 P_("Extra space at the left"),
6074 CLUTTER_PARAM_READWRITE);
6077 * ClutterActor:margin-right:
6079 * The margin (in pixels) from the right of the actor.
6081 * This property adds a margin to the actor's preferred size; the margin
6082 * will be automatically taken into account when allocating the actor.
6086 obj_props[PROP_MARGIN_RIGHT] =
6087 g_param_spec_float ("margin-right",
6089 P_("Extra space at the right"),
6092 CLUTTER_PARAM_READWRITE);
6095 * ClutterActor:background-color-set:
6097 * Whether the #ClutterActor:background-color property has been set.
6101 obj_props[PROP_BACKGROUND_COLOR_SET] =
6102 g_param_spec_boolean ("background-color-set",
6103 P_("Background Color Set"),
6104 P_("Whether the background color is set"),
6106 CLUTTER_PARAM_READABLE);
6109 * ClutterActor:background-color:
6111 * Paints a solid fill of the actor's allocation using the specified
6114 * The #ClutterActor:background-color property is animatable.
6118 obj_props[PROP_BACKGROUND_COLOR] =
6119 clutter_param_spec_color ("background-color",
6120 P_("Background color"),
6121 P_("The actor's background color"),
6122 CLUTTER_COLOR_Transparent,
6124 G_PARAM_STATIC_STRINGS |
6125 CLUTTER_PARAM_ANIMATABLE);
6128 * ClutterActor:first-child:
6130 * The actor's first child.
6134 obj_props[PROP_FIRST_CHILD] =
6135 g_param_spec_object ("first-child",
6137 P_("The actor's first child"),
6139 CLUTTER_PARAM_READABLE);
6142 * ClutterActor:last-child:
6144 * The actor's last child.
6148 obj_props[PROP_LAST_CHILD] =
6149 g_param_spec_object ("last-child",
6151 P_("The actor's last child"),
6153 CLUTTER_PARAM_READABLE);
6155 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6158 * ClutterActor::destroy:
6159 * @actor: the #ClutterActor which emitted the signal
6161 * The ::destroy signal notifies that all references held on the
6162 * actor which emitted it should be released.
6164 * The ::destroy signal should be used by all holders of a reference
6167 * This signal might result in the finalization of the #ClutterActor
6168 * if all references are released.
6170 * Composite actors and actors implementing the #ClutterContainer
6171 * interface should override the default implementation of the
6172 * class handler of this signal and call clutter_actor_destroy() on
6173 * their children. When overriding the default class handler, it is
6174 * required to chain up to the parent's implementation.
6178 actor_signals[DESTROY] =
6179 g_signal_new (I_("destroy"),
6180 G_TYPE_FROM_CLASS (object_class),
6181 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6182 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6184 _clutter_marshal_VOID__VOID,
6187 * ClutterActor::show:
6188 * @actor: the object which received the signal
6190 * The ::show signal is emitted when an actor is visible and
6191 * rendered on the stage.
6195 actor_signals[SHOW] =
6196 g_signal_new (I_("show"),
6197 G_TYPE_FROM_CLASS (object_class),
6199 G_STRUCT_OFFSET (ClutterActorClass, show),
6201 _clutter_marshal_VOID__VOID,
6204 * ClutterActor::hide:
6205 * @actor: the object which received the signal
6207 * The ::hide signal is emitted when an actor is no longer rendered
6212 actor_signals[HIDE] =
6213 g_signal_new (I_("hide"),
6214 G_TYPE_FROM_CLASS (object_class),
6216 G_STRUCT_OFFSET (ClutterActorClass, hide),
6218 _clutter_marshal_VOID__VOID,
6221 * ClutterActor::parent-set:
6222 * @actor: the object which received the signal
6223 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6225 * This signal is emitted when the parent of the actor changes.
6229 actor_signals[PARENT_SET] =
6230 g_signal_new (I_("parent-set"),
6231 G_TYPE_FROM_CLASS (object_class),
6233 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6235 _clutter_marshal_VOID__OBJECT,
6237 CLUTTER_TYPE_ACTOR);
6240 * ClutterActor::queue-redraw:
6241 * @actor: the actor we're bubbling the redraw request through
6242 * @origin: the actor which initiated the redraw request
6244 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6245 * is called on @origin.
6247 * The default implementation for #ClutterActor chains up to the
6248 * parent actor and queues a redraw on the parent, thus "bubbling"
6249 * the redraw queue up through the actor graph. The default
6250 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6251 * in a main loop idle handler.
6253 * Note that the @origin actor may be the stage, or a container; it
6254 * does not have to be a leaf node in the actor graph.
6256 * Toolkits embedding a #ClutterStage which require a redraw and
6257 * relayout cycle can stop the emission of this signal using the
6258 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6263 * on_redraw_complete (gpointer data)
6265 * ClutterStage *stage = data;
6267 * /* execute the Clutter drawing pipeline */
6268 * clutter_stage_ensure_redraw (stage);
6272 * on_stage_queue_redraw (ClutterStage *stage)
6274 * /* this prevents the default handler to run */
6275 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6277 * /* queue a redraw with the host toolkit and call
6278 * * a function when the redraw has been completed
6280 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6284 * <note><para>This signal is emitted before the Clutter paint
6285 * pipeline is executed. If you want to know when the pipeline has
6286 * been completed you should connect to the ::paint signal on the
6287 * Stage with g_signal_connect_after().</para></note>
6291 actor_signals[QUEUE_REDRAW] =
6292 g_signal_new (I_("queue-redraw"),
6293 G_TYPE_FROM_CLASS (object_class),
6296 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6298 _clutter_marshal_VOID__OBJECT,
6300 CLUTTER_TYPE_ACTOR);
6303 * ClutterActor::queue-relayout
6304 * @actor: the actor being queued for relayout
6306 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6307 * is called on an actor.
6309 * The default implementation for #ClutterActor chains up to the
6310 * parent actor and queues a relayout on the parent, thus "bubbling"
6311 * the relayout queue up through the actor graph.
6313 * The main purpose of this signal is to allow relayout to be propagated
6314 * properly in the procense of #ClutterClone actors. Applications will
6315 * not normally need to connect to this signal.
6319 actor_signals[QUEUE_RELAYOUT] =
6320 g_signal_new (I_("queue-relayout"),
6321 G_TYPE_FROM_CLASS (object_class),
6324 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6326 _clutter_marshal_VOID__VOID,
6330 * ClutterActor::event:
6331 * @actor: the actor which received the event
6332 * @event: a #ClutterEvent
6334 * The ::event signal is emitted each time an event is received
6335 * by the @actor. This signal will be emitted on every actor,
6336 * following the hierarchy chain, until it reaches the top-level
6337 * container (the #ClutterStage).
6339 * Return value: %TRUE if the event has been handled by the actor,
6340 * or %FALSE to continue the emission.
6344 actor_signals[EVENT] =
6345 g_signal_new (I_("event"),
6346 G_TYPE_FROM_CLASS (object_class),
6348 G_STRUCT_OFFSET (ClutterActorClass, event),
6349 _clutter_boolean_handled_accumulator, NULL,
6350 _clutter_marshal_BOOLEAN__BOXED,
6352 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6354 * ClutterActor::button-press-event:
6355 * @actor: the actor which received the event
6356 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6358 * The ::button-press-event signal is emitted each time a mouse button
6359 * is pressed on @actor.
6361 * Return value: %TRUE if the event has been handled by the actor,
6362 * or %FALSE to continue the emission.
6366 actor_signals[BUTTON_PRESS_EVENT] =
6367 g_signal_new (I_("button-press-event"),
6368 G_TYPE_FROM_CLASS (object_class),
6370 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6371 _clutter_boolean_handled_accumulator, NULL,
6372 _clutter_marshal_BOOLEAN__BOXED,
6374 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6376 * ClutterActor::button-release-event:
6377 * @actor: the actor which received the event
6378 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6380 * The ::button-release-event signal is emitted each time a mouse button
6381 * is released on @actor.
6383 * Return value: %TRUE if the event has been handled by the actor,
6384 * or %FALSE to continue the emission.
6388 actor_signals[BUTTON_RELEASE_EVENT] =
6389 g_signal_new (I_("button-release-event"),
6390 G_TYPE_FROM_CLASS (object_class),
6392 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6393 _clutter_boolean_handled_accumulator, NULL,
6394 _clutter_marshal_BOOLEAN__BOXED,
6396 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6398 * ClutterActor::scroll-event:
6399 * @actor: the actor which received the event
6400 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6402 * The ::scroll-event signal is emitted each time the mouse is
6403 * scrolled on @actor
6405 * Return value: %TRUE if the event has been handled by the actor,
6406 * or %FALSE to continue the emission.
6410 actor_signals[SCROLL_EVENT] =
6411 g_signal_new (I_("scroll-event"),
6412 G_TYPE_FROM_CLASS (object_class),
6414 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6415 _clutter_boolean_handled_accumulator, NULL,
6416 _clutter_marshal_BOOLEAN__BOXED,
6418 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6420 * ClutterActor::key-press-event:
6421 * @actor: the actor which received the event
6422 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6424 * The ::key-press-event signal is emitted each time a keyboard button
6425 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6427 * Return value: %TRUE if the event has been handled by the actor,
6428 * or %FALSE to continue the emission.
6432 actor_signals[KEY_PRESS_EVENT] =
6433 g_signal_new (I_("key-press-event"),
6434 G_TYPE_FROM_CLASS (object_class),
6436 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6437 _clutter_boolean_handled_accumulator, NULL,
6438 _clutter_marshal_BOOLEAN__BOXED,
6440 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6442 * ClutterActor::key-release-event:
6443 * @actor: the actor which received the event
6444 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6446 * The ::key-release-event signal is emitted each time a keyboard button
6447 * is released while @actor has key focus (see
6448 * clutter_stage_set_key_focus()).
6450 * Return value: %TRUE if the event has been handled by the actor,
6451 * or %FALSE to continue the emission.
6455 actor_signals[KEY_RELEASE_EVENT] =
6456 g_signal_new (I_("key-release-event"),
6457 G_TYPE_FROM_CLASS (object_class),
6459 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6460 _clutter_boolean_handled_accumulator, NULL,
6461 _clutter_marshal_BOOLEAN__BOXED,
6463 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6465 * ClutterActor::motion-event:
6466 * @actor: the actor which received the event
6467 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6469 * The ::motion-event signal is emitted each time the mouse pointer is
6470 * moved over @actor.
6472 * Return value: %TRUE if the event has been handled by the actor,
6473 * or %FALSE to continue the emission.
6477 actor_signals[MOTION_EVENT] =
6478 g_signal_new (I_("motion-event"),
6479 G_TYPE_FROM_CLASS (object_class),
6481 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6482 _clutter_boolean_handled_accumulator, NULL,
6483 _clutter_marshal_BOOLEAN__BOXED,
6485 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6488 * ClutterActor::key-focus-in:
6489 * @actor: the actor which now has key focus
6491 * The ::key-focus-in signal is emitted when @actor receives key focus.
6495 actor_signals[KEY_FOCUS_IN] =
6496 g_signal_new (I_("key-focus-in"),
6497 G_TYPE_FROM_CLASS (object_class),
6499 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6501 _clutter_marshal_VOID__VOID,
6505 * ClutterActor::key-focus-out:
6506 * @actor: the actor which now has key focus
6508 * The ::key-focus-out signal is emitted when @actor loses key focus.
6512 actor_signals[KEY_FOCUS_OUT] =
6513 g_signal_new (I_("key-focus-out"),
6514 G_TYPE_FROM_CLASS (object_class),
6516 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6518 _clutter_marshal_VOID__VOID,
6522 * ClutterActor::enter-event:
6523 * @actor: the actor which the pointer has entered.
6524 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6526 * The ::enter-event signal is emitted when the pointer enters the @actor
6528 * Return value: %TRUE if the event has been handled by the actor,
6529 * or %FALSE to continue the emission.
6533 actor_signals[ENTER_EVENT] =
6534 g_signal_new (I_("enter-event"),
6535 G_TYPE_FROM_CLASS (object_class),
6537 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6538 _clutter_boolean_handled_accumulator, NULL,
6539 _clutter_marshal_BOOLEAN__BOXED,
6541 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6544 * ClutterActor::leave-event:
6545 * @actor: the actor which the pointer has left
6546 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6548 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6550 * Return value: %TRUE if the event has been handled by the actor,
6551 * or %FALSE to continue the emission.
6555 actor_signals[LEAVE_EVENT] =
6556 g_signal_new (I_("leave-event"),
6557 G_TYPE_FROM_CLASS (object_class),
6559 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6560 _clutter_boolean_handled_accumulator, NULL,
6561 _clutter_marshal_BOOLEAN__BOXED,
6563 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6566 * ClutterActor::captured-event:
6567 * @actor: the actor which received the signal
6568 * @event: a #ClutterEvent
6570 * The ::captured-event signal is emitted when an event is captured
6571 * by Clutter. This signal will be emitted starting from the top-level
6572 * container (the #ClutterStage) to the actor which received the event
6573 * going down the hierarchy. This signal can be used to intercept every
6574 * event before the specialized events (like
6575 * ClutterActor::button-press-event or ::key-released-event) are
6578 * Return value: %TRUE if the event has been handled by the actor,
6579 * or %FALSE to continue the emission.
6583 actor_signals[CAPTURED_EVENT] =
6584 g_signal_new (I_("captured-event"),
6585 G_TYPE_FROM_CLASS (object_class),
6587 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6588 _clutter_boolean_handled_accumulator, NULL,
6589 _clutter_marshal_BOOLEAN__BOXED,
6591 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6594 * ClutterActor::paint:
6595 * @actor: the #ClutterActor that received the signal
6597 * The ::paint signal is emitted each time an actor is being painted.
6599 * Subclasses of #ClutterActor should override the class signal handler
6600 * and paint themselves in that function.
6602 * It is possible to connect a handler to the ::paint signal in order
6603 * to set up some custom aspect of a paint.
6607 actor_signals[PAINT] =
6608 g_signal_new (I_("paint"),
6609 G_TYPE_FROM_CLASS (object_class),
6612 G_STRUCT_OFFSET (ClutterActorClass, paint),
6614 _clutter_marshal_VOID__VOID,
6617 * ClutterActor::realize:
6618 * @actor: the #ClutterActor that received the signal
6620 * The ::realize signal is emitted each time an actor is being
6625 actor_signals[REALIZE] =
6626 g_signal_new (I_("realize"),
6627 G_TYPE_FROM_CLASS (object_class),
6629 G_STRUCT_OFFSET (ClutterActorClass, realize),
6631 _clutter_marshal_VOID__VOID,
6634 * ClutterActor::unrealize:
6635 * @actor: the #ClutterActor that received the signal
6637 * The ::unrealize signal is emitted each time an actor is being
6642 actor_signals[UNREALIZE] =
6643 g_signal_new (I_("unrealize"),
6644 G_TYPE_FROM_CLASS (object_class),
6646 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6648 _clutter_marshal_VOID__VOID,
6652 * ClutterActor::pick:
6653 * @actor: the #ClutterActor that received the signal
6654 * @color: the #ClutterColor to be used when picking
6656 * The ::pick signal is emitted each time an actor is being painted
6657 * in "pick mode". The pick mode is used to identify the actor during
6658 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6659 * The actor should paint its shape using the passed @pick_color.
6661 * Subclasses of #ClutterActor should override the class signal handler
6662 * and paint themselves in that function.
6664 * It is possible to connect a handler to the ::pick signal in order
6665 * to set up some custom aspect of a paint in pick mode.
6669 actor_signals[PICK] =
6670 g_signal_new (I_("pick"),
6671 G_TYPE_FROM_CLASS (object_class),
6673 G_STRUCT_OFFSET (ClutterActorClass, pick),
6675 _clutter_marshal_VOID__BOXED,
6677 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6680 * ClutterActor::allocation-changed:
6681 * @actor: the #ClutterActor that emitted the signal
6682 * @box: a #ClutterActorBox with the new allocation
6683 * @flags: #ClutterAllocationFlags for the allocation
6685 * The ::allocation-changed signal is emitted when the
6686 * #ClutterActor:allocation property changes. Usually, application
6687 * code should just use the notifications for the :allocation property
6688 * but if you want to track the allocation flags as well, for instance
6689 * to know whether the absolute origin of @actor changed, then you might
6690 * want use this signal instead.
6694 actor_signals[ALLOCATION_CHANGED] =
6695 g_signal_new (I_("allocation-changed"),
6696 G_TYPE_FROM_CLASS (object_class),
6700 _clutter_marshal_VOID__BOXED_FLAGS,
6702 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6703 CLUTTER_TYPE_ALLOCATION_FLAGS);
6707 clutter_actor_init (ClutterActor *self)
6709 ClutterActorPrivate *priv;
6711 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6713 priv->id = _clutter_context_acquire_id (self);
6716 priv->opacity = 0xff;
6717 priv->show_on_set_parent = TRUE;
6719 priv->needs_width_request = TRUE;
6720 priv->needs_height_request = TRUE;
6721 priv->needs_allocation = TRUE;
6723 priv->cached_width_age = 1;
6724 priv->cached_height_age = 1;
6726 priv->opacity_override = -1;
6727 priv->enable_model_view_transform = TRUE;
6729 /* Initialize an empty paint volume to start with */
6730 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6731 priv->last_paint_volume_valid = TRUE;
6733 priv->transform_valid = FALSE;
6737 * clutter_actor_new:
6739 * Creates a new #ClutterActor.
6741 * A newly created actor has a floating reference, which will be sunk
6742 * when it is added to another actor.
6744 * Return value: (transfer full): the newly created #ClutterActor
6749 clutter_actor_new (void)
6751 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
6755 * clutter_actor_destroy:
6756 * @self: a #ClutterActor
6758 * Destroys an actor. When an actor is destroyed, it will break any
6759 * references it holds to other objects. If the actor is inside a
6760 * container, the actor will be removed.
6762 * When you destroy a container, its children will be destroyed as well.
6764 * Note: you cannot destroy the #ClutterStage returned by
6765 * clutter_stage_get_default().
6768 clutter_actor_destroy (ClutterActor *self)
6770 g_return_if_fail (CLUTTER_IS_ACTOR (self));
6772 g_object_ref (self);
6774 /* avoid recursion while destroying */
6775 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
6777 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6779 g_object_run_dispose (G_OBJECT (self));
6781 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
6784 g_object_unref (self);
6788 _clutter_actor_finish_queue_redraw (ClutterActor *self,
6789 ClutterPaintVolume *clip)
6791 ClutterActorPrivate *priv = self->priv;
6792 ClutterPaintVolume *pv;
6795 /* Remove queue entry early in the process, otherwise a new
6796 queue_redraw() during signal handling could put back this
6797 object in the stage redraw list (but the entry is freed as
6798 soon as we return from this function, causing a segfault
6801 priv->queue_redraw_entry = NULL;
6803 /* If we've been explicitly passed a clip volume then there's
6804 * nothing more to calculate, but otherwise the only thing we know
6805 * is that the change is constrained to the given actor.
6807 * The idea is that if we know the paint volume for where the actor
6808 * was last drawn (in eye coordinates) and we also have the paint
6809 * volume for where it will be drawn next (in actor coordinates)
6810 * then if we queue a redraw for both these volumes that will cover
6811 * everything that needs to be redrawn to clear the old view and
6812 * show the latest view of the actor.
6814 * Don't clip this redraw if we don't know what position we had for
6815 * the previous redraw since we don't know where to set the clip so
6816 * it will clear the actor as it is currently.
6820 _clutter_actor_set_queue_redraw_clip (self, clip);
6823 else if (G_LIKELY (priv->last_paint_volume_valid))
6825 pv = _clutter_actor_get_paint_volume_mutable (self);
6828 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
6830 /* make sure we redraw the actors old position... */
6831 _clutter_actor_set_queue_redraw_clip (stage,
6832 &priv->last_paint_volume);
6833 _clutter_actor_signal_queue_redraw (stage, stage);
6834 _clutter_actor_set_queue_redraw_clip (stage, NULL);
6836 /* XXX: Ideally the redraw signal would take a clip volume
6837 * argument, but that would be an ABI break. Until we can
6838 * break the ABI we pass the argument out-of-band
6841 /* setup the clip for the actors new position... */
6842 _clutter_actor_set_queue_redraw_clip (self, pv);
6851 _clutter_actor_signal_queue_redraw (self, self);
6853 /* Just in case anyone is manually firing redraw signals without
6854 * using the public queue_redraw() API we are careful to ensure that
6855 * our out-of-band clip member is cleared before returning...
6857 * Note: A NULL clip denotes a full-stage, un-clipped redraw
6859 if (G_LIKELY (clipped))
6860 _clutter_actor_set_queue_redraw_clip (self, NULL);
6864 _clutter_actor_get_allocation_clip (ClutterActor *self,
6865 ClutterActorBox *clip)
6867 ClutterActorBox allocation;
6869 /* XXX: we don't care if we get an out of date allocation here
6870 * because clutter_actor_queue_redraw_with_clip knows to ignore
6871 * the clip if the actor's allocation is invalid.
6873 * This is noted because clutter_actor_get_allocation_box does some
6874 * unnecessary work to support buggy code with a comment suggesting
6875 * that it could be changed later which would be good for this use
6878 clutter_actor_get_allocation_box (self, &allocation);
6880 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
6881 * actor's own coordinate space but the allocation is in parent
6885 clip->x2 = allocation.x2 - allocation.x1;
6886 clip->y2 = allocation.y2 - allocation.y1;
6890 _clutter_actor_queue_redraw_full (ClutterActor *self,
6891 ClutterRedrawFlags flags,
6892 ClutterPaintVolume *volume,
6893 ClutterEffect *effect)
6895 ClutterActorPrivate *priv = self->priv;
6896 ClutterPaintVolume allocation_pv;
6897 ClutterPaintVolume *pv;
6898 gboolean should_free_pv;
6899 ClutterActor *stage;
6901 /* Here's an outline of the actor queue redraw mechanism:
6903 * The process starts in one of the following two functions which
6904 * are wrappers for this function:
6905 * clutter_actor_queue_redraw
6906 * _clutter_actor_queue_redraw_with_clip
6908 * additionally, an effect can queue a redraw by wrapping this
6909 * function in clutter_effect_queue_rerun
6911 * This functions queues an entry in a list associated with the
6912 * stage which is a list of actors that queued a redraw while
6913 * updating the timelines, performing layouting and processing other
6914 * mainloop sources before the next paint starts.
6916 * We aim to minimize the processing done at this point because
6917 * there is a good chance other events will happen while updating
6918 * the scenegraph that would invalidate any expensive work we might
6919 * otherwise try to do here. For example we don't try and resolve
6920 * the screen space bounding box of an actor at this stage so as to
6921 * minimize how much of the screen redraw because it's possible
6922 * something else will happen which will force a full redraw anyway.
6924 * When all updates are complete and we come to paint the stage then
6925 * we iterate this list and actually emit the "queue-redraw" signals
6926 * for each of the listed actors which will bubble up to the stage
6927 * for each actor and at that point we will transform the actors
6928 * paint volume into screen coordinates to determine the clip region
6929 * for what needs to be redrawn in the next paint.
6931 * Besides minimizing redundant work another reason for this
6932 * deferred design is that it's more likely we will be able to
6933 * determine the paint volume of an actor once we've finished
6934 * updating the scenegraph because its allocation should be up to
6935 * date. NB: If we can't determine an actors paint volume then we
6936 * can't automatically queue a clipped redraw which can make a big
6937 * difference to performance.
6939 * So the control flow goes like this:
6940 * One of clutter_actor_queue_redraw,
6941 * _clutter_actor_queue_redraw_with_clip
6942 * or clutter_effect_queue_rerun
6944 * then control moves to:
6945 * _clutter_stage_queue_actor_redraw
6947 * later during _clutter_stage_do_update, once relayouting is done
6948 * and the scenegraph has been updated we will call:
6949 * _clutter_stage_finish_queue_redraws
6951 * _clutter_stage_finish_queue_redraws will call
6952 * _clutter_actor_finish_queue_redraw for each listed actor.
6953 * Note: actors *are* allowed to queue further redraws during this
6954 * process (considering clone actors or texture_new_from_actor which
6955 * respond to their source queueing a redraw by queuing a redraw
6956 * themselves). We repeat the process until the list is empty.
6958 * This will result in the "queue-redraw" signal being fired for
6959 * each actor which will pass control to the default signal handler:
6960 * clutter_actor_real_queue_redraw
6962 * This will bubble up to the stages handler:
6963 * clutter_stage_real_queue_redraw
6965 * clutter_stage_real_queue_redraw will transform the actors paint
6966 * volume into screen space and add it as a clip region for the next
6970 /* ignore queueing a redraw for actors being destroyed */
6971 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
6974 stage = _clutter_actor_get_stage_internal (self);
6976 /* Ignore queueing a redraw for actors not descended from a stage */
6980 /* ignore queueing a redraw on stages that are being destroyed */
6981 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
6984 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
6986 ClutterActorBox allocation_clip;
6987 ClutterVertex origin;
6989 /* If the actor doesn't have a valid allocation then we will
6990 * queue a full stage redraw. */
6991 if (priv->needs_allocation)
6993 /* NB: NULL denotes an undefined clip which will result in a
6995 _clutter_actor_set_queue_redraw_clip (self, NULL);
6996 _clutter_actor_signal_queue_redraw (self, self);
7000 _clutter_paint_volume_init_static (&allocation_pv, self);
7001 pv = &allocation_pv;
7003 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7005 origin.x = allocation_clip.x1;
7006 origin.y = allocation_clip.y1;
7008 clutter_paint_volume_set_origin (pv, &origin);
7009 clutter_paint_volume_set_width (pv,
7010 allocation_clip.x2 - allocation_clip.x1);
7011 clutter_paint_volume_set_height (pv,
7012 allocation_clip.y2 -
7013 allocation_clip.y1);
7014 should_free_pv = TRUE;
7019 should_free_pv = FALSE;
7022 self->priv->queue_redraw_entry =
7023 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7024 priv->queue_redraw_entry,
7029 clutter_paint_volume_free (pv);
7031 /* If this is the first redraw queued then we can directly use the
7033 if (!priv->is_dirty)
7034 priv->effect_to_redraw = effect;
7035 /* Otherwise we need to merge it with the existing effect parameter */
7036 else if (effect != NULL)
7038 /* If there's already an effect then we need to use whichever is
7039 later in the chain of actors. Otherwise a full redraw has
7040 already been queued on the actor so we need to ignore the
7042 if (priv->effect_to_redraw != NULL)
7044 if (priv->effects == NULL)
7045 g_warning ("Redraw queued with an effect that is "
7046 "not applied to the actor");
7051 for (l = _clutter_meta_group_peek_metas (priv->effects);
7055 if (l->data == priv->effect_to_redraw ||
7057 priv->effect_to_redraw = l->data;
7064 /* If no effect is specified then we need to redraw the whole
7066 priv->effect_to_redraw = NULL;
7069 priv->is_dirty = TRUE;
7073 * clutter_actor_queue_redraw:
7074 * @self: A #ClutterActor
7076 * Queues up a redraw of an actor and any children. The redraw occurs
7077 * once the main loop becomes idle (after the current batch of events
7078 * has been processed, roughly).
7080 * Applications rarely need to call this, as redraws are handled
7081 * automatically by modification functions.
7083 * This function will not do anything if @self is not visible, or
7084 * if the actor is inside an invisible part of the scenegraph.
7086 * Also be aware that painting is a NOP for actors with an opacity of
7089 * When you are implementing a custom actor you must queue a redraw
7090 * whenever some private state changes that will affect painting or
7091 * picking of your actor.
7094 clutter_actor_queue_redraw (ClutterActor *self)
7096 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7098 _clutter_actor_queue_redraw_full (self,
7100 NULL, /* clip volume */
7105 * _clutter_actor_queue_redraw_with_clip:
7106 * @self: A #ClutterActor
7107 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7108 * this queue redraw.
7109 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7110 * redrawn or %NULL if you are just using a @flag to state your
7113 * Queues up a clipped redraw of an actor and any children. The redraw
7114 * occurs once the main loop becomes idle (after the current batch of
7115 * events has been processed, roughly).
7117 * If no flags are given the clip volume is defined by @volume
7118 * specified in actor coordinates and tells Clutter that only content
7119 * within this volume has been changed so Clutter can optionally
7120 * optimize the redraw.
7122 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7123 * should be %NULL and this tells Clutter to use the actor's current
7124 * allocation as a clip box. This flag can only be used for 2D actors,
7125 * because any actor with depth may be projected outside its
7128 * Applications rarely need to call this, as redraws are handled
7129 * automatically by modification functions.
7131 * This function will not do anything if @self is not visible, or if
7132 * the actor is inside an invisible part of the scenegraph.
7134 * Also be aware that painting is a NOP for actors with an opacity of
7137 * When you are implementing a custom actor you must queue a redraw
7138 * whenever some private state changes that will affect painting or
7139 * picking of your actor.
7142 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7143 ClutterRedrawFlags flags,
7144 ClutterPaintVolume *volume)
7146 _clutter_actor_queue_redraw_full (self,
7148 volume, /* clip volume */
7153 _clutter_actor_queue_only_relayout (ClutterActor *self)
7155 ClutterActorPrivate *priv = self->priv;
7157 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7160 if (priv->needs_width_request &&
7161 priv->needs_height_request &&
7162 priv->needs_allocation)
7163 return; /* save some cpu cycles */
7165 #if CLUTTER_ENABLE_DEBUG
7166 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7168 g_warning ("The actor '%s' is currently inside an allocation "
7169 "cycle; calling clutter_actor_queue_relayout() is "
7171 _clutter_actor_get_debug_name (self));
7173 #endif /* CLUTTER_ENABLE_DEBUG */
7175 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7179 * clutter_actor_queue_redraw_with_clip:
7180 * @self: a #ClutterActor
7181 * @clip: (allow-none): a rectangular clip region, or %NULL
7183 * Queues a redraw on @self limited to a specific, actor-relative
7186 * If @clip is %NULL this function is equivalent to
7187 * clutter_actor_queue_redraw().
7192 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7193 const cairo_rectangle_int_t *clip)
7195 ClutterPaintVolume volume;
7196 ClutterVertex origin;
7198 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7202 clutter_actor_queue_redraw (self);
7206 _clutter_paint_volume_init_static (&volume, self);
7212 clutter_paint_volume_set_origin (&volume, &origin);
7213 clutter_paint_volume_set_width (&volume, clip->width);
7214 clutter_paint_volume_set_height (&volume, clip->height);
7216 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7218 clutter_paint_volume_free (&volume);
7222 * clutter_actor_queue_relayout:
7223 * @self: A #ClutterActor
7225 * Indicates that the actor's size request or other layout-affecting
7226 * properties may have changed. This function is used inside #ClutterActor
7227 * subclass implementations, not by applications directly.
7229 * Queueing a new layout automatically queues a redraw as well.
7234 clutter_actor_queue_relayout (ClutterActor *self)
7236 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7238 _clutter_actor_queue_only_relayout (self);
7239 clutter_actor_queue_redraw (self);
7243 * clutter_actor_get_preferred_size:
7244 * @self: a #ClutterActor
7245 * @min_width_p: (out) (allow-none): return location for the minimum
7247 * @min_height_p: (out) (allow-none): return location for the minimum
7249 * @natural_width_p: (out) (allow-none): return location for the natural
7251 * @natural_height_p: (out) (allow-none): return location for the natural
7254 * Computes the preferred minimum and natural size of an actor, taking into
7255 * account the actor's geometry management (either height-for-width
7256 * or width-for-height).
7258 * The width and height used to compute the preferred height and preferred
7259 * width are the actor's natural ones.
7261 * If you need to control the height for the preferred width, or the width for
7262 * the preferred height, you should use clutter_actor_get_preferred_width()
7263 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7264 * geometry management using the #ClutterActor:request-mode property.
7269 clutter_actor_get_preferred_size (ClutterActor *self,
7270 gfloat *min_width_p,
7271 gfloat *min_height_p,
7272 gfloat *natural_width_p,
7273 gfloat *natural_height_p)
7275 ClutterActorPrivate *priv;
7276 gfloat min_width, min_height;
7277 gfloat natural_width, natural_height;
7279 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7283 min_width = min_height = 0;
7284 natural_width = natural_height = 0;
7286 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7288 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7289 clutter_actor_get_preferred_width (self, -1,
7292 clutter_actor_get_preferred_height (self, natural_width,
7298 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7299 clutter_actor_get_preferred_height (self, -1,
7302 clutter_actor_get_preferred_width (self, natural_height,
7308 *min_width_p = min_width;
7311 *min_height_p = min_height;
7313 if (natural_width_p)
7314 *natural_width_p = natural_width;
7316 if (natural_height_p)
7317 *natural_height_p = natural_height;
7322 * @align: a #ClutterActorAlign
7323 * @direction: a #ClutterTextDirection
7325 * Retrieves the correct alignment depending on the text direction
7327 * Return value: the effective alignment
7329 static ClutterActorAlign
7330 effective_align (ClutterActorAlign align,
7331 ClutterTextDirection direction)
7333 ClutterActorAlign res;
7337 case CLUTTER_ACTOR_ALIGN_START:
7338 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7339 ? CLUTTER_ACTOR_ALIGN_END
7340 : CLUTTER_ACTOR_ALIGN_START;
7343 case CLUTTER_ACTOR_ALIGN_END:
7344 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7345 ? CLUTTER_ACTOR_ALIGN_START
7346 : CLUTTER_ACTOR_ALIGN_END;
7358 adjust_for_margin (float margin_start,
7360 float *minimum_size,
7361 float *natural_size,
7362 float *allocated_start,
7363 float *allocated_end)
7365 *minimum_size -= (margin_start + margin_end);
7366 *natural_size -= (margin_start + margin_end);
7367 *allocated_start += margin_start;
7368 *allocated_end -= margin_end;
7372 adjust_for_alignment (ClutterActorAlign alignment,
7374 float *allocated_start,
7375 float *allocated_end)
7377 float allocated_size = *allocated_end - *allocated_start;
7381 case CLUTTER_ACTOR_ALIGN_FILL:
7385 case CLUTTER_ACTOR_ALIGN_START:
7387 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7390 case CLUTTER_ACTOR_ALIGN_END:
7391 if (allocated_size > natural_size)
7393 *allocated_start += (allocated_size - natural_size);
7394 *allocated_end = *allocated_start + natural_size;
7398 case CLUTTER_ACTOR_ALIGN_CENTER:
7399 if (allocated_size > natural_size)
7401 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7402 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7409 * clutter_actor_adjust_width:
7410 * @self: a #ClutterActor
7411 * @minimum_width: (inout): the actor's preferred minimum width, which
7412 * will be adjusted depending on the margin
7413 * @natural_width: (inout): the actor's preferred natural width, which
7414 * will be adjusted depending on the margin
7415 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7416 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7418 * Adjusts the preferred and allocated position and size of an actor,
7419 * depending on the margin and alignment properties.
7422 clutter_actor_adjust_width (ClutterActor *self,
7423 gfloat *minimum_width,
7424 gfloat *natural_width,
7425 gfloat *adjusted_x1,
7426 gfloat *adjusted_x2)
7428 ClutterTextDirection text_dir;
7429 const ClutterLayoutInfo *info;
7431 info = _clutter_actor_get_layout_info_or_defaults (self);
7432 text_dir = clutter_actor_get_text_direction (self);
7434 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7436 /* this will tweak natural_width to remove the margin, so that
7437 * adjust_for_alignment() will use the correct size
7439 adjust_for_margin (info->margin.left, info->margin.right,
7440 minimum_width, natural_width,
7441 adjusted_x1, adjusted_x2);
7443 adjust_for_alignment (effective_align (info->x_align, text_dir),
7445 adjusted_x1, adjusted_x2);
7449 * clutter_actor_adjust_height:
7450 * @self: a #ClutterActor
7451 * @minimum_height: (inout): the actor's preferred minimum height, which
7452 * will be adjusted depending on the margin
7453 * @natural_height: (inout): the actor's preferred natural height, which
7454 * will be adjusted depending on the margin
7455 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7456 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7458 * Adjusts the preferred and allocated position and size of an actor,
7459 * depending on the margin and alignment properties.
7462 clutter_actor_adjust_height (ClutterActor *self,
7463 gfloat *minimum_height,
7464 gfloat *natural_height,
7465 gfloat *adjusted_y1,
7466 gfloat *adjusted_y2)
7468 const ClutterLayoutInfo *info;
7470 info = _clutter_actor_get_layout_info_or_defaults (self);
7472 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7474 /* this will tweak natural_height to remove the margin, so that
7475 * adjust_for_alignment() will use the correct size
7477 adjust_for_margin (info->margin.top, info->margin.bottom,
7478 minimum_height, natural_height,
7482 /* we don't use effective_align() here, because text direction
7483 * only affects the horizontal axis
7485 adjust_for_alignment (info->y_align,
7492 /* looks for a cached size request for this for_size. If not
7493 * found, returns the oldest entry so it can be overwritten */
7495 _clutter_actor_get_cached_size_request (gfloat for_size,
7496 SizeRequest *cached_size_requests,
7497 SizeRequest **result)
7501 *result = &cached_size_requests[0];
7503 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7507 sr = &cached_size_requests[i];
7510 sr->for_size == for_size)
7512 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7516 else if (sr->age < (*result)->age)
7522 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7528 * clutter_actor_get_preferred_width:
7529 * @self: A #ClutterActor
7530 * @for_height: available height when computing the preferred width,
7531 * or a negative value to indicate that no height is defined
7532 * @min_width_p: (out) (allow-none): return location for minimum width,
7534 * @natural_width_p: (out) (allow-none): return location for the natural
7537 * Computes the requested minimum and natural widths for an actor,
7538 * optionally depending on the specified height, or if they are
7539 * already computed, returns the cached values.
7541 * An actor may not get its request - depending on the layout
7542 * manager that's in effect.
7544 * A request should not incorporate the actor's scale or anchor point;
7545 * those transformations do not affect layout, only rendering.
7550 clutter_actor_get_preferred_width (ClutterActor *self,
7552 gfloat *min_width_p,
7553 gfloat *natural_width_p)
7555 float request_min_width, request_natural_width;
7556 SizeRequest *cached_size_request;
7557 const ClutterLayoutInfo *info;
7558 ClutterActorPrivate *priv;
7559 gboolean found_in_cache;
7561 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7565 info = _clutter_actor_get_layout_info_or_defaults (self);
7567 /* we shortcircuit the case of a fixed size set using set_width() */
7568 if (priv->min_width_set && priv->natural_width_set)
7570 if (min_width_p != NULL)
7571 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7573 if (natural_width_p != NULL)
7574 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7579 /* the remaining cases are:
7581 * - either min_width or natural_width have been set
7582 * - neither min_width or natural_width have been set
7584 * in both cases, we go through the cache (and through the actor in case
7585 * of cache misses) and determine the authoritative value depending on
7589 if (!priv->needs_width_request)
7592 _clutter_actor_get_cached_size_request (for_height,
7593 priv->width_requests,
7594 &cached_size_request);
7598 /* if the actor needs a width request we use the first slot */
7599 found_in_cache = FALSE;
7600 cached_size_request = &priv->width_requests[0];
7603 if (!found_in_cache)
7605 gfloat minimum_width, natural_width;
7606 ClutterActorClass *klass;
7608 minimum_width = natural_width = 0;
7610 /* adjust for the margin */
7611 if (for_height >= 0)
7613 for_height -= (info->margin.top + info->margin.bottom);
7618 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7620 klass = CLUTTER_ACTOR_GET_CLASS (self);
7621 klass->get_preferred_width (self, for_height,
7625 /* adjust for the margin */
7626 minimum_width += (info->margin.left + info->margin.right);
7627 natural_width += (info->margin.left + info->margin.right);
7629 /* Due to accumulated float errors, it's better not to warn
7630 * on this, but just fix it.
7632 if (natural_width < minimum_width)
7633 natural_width = minimum_width;
7635 cached_size_request->min_size = minimum_width;
7636 cached_size_request->natural_size = natural_width;
7637 cached_size_request->for_size = for_height;
7638 cached_size_request->age = priv->cached_width_age;
7640 priv->cached_width_age += 1;
7641 priv->needs_width_request = FALSE;
7644 if (!priv->min_width_set)
7645 request_min_width = cached_size_request->min_size;
7647 request_min_width = info->min_width;
7649 if (!priv->natural_width_set)
7650 request_natural_width = cached_size_request->natural_size;
7652 request_natural_width = info->natural_width;
7655 *min_width_p = request_min_width;
7657 if (natural_width_p)
7658 *natural_width_p = request_natural_width;
7662 * clutter_actor_get_preferred_height:
7663 * @self: A #ClutterActor
7664 * @for_width: available width to assume in computing desired height,
7665 * or a negative value to indicate that no width is defined
7666 * @min_height_p: (out) (allow-none): return location for minimum height,
7668 * @natural_height_p: (out) (allow-none): return location for natural
7671 * Computes the requested minimum and natural heights for an actor,
7672 * or if they are already computed, returns the cached values.
7674 * An actor may not get its request - depending on the layout
7675 * manager that's in effect.
7677 * A request should not incorporate the actor's scale or anchor point;
7678 * those transformations do not affect layout, only rendering.
7683 clutter_actor_get_preferred_height (ClutterActor *self,
7685 gfloat *min_height_p,
7686 gfloat *natural_height_p)
7688 float request_min_height, request_natural_height;
7689 SizeRequest *cached_size_request;
7690 const ClutterLayoutInfo *info;
7691 ClutterActorPrivate *priv;
7692 gboolean found_in_cache;
7694 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7698 info = _clutter_actor_get_layout_info_or_defaults (self);
7700 /* we shortcircuit the case of a fixed size set using set_height() */
7701 if (priv->min_height_set && priv->natural_height_set)
7703 if (min_height_p != NULL)
7704 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7706 if (natural_height_p != NULL)
7707 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7712 /* the remaining cases are:
7714 * - either min_height or natural_height have been set
7715 * - neither min_height or natural_height have been set
7717 * in both cases, we go through the cache (and through the actor in case
7718 * of cache misses) and determine the authoritative value depending on
7722 if (!priv->needs_height_request)
7725 _clutter_actor_get_cached_size_request (for_width,
7726 priv->height_requests,
7727 &cached_size_request);
7731 found_in_cache = FALSE;
7732 cached_size_request = &priv->height_requests[0];
7735 if (!found_in_cache)
7737 gfloat minimum_height, natural_height;
7738 ClutterActorClass *klass;
7740 minimum_height = natural_height = 0;
7742 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7744 /* adjust for margin */
7747 for_width -= (info->margin.left + info->margin.right);
7752 klass = CLUTTER_ACTOR_GET_CLASS (self);
7753 klass->get_preferred_height (self, for_width,
7757 /* adjust for margin */
7758 minimum_height += (info->margin.top + info->margin.bottom);
7759 natural_height += (info->margin.top + info->margin.bottom);
7761 /* Due to accumulated float errors, it's better not to warn
7762 * on this, but just fix it.
7764 if (natural_height < minimum_height)
7765 natural_height = minimum_height;
7767 cached_size_request->min_size = minimum_height;
7768 cached_size_request->natural_size = natural_height;
7769 cached_size_request->for_size = for_width;
7770 cached_size_request->age = priv->cached_height_age;
7772 priv->cached_height_age += 1;
7773 priv->needs_height_request = FALSE;
7776 if (!priv->min_height_set)
7777 request_min_height = cached_size_request->min_size;
7779 request_min_height = info->min_height;
7781 if (!priv->natural_height_set)
7782 request_natural_height = cached_size_request->natural_size;
7784 request_natural_height = info->natural_height;
7787 *min_height_p = request_min_height;
7789 if (natural_height_p)
7790 *natural_height_p = request_natural_height;
7794 * clutter_actor_get_allocation_box:
7795 * @self: A #ClutterActor
7796 * @box: (out): the function fills this in with the actor's allocation
7798 * Gets the layout box an actor has been assigned. The allocation can
7799 * only be assumed valid inside a paint() method; anywhere else, it
7800 * may be out-of-date.
7802 * An allocation does not incorporate the actor's scale or anchor point;
7803 * those transformations do not affect layout, only rendering.
7805 * <note>Do not call any of the clutter_actor_get_allocation_*() family
7806 * of functions inside the implementation of the get_preferred_width()
7807 * or get_preferred_height() virtual functions.</note>
7812 clutter_actor_get_allocation_box (ClutterActor *self,
7813 ClutterActorBox *box)
7815 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7817 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
7818 * which limits calling get_allocation to inside paint() basically; or
7819 * we can 2) force a layout, which could be expensive if someone calls
7820 * get_allocation somewhere silly; or we can 3) just return the latest
7821 * value, allowing it to be out-of-date, and assume people know what
7824 * The least-surprises approach that keeps existing code working is
7825 * likely to be 2). People can end up doing some inefficient things,
7826 * though, and in general code that requires 2) is probably broken.
7829 /* this implements 2) */
7830 if (G_UNLIKELY (self->priv->needs_allocation))
7832 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7834 /* do not queue a relayout on an unparented actor */
7836 _clutter_stage_maybe_relayout (stage);
7839 /* commenting out the code above and just keeping this assigment
7842 *box = self->priv->allocation;
7846 * clutter_actor_get_allocation_geometry:
7847 * @self: A #ClutterActor
7848 * @geom: (out): allocation geometry in pixels
7850 * Gets the layout box an actor has been assigned. The allocation can
7851 * only be assumed valid inside a paint() method; anywhere else, it
7852 * may be out-of-date.
7854 * An allocation does not incorporate the actor's scale or anchor point;
7855 * those transformations do not affect layout, only rendering.
7857 * The returned rectangle is in pixels.
7862 clutter_actor_get_allocation_geometry (ClutterActor *self,
7863 ClutterGeometry *geom)
7865 ClutterActorBox box;
7867 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7868 g_return_if_fail (geom != NULL);
7870 clutter_actor_get_allocation_box (self, &box);
7872 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
7873 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
7874 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
7875 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
7879 clutter_actor_update_constraints (ClutterActor *self,
7880 ClutterActorBox *allocation)
7882 ClutterActorPrivate *priv = self->priv;
7883 const GList *constraints, *l;
7885 if (priv->constraints == NULL)
7888 constraints = _clutter_meta_group_peek_metas (priv->constraints);
7889 for (l = constraints; l != NULL; l = l->next)
7891 ClutterConstraint *constraint = l->data;
7892 ClutterActorMeta *meta = l->data;
7894 if (clutter_actor_meta_get_enabled (meta))
7896 _clutter_constraint_update_allocation (constraint,
7904 * clutter_actor_adjust_allocation:
7905 * @self: a #ClutterActor
7906 * @allocation: (inout): the allocation to adjust
7908 * Adjusts the passed allocation box taking into account the actor's
7909 * layout information, like alignment, expansion, and margin.
7912 clutter_actor_adjust_allocation (ClutterActor *self,
7913 ClutterActorBox *allocation)
7915 ClutterActorBox adj_allocation;
7916 float alloc_width, alloc_height;
7917 float min_width, min_height;
7918 float nat_width, nat_height;
7919 ClutterRequestMode req_mode;
7921 adj_allocation = *allocation;
7923 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
7925 /* we want to hit the cache, so we use the public API */
7926 req_mode = clutter_actor_get_request_mode (self);
7928 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7930 clutter_actor_get_preferred_width (self, -1,
7933 clutter_actor_get_preferred_height (self, alloc_width,
7937 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
7939 clutter_actor_get_preferred_height (self, -1,
7942 clutter_actor_get_preferred_height (self, alloc_height,
7947 #ifdef CLUTTER_ENABLE_DEBUG
7948 /* warn about underallocations */
7949 if (_clutter_diagnostic_enabled () &&
7950 (floorf (min_width - alloc_width) > 0 ||
7951 floorf (min_height - alloc_height) > 0))
7953 ClutterActor *parent = clutter_actor_get_parent (self);
7955 /* the only actors that are allowed to be underallocated are the Stage,
7956 * as it doesn't have an implicit size, and Actors that specifically
7957 * told us that they want to opt-out from layout control mechanisms
7958 * through the NO_LAYOUT escape hatch.
7960 if (parent != NULL &&
7961 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
7963 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
7964 "of %.2f x %.2f from its parent actor '%s', but its "
7965 "requested minimum size is of %.2f x %.2f",
7966 _clutter_actor_get_debug_name (self),
7967 alloc_width, alloc_height,
7968 _clutter_actor_get_debug_name (parent),
7969 min_width, min_height);
7974 clutter_actor_adjust_width (self,
7978 &adj_allocation.x2);
7980 clutter_actor_adjust_height (self,
7984 &adj_allocation.y2);
7986 /* we maintain the invariant that an allocation cannot be adjusted
7987 * to be outside the parent-given box
7989 if (adj_allocation.x1 < allocation->x1 ||
7990 adj_allocation.y1 < allocation->y1 ||
7991 adj_allocation.x2 > allocation->x2 ||
7992 adj_allocation.y2 > allocation->y2)
7994 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
7995 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
7996 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
7997 _clutter_actor_get_debug_name (self),
7998 adj_allocation.x1, adj_allocation.y1,
7999 adj_allocation.x2 - adj_allocation.x1,
8000 adj_allocation.y2 - adj_allocation.y1,
8001 allocation->x1, allocation->y1,
8002 allocation->x2 - allocation->x1,
8003 allocation->y2 - allocation->y1);
8007 *allocation = adj_allocation;
8011 * clutter_actor_allocate:
8012 * @self: A #ClutterActor
8013 * @box: new allocation of the actor, in parent-relative coordinates
8014 * @flags: flags that control the allocation
8016 * Called by the parent of an actor to assign the actor its size.
8017 * Should never be called by applications (except when implementing
8018 * a container or layout manager).
8020 * Actors can know from their allocation box whether they have moved
8021 * with respect to their parent actor. The @flags parameter describes
8022 * additional information about the allocation, for instance whether
8023 * the parent has moved with respect to the stage, for example because
8024 * a grandparent's origin has moved.
8029 clutter_actor_allocate (ClutterActor *self,
8030 const ClutterActorBox *box,
8031 ClutterAllocationFlags flags)
8033 ClutterActorPrivate *priv;
8034 ClutterActorClass *klass;
8035 ClutterActorBox old_allocation, real_allocation;
8036 gboolean origin_changed, child_moved, size_changed;
8037 gboolean stage_allocation_changed;
8039 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8040 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8042 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8043 "which isn't a descendent of the stage!\n",
8044 self, _clutter_actor_get_debug_name (self));
8050 old_allocation = priv->allocation;
8051 real_allocation = *box;
8053 /* constraints are allowed to modify the allocation only here; we do
8054 * this prior to all the other checks so that we can bail out if the
8055 * allocation did not change
8057 clutter_actor_update_constraints (self, &real_allocation);
8059 /* adjust the allocation depending on the align/margin properties */
8060 clutter_actor_adjust_allocation (self, &real_allocation);
8062 if (real_allocation.x2 < real_allocation.x1 ||
8063 real_allocation.y2 < real_allocation.y1)
8065 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8066 _clutter_actor_get_debug_name (self),
8067 real_allocation.x2 - real_allocation.x1,
8068 real_allocation.y2 - real_allocation.y1);
8071 /* we allow 0-sized actors, but not negative-sized ones */
8072 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8073 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8075 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8077 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8078 real_allocation.y1 != old_allocation.y1);
8080 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8081 real_allocation.y2 != old_allocation.y2);
8083 if (origin_changed || child_moved || size_changed)
8084 stage_allocation_changed = TRUE;
8086 stage_allocation_changed = FALSE;
8088 /* If we get an allocation "out of the blue"
8089 * (we did not queue relayout), then we want to
8090 * ignore it. But if we have needs_allocation set,
8091 * we want to guarantee that allocate() virtual
8092 * method is always called, i.e. that queue_relayout()
8093 * always results in an allocate() invocation on
8096 * The optimization here is to avoid re-allocating
8097 * actors that did not queue relayout and were
8100 if (!priv->needs_allocation && !stage_allocation_changed)
8102 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8106 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8107 * clutter_actor_allocate(), it indicates whether the parent has its
8108 * absolute origin moved; when passed in to ClutterActor::allocate()
8109 * virtual method though, it indicates whether the child has its
8110 * absolute origin moved. So we set it when child_moved is TRUE
8113 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8115 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8117 klass = CLUTTER_ACTOR_GET_CLASS (self);
8118 klass->allocate (self, &real_allocation, flags);
8120 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8122 if (stage_allocation_changed)
8123 clutter_actor_queue_redraw (self);
8127 * clutter_actor_set_allocation:
8128 * @self: a #ClutterActor
8129 * @box: a #ClutterActorBox
8130 * @flags: allocation flags
8132 * Stores the allocation of @self as defined by @box.
8134 * This function can only be called from within the implementation of
8135 * the #ClutterActorClass.allocate() virtual function.
8137 * The allocation should have been adjusted to take into account constraints,
8138 * alignment, and margin properties. If you are implementing a #ClutterActor
8139 * subclass that provides its own layout management policy for its children
8140 * instead of using a #ClutterLayoutManager delegate, you should not call
8141 * this function on the children of @self; instead, you should call
8142 * clutter_actor_allocate(), which will adjust the allocation box for
8145 * This function should only be used by subclasses of #ClutterActor
8146 * that wish to store their allocation but cannot chain up to the
8147 * parent's implementation; the default implementation of the
8148 * #ClutterActorClass.allocate() virtual function will call this
8151 * It is important to note that, while chaining up was the recommended
8152 * behaviour for #ClutterActor subclasses prior to the introduction of
8153 * this function, it is recommended to call clutter_actor_set_allocation()
8156 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8157 * to handle the allocation of its children, this function will call
8158 * the clutter_layout_manager_allocate() function only if the
8159 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8160 * expected that the subclass will call clutter_layout_manager_allocate()
8161 * by itself. For instance, the following code:
8165 * my_actor_allocate (ClutterActor *actor,
8166 * const ClutterActorBox *allocation,
8167 * ClutterAllocationFlags flags)
8169 * ClutterActorBox new_alloc;
8170 * ClutterAllocationFlags new_flags;
8172 * adjust_allocation (allocation, &new_alloc);
8174 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8176 * /* this will use the layout manager set on the actor */
8177 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8181 * is equivalent to this:
8185 * my_actor_allocate (ClutterActor *actor,
8186 * const ClutterActorBox *allocation,
8187 * ClutterAllocationFlags flags)
8189 * ClutterLayoutManager *layout;
8190 * ClutterActorBox new_alloc;
8192 * adjust_allocation (allocation, &new_alloc);
8194 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8196 * layout = clutter_actor_get_layout_manager (actor);
8197 * clutter_layout_manager_allocate (layout,
8198 * CLUTTER_CONTAINER (actor),
8207 clutter_actor_set_allocation (ClutterActor *self,
8208 const ClutterActorBox *box,
8209 ClutterAllocationFlags flags)
8211 ClutterActorPrivate *priv;
8214 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8215 g_return_if_fail (box != NULL);
8217 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8219 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8220 "can only be called from within the implementation of "
8221 "the ClutterActor::allocate() virtual function.");
8227 g_object_freeze_notify (G_OBJECT (self));
8229 changed = clutter_actor_set_allocation_internal (self, box, flags);
8231 /* we allocate our children before we notify changes in our geometry,
8232 * so that people connecting to properties will be able to get valid
8233 * data out of the sub-tree of the scene graph that has this actor at
8236 clutter_actor_maybe_layout_children (self, box, flags);
8240 ClutterActorBox signal_box = priv->allocation;
8241 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8243 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8248 g_object_thaw_notify (G_OBJECT (self));
8252 * clutter_actor_set_geometry:
8253 * @self: A #ClutterActor
8254 * @geometry: A #ClutterGeometry
8256 * Sets the actor's fixed position and forces its minimum and natural
8257 * size, in pixels. This means the untransformed actor will have the
8258 * given geometry. This is the same as calling clutter_actor_set_position()
8259 * and clutter_actor_set_size().
8261 * Deprecated: 1.10: Use clutter_actor_set_position() and
8262 * clutter_actor_set_size() instead.
8265 clutter_actor_set_geometry (ClutterActor *self,
8266 const ClutterGeometry *geometry)
8268 g_object_freeze_notify (G_OBJECT (self));
8270 clutter_actor_set_position (self, geometry->x, geometry->y);
8271 clutter_actor_set_size (self, geometry->width, geometry->height);
8273 g_object_thaw_notify (G_OBJECT (self));
8277 * clutter_actor_get_geometry:
8278 * @self: A #ClutterActor
8279 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8281 * Gets the size and position of an actor relative to its parent
8282 * actor. This is the same as calling clutter_actor_get_position() and
8283 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8284 * requested size and position if the actor's allocation is invalid.
8286 * Deprecated: 1.10: Use clutter_actor_get_position() and
8287 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8291 clutter_actor_get_geometry (ClutterActor *self,
8292 ClutterGeometry *geometry)
8294 gfloat x, y, width, height;
8296 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8297 g_return_if_fail (geometry != NULL);
8299 clutter_actor_get_position (self, &x, &y);
8300 clutter_actor_get_size (self, &width, &height);
8302 geometry->x = (int) x;
8303 geometry->y = (int) y;
8304 geometry->width = (int) width;
8305 geometry->height = (int) height;
8309 * clutter_actor_set_position:
8310 * @self: A #ClutterActor
8311 * @x: New left position of actor in pixels.
8312 * @y: New top position of actor in pixels.
8314 * Sets the actor's fixed position in pixels relative to any parent
8317 * If a layout manager is in use, this position will override the
8318 * layout manager and force a fixed position.
8321 clutter_actor_set_position (ClutterActor *self,
8325 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8327 g_object_freeze_notify (G_OBJECT (self));
8329 clutter_actor_set_x (self, x);
8330 clutter_actor_set_y (self, y);
8332 g_object_thaw_notify (G_OBJECT (self));
8336 * clutter_actor_get_fixed_position_set:
8337 * @self: A #ClutterActor
8339 * Checks whether an actor has a fixed position set (and will thus be
8340 * unaffected by any layout manager).
8342 * Return value: %TRUE if the fixed position is set on the actor
8347 clutter_actor_get_fixed_position_set (ClutterActor *self)
8349 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8351 return self->priv->position_set;
8355 * clutter_actor_set_fixed_position_set:
8356 * @self: A #ClutterActor
8357 * @is_set: whether to use fixed position
8359 * Sets whether an actor has a fixed position set (and will thus be
8360 * unaffected by any layout manager).
8365 clutter_actor_set_fixed_position_set (ClutterActor *self,
8368 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8370 if (self->priv->position_set == (is_set != FALSE))
8373 self->priv->position_set = is_set != FALSE;
8374 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8376 clutter_actor_queue_relayout (self);
8380 * clutter_actor_move_by:
8381 * @self: A #ClutterActor
8382 * @dx: Distance to move Actor on X axis.
8383 * @dy: Distance to move Actor on Y axis.
8385 * Moves an actor by the specified distance relative to its current
8386 * position in pixels.
8388 * This function modifies the fixed position of an actor and thus removes
8389 * it from any layout management. Another way to move an actor is with an
8390 * anchor point, see clutter_actor_set_anchor_point().
8395 clutter_actor_move_by (ClutterActor *self,
8399 const ClutterLayoutInfo *info;
8402 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8404 info = _clutter_actor_get_layout_info_or_defaults (self);
8408 clutter_actor_set_position (self, x + dx, y + dy);
8412 clutter_actor_set_min_width (ClutterActor *self,
8415 ClutterActorPrivate *priv = self->priv;
8416 ClutterActorBox old = { 0, };
8417 ClutterLayoutInfo *info;
8419 /* if we are setting the size on a top-level actor and the
8420 * backend only supports static top-levels (e.g. framebuffers)
8421 * then we ignore the passed value and we override it with
8422 * the stage implementation's preferred size.
8424 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8425 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8428 info = _clutter_actor_get_layout_info (self);
8430 if (priv->min_width_set && min_width == info->min_width)
8433 g_object_freeze_notify (G_OBJECT (self));
8435 clutter_actor_store_old_geometry (self, &old);
8437 info->min_width = min_width;
8438 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8439 clutter_actor_set_min_width_set (self, TRUE);
8441 clutter_actor_notify_if_geometry_changed (self, &old);
8443 g_object_thaw_notify (G_OBJECT (self));
8445 clutter_actor_queue_relayout (self);
8449 clutter_actor_set_min_height (ClutterActor *self,
8453 ClutterActorPrivate *priv = self->priv;
8454 ClutterActorBox old = { 0, };
8455 ClutterLayoutInfo *info;
8457 /* if we are setting the size on a top-level actor and the
8458 * backend only supports static top-levels (e.g. framebuffers)
8459 * then we ignore the passed value and we override it with
8460 * the stage implementation's preferred size.
8462 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8463 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8466 info = _clutter_actor_get_layout_info (self);
8468 if (priv->min_height_set && min_height == info->min_height)
8471 g_object_freeze_notify (G_OBJECT (self));
8473 clutter_actor_store_old_geometry (self, &old);
8475 info->min_height = min_height;
8476 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8477 clutter_actor_set_min_height_set (self, TRUE);
8479 clutter_actor_notify_if_geometry_changed (self, &old);
8481 g_object_thaw_notify (G_OBJECT (self));
8483 clutter_actor_queue_relayout (self);
8487 clutter_actor_set_natural_width (ClutterActor *self,
8488 gfloat natural_width)
8490 ClutterActorPrivate *priv = self->priv;
8491 ClutterActorBox old = { 0, };
8492 ClutterLayoutInfo *info;
8494 /* if we are setting the size on a top-level actor and the
8495 * backend only supports static top-levels (e.g. framebuffers)
8496 * then we ignore the passed value and we override it with
8497 * the stage implementation's preferred size.
8499 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8500 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8503 info = _clutter_actor_get_layout_info (self);
8505 if (priv->natural_width_set && natural_width == info->natural_width)
8508 g_object_freeze_notify (G_OBJECT (self));
8510 clutter_actor_store_old_geometry (self, &old);
8512 info->natural_width = natural_width;
8513 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8514 clutter_actor_set_natural_width_set (self, TRUE);
8516 clutter_actor_notify_if_geometry_changed (self, &old);
8518 g_object_thaw_notify (G_OBJECT (self));
8520 clutter_actor_queue_relayout (self);
8524 clutter_actor_set_natural_height (ClutterActor *self,
8525 gfloat natural_height)
8527 ClutterActorPrivate *priv = self->priv;
8528 ClutterActorBox old = { 0, };
8529 ClutterLayoutInfo *info;
8531 /* if we are setting the size on a top-level actor and the
8532 * backend only supports static top-levels (e.g. framebuffers)
8533 * then we ignore the passed value and we override it with
8534 * the stage implementation's preferred size.
8536 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8537 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8540 info = _clutter_actor_get_layout_info (self);
8542 if (priv->natural_height_set && natural_height == info->natural_height)
8545 g_object_freeze_notify (G_OBJECT (self));
8547 clutter_actor_store_old_geometry (self, &old);
8549 info->natural_height = natural_height;
8550 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8551 clutter_actor_set_natural_height_set (self, TRUE);
8553 clutter_actor_notify_if_geometry_changed (self, &old);
8555 g_object_thaw_notify (G_OBJECT (self));
8557 clutter_actor_queue_relayout (self);
8561 clutter_actor_set_min_width_set (ClutterActor *self,
8562 gboolean use_min_width)
8564 ClutterActorPrivate *priv = self->priv;
8565 ClutterActorBox old = { 0, };
8567 if (priv->min_width_set == (use_min_width != FALSE))
8570 clutter_actor_store_old_geometry (self, &old);
8572 priv->min_width_set = use_min_width != FALSE;
8573 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8575 clutter_actor_notify_if_geometry_changed (self, &old);
8577 clutter_actor_queue_relayout (self);
8581 clutter_actor_set_min_height_set (ClutterActor *self,
8582 gboolean use_min_height)
8584 ClutterActorPrivate *priv = self->priv;
8585 ClutterActorBox old = { 0, };
8587 if (priv->min_height_set == (use_min_height != FALSE))
8590 clutter_actor_store_old_geometry (self, &old);
8592 priv->min_height_set = use_min_height != FALSE;
8593 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8595 clutter_actor_notify_if_geometry_changed (self, &old);
8597 clutter_actor_queue_relayout (self);
8601 clutter_actor_set_natural_width_set (ClutterActor *self,
8602 gboolean use_natural_width)
8604 ClutterActorPrivate *priv = self->priv;
8605 ClutterActorBox old = { 0, };
8607 if (priv->natural_width_set == (use_natural_width != FALSE))
8610 clutter_actor_store_old_geometry (self, &old);
8612 priv->natural_width_set = use_natural_width != FALSE;
8613 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8615 clutter_actor_notify_if_geometry_changed (self, &old);
8617 clutter_actor_queue_relayout (self);
8621 clutter_actor_set_natural_height_set (ClutterActor *self,
8622 gboolean use_natural_height)
8624 ClutterActorPrivate *priv = self->priv;
8625 ClutterActorBox old = { 0, };
8627 if (priv->natural_height_set == (use_natural_height != FALSE))
8630 clutter_actor_store_old_geometry (self, &old);
8632 priv->natural_height_set = use_natural_height != FALSE;
8633 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8635 clutter_actor_notify_if_geometry_changed (self, &old);
8637 clutter_actor_queue_relayout (self);
8641 * clutter_actor_set_request_mode:
8642 * @self: a #ClutterActor
8643 * @mode: the request mode
8645 * Sets the geometry request mode of @self.
8647 * The @mode determines the order for invoking
8648 * clutter_actor_get_preferred_width() and
8649 * clutter_actor_get_preferred_height()
8654 clutter_actor_set_request_mode (ClutterActor *self,
8655 ClutterRequestMode mode)
8657 ClutterActorPrivate *priv;
8659 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8663 if (priv->request_mode == mode)
8666 priv->request_mode = mode;
8668 priv->needs_width_request = TRUE;
8669 priv->needs_height_request = TRUE;
8671 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8673 clutter_actor_queue_relayout (self);
8677 * clutter_actor_get_request_mode:
8678 * @self: a #ClutterActor
8680 * Retrieves the geometry request mode of @self
8682 * Return value: the request mode for the actor
8687 clutter_actor_get_request_mode (ClutterActor *self)
8689 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8690 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8692 return self->priv->request_mode;
8695 /* variant of set_width() without checks and without notification
8696 * freeze+thaw, for internal usage only
8699 clutter_actor_set_width_internal (ClutterActor *self,
8704 /* the Stage will use the :min-width to control the minimum
8705 * width to be resized to, so we should not be setting it
8706 * along with the :natural-width
8708 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8709 clutter_actor_set_min_width (self, width);
8711 clutter_actor_set_natural_width (self, width);
8715 /* we only unset the :natural-width for the Stage */
8716 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8717 clutter_actor_set_min_width_set (self, FALSE);
8719 clutter_actor_set_natural_width_set (self, FALSE);
8723 /* variant of set_height() without checks and without notification
8724 * freeze+thaw, for internal usage only
8727 clutter_actor_set_height_internal (ClutterActor *self,
8732 /* see the comment above in set_width_internal() */
8733 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8734 clutter_actor_set_min_height (self, height);
8736 clutter_actor_set_natural_height (self, height);
8740 /* see the comment above in set_width_internal() */
8741 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8742 clutter_actor_set_min_height_set (self, FALSE);
8744 clutter_actor_set_natural_height_set (self, FALSE);
8749 * clutter_actor_set_size:
8750 * @self: A #ClutterActor
8751 * @width: New width of actor in pixels, or -1
8752 * @height: New height of actor in pixels, or -1
8754 * Sets the actor's size request in pixels. This overrides any
8755 * "normal" size request the actor would have. For example
8756 * a text actor might normally request the size of the text;
8757 * this function would force a specific size instead.
8759 * If @width and/or @height are -1 the actor will use its
8760 * "normal" size request instead of overriding it, i.e.
8761 * you can "unset" the size with -1.
8763 * This function sets or unsets both the minimum and natural size.
8766 clutter_actor_set_size (ClutterActor *self,
8770 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8772 g_object_freeze_notify (G_OBJECT (self));
8774 clutter_actor_set_width (self, width);
8775 clutter_actor_set_height (self, height);
8777 g_object_thaw_notify (G_OBJECT (self));
8781 * clutter_actor_get_size:
8782 * @self: A #ClutterActor
8783 * @width: (out) (allow-none): return location for the width, or %NULL.
8784 * @height: (out) (allow-none): return location for the height, or %NULL.
8786 * This function tries to "do what you mean" and return
8787 * the size an actor will have. If the actor has a valid
8788 * allocation, the allocation will be returned; otherwise,
8789 * the actors natural size request will be returned.
8791 * If you care whether you get the request vs. the allocation, you
8792 * should probably call a different function like
8793 * clutter_actor_get_allocation_box() or
8794 * clutter_actor_get_preferred_width().
8799 clutter_actor_get_size (ClutterActor *self,
8803 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8806 *width = clutter_actor_get_width (self);
8809 *height = clutter_actor_get_height (self);
8813 * clutter_actor_get_position:
8814 * @self: a #ClutterActor
8815 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8816 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8818 * This function tries to "do what you mean" and tell you where the
8819 * actor is, prior to any transformations. Retrieves the fixed
8820 * position of an actor in pixels, if one has been set; otherwise, if
8821 * the allocation is valid, returns the actor's allocated position;
8822 * otherwise, returns 0,0.
8824 * The returned position is in pixels.
8829 clutter_actor_get_position (ClutterActor *self,
8833 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8836 *x = clutter_actor_get_x (self);
8839 *y = clutter_actor_get_y (self);
8843 * clutter_actor_get_transformed_position:
8844 * @self: A #ClutterActor
8845 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
8846 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
8848 * Gets the absolute position of an actor, in pixels relative to the stage.
8853 clutter_actor_get_transformed_position (ClutterActor *self,
8860 v1.x = v1.y = v1.z = 0;
8861 clutter_actor_apply_transform_to_point (self, &v1, &v2);
8871 * clutter_actor_get_transformed_size:
8872 * @self: A #ClutterActor
8873 * @width: (out) (allow-none): return location for the width, or %NULL
8874 * @height: (out) (allow-none): return location for the height, or %NULL
8876 * Gets the absolute size of an actor in pixels, taking into account the
8879 * If the actor has a valid allocation, the allocated size will be used.
8880 * If the actor has not a valid allocation then the preferred size will
8881 * be transformed and returned.
8883 * If you want the transformed allocation, see
8884 * clutter_actor_get_abs_allocation_vertices() instead.
8886 * <note>When the actor (or one of its ancestors) is rotated around the
8887 * X or Y axis, it no longer appears as on the stage as a rectangle, but
8888 * as a generic quadrangle; in that case this function returns the size
8889 * of the smallest rectangle that encapsulates the entire quad. Please
8890 * note that in this case no assumptions can be made about the relative
8891 * position of this envelope to the absolute position of the actor, as
8892 * returned by clutter_actor_get_transformed_position(); if you need this
8893 * information, you need to use clutter_actor_get_abs_allocation_vertices()
8894 * to get the coords of the actual quadrangle.</note>
8899 clutter_actor_get_transformed_size (ClutterActor *self,
8903 ClutterActorPrivate *priv;
8905 gfloat x_min, x_max, y_min, y_max;
8908 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8912 /* if the actor hasn't been allocated yet, get the preferred
8913 * size and transform that
8915 if (priv->needs_allocation)
8917 gfloat natural_width, natural_height;
8918 ClutterActorBox box;
8920 /* Make a fake allocation to transform.
8922 * NB: _clutter_actor_transform_and_project_box expects a box in
8923 * the actor's coordinate space... */
8928 natural_width = natural_height = 0;
8929 clutter_actor_get_preferred_size (self, NULL, NULL,
8933 box.x2 = natural_width;
8934 box.y2 = natural_height;
8936 _clutter_actor_transform_and_project_box (self, &box, v);
8939 clutter_actor_get_abs_allocation_vertices (self, v);
8941 x_min = x_max = v[0].x;
8942 y_min = y_max = v[0].y;
8944 for (i = 1; i < G_N_ELEMENTS (v); ++i)
8960 *width = x_max - x_min;
8963 *height = y_max - y_min;
8967 * clutter_actor_get_width:
8968 * @self: A #ClutterActor
8970 * Retrieves the width of a #ClutterActor.
8972 * If the actor has a valid allocation, this function will return the
8973 * width of the allocated area given to the actor.
8975 * If the actor does not have a valid allocation, this function will
8976 * return the actor's natural width, that is the preferred width of
8979 * If you care whether you get the preferred width or the width that
8980 * has been assigned to the actor, you should probably call a different
8981 * function like clutter_actor_get_allocation_box() to retrieve the
8982 * allocated size or clutter_actor_get_preferred_width() to retrieve the
8985 * If an actor has a fixed width, for instance a width that has been
8986 * assigned using clutter_actor_set_width(), the width returned will
8987 * be the same value.
8989 * Return value: the width of the actor, in pixels
8992 clutter_actor_get_width (ClutterActor *self)
8994 ClutterActorPrivate *priv;
8996 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9000 if (priv->needs_allocation)
9002 gfloat natural_width = 0;
9004 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9005 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9008 gfloat natural_height = 0;
9010 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9011 clutter_actor_get_preferred_width (self, natural_height,
9016 return natural_width;
9019 return priv->allocation.x2 - priv->allocation.x1;
9023 * clutter_actor_get_height:
9024 * @self: A #ClutterActor
9026 * Retrieves the height of a #ClutterActor.
9028 * If the actor has a valid allocation, this function will return the
9029 * height of the allocated area given to the actor.
9031 * If the actor does not have a valid allocation, this function will
9032 * return the actor's natural height, that is the preferred height of
9035 * If you care whether you get the preferred height or the height that
9036 * has been assigned to the actor, you should probably call a different
9037 * function like clutter_actor_get_allocation_box() to retrieve the
9038 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9041 * If an actor has a fixed height, for instance a height that has been
9042 * assigned using clutter_actor_set_height(), the height returned will
9043 * be the same value.
9045 * Return value: the height of the actor, in pixels
9048 clutter_actor_get_height (ClutterActor *self)
9050 ClutterActorPrivate *priv;
9052 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9056 if (priv->needs_allocation)
9058 gfloat natural_height = 0;
9060 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9062 gfloat natural_width = 0;
9064 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9065 clutter_actor_get_preferred_height (self, natural_width,
9066 NULL, &natural_height);
9069 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9071 return natural_height;
9074 return priv->allocation.y2 - priv->allocation.y1;
9078 * clutter_actor_set_width:
9079 * @self: A #ClutterActor
9080 * @width: Requested new width for the actor, in pixels, or -1
9082 * Forces a width on an actor, causing the actor's preferred width
9083 * and height (if any) to be ignored.
9085 * If @width is -1 the actor will use its preferred width request
9086 * instead of overriding it, i.e. you can "unset" the width with -1.
9088 * This function sets both the minimum and natural size of the actor.
9093 clutter_actor_set_width (ClutterActor *self,
9096 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9098 if (clutter_actor_get_easing_duration (self) != 0)
9100 ClutterTransition *transition;
9102 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9103 if (transition == NULL)
9105 float old_width = clutter_actor_get_width (self);
9107 transition = _clutter_actor_create_transition (self,
9108 obj_props[PROP_WIDTH],
9111 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9114 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9116 clutter_actor_queue_relayout (self);
9120 g_object_freeze_notify (G_OBJECT (self));
9122 clutter_actor_set_width_internal (self, width);
9124 g_object_thaw_notify (G_OBJECT (self));
9129 * clutter_actor_set_height:
9130 * @self: A #ClutterActor
9131 * @height: Requested new height for the actor, in pixels, or -1
9133 * Forces a height on an actor, causing the actor's preferred width
9134 * and height (if any) to be ignored.
9136 * If @height is -1 the actor will use its preferred height instead of
9137 * overriding it, i.e. you can "unset" the height with -1.
9139 * This function sets both the minimum and natural size of the actor.
9144 clutter_actor_set_height (ClutterActor *self,
9147 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9149 if (clutter_actor_get_easing_duration (self) != 0)
9151 ClutterTransition *transition;
9153 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9154 if (transition == NULL)
9156 float old_height = clutter_actor_get_height (self);
9158 transition = _clutter_actor_create_transition (self,
9159 obj_props[PROP_HEIGHT],
9162 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9165 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9167 clutter_actor_queue_relayout (self);
9171 g_object_freeze_notify (G_OBJECT (self));
9173 clutter_actor_set_height_internal (self, height);
9175 g_object_thaw_notify (G_OBJECT (self));
9180 clutter_actor_set_x_internal (ClutterActor *self,
9183 ClutterActorPrivate *priv = self->priv;
9184 ClutterLayoutInfo *linfo;
9185 ClutterActorBox old = { 0, };
9187 linfo = _clutter_actor_get_layout_info (self);
9189 if (priv->position_set && linfo->fixed_x == x)
9192 clutter_actor_store_old_geometry (self, &old);
9195 clutter_actor_set_fixed_position_set (self, TRUE);
9197 clutter_actor_notify_if_geometry_changed (self, &old);
9199 clutter_actor_queue_relayout (self);
9203 clutter_actor_set_y_internal (ClutterActor *self,
9206 ClutterActorPrivate *priv = self->priv;
9207 ClutterLayoutInfo *linfo;
9208 ClutterActorBox old = { 0, };
9210 linfo = _clutter_actor_get_layout_info (self);
9212 if (priv->position_set && linfo->fixed_y == y)
9215 clutter_actor_store_old_geometry (self, &old);
9218 clutter_actor_set_fixed_position_set (self, TRUE);
9220 clutter_actor_notify_if_geometry_changed (self, &old);
9224 * clutter_actor_set_x:
9225 * @self: a #ClutterActor
9226 * @x: the actor's position on the X axis
9228 * Sets the actor's X coordinate, relative to its parent, in pixels.
9230 * Overrides any layout manager and forces a fixed position for
9233 * The #ClutterActor:x property is animatable.
9238 clutter_actor_set_x (ClutterActor *self,
9241 const ClutterLayoutInfo *linfo;
9243 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9245 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9247 if (clutter_actor_get_easing_duration (self) != 0)
9249 ClutterTransition *transition;
9251 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9252 if (transition == NULL)
9254 transition = _clutter_actor_create_transition (self,
9259 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9262 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9264 clutter_actor_queue_relayout (self);
9267 clutter_actor_set_x_internal (self, x);
9271 * clutter_actor_set_y:
9272 * @self: a #ClutterActor
9273 * @y: the actor's position on the Y axis
9275 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9277 * Overrides any layout manager and forces a fixed position for
9280 * The #ClutterActor:y property is animatable.
9285 clutter_actor_set_y (ClutterActor *self,
9288 const ClutterLayoutInfo *linfo;
9290 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9292 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9294 if (clutter_actor_get_easing_duration (self) != 0)
9296 ClutterTransition *transition;
9298 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9299 if (transition == NULL)
9301 transition = _clutter_actor_create_transition (self,
9306 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9309 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9311 clutter_actor_queue_relayout (self);
9314 clutter_actor_set_y_internal (self, y);
9316 clutter_actor_queue_relayout (self);
9320 * clutter_actor_get_x:
9321 * @self: A #ClutterActor
9323 * Retrieves the X coordinate of a #ClutterActor.
9325 * This function tries to "do what you mean", by returning the
9326 * correct value depending on the actor's state.
9328 * If the actor has a valid allocation, this function will return
9329 * the X coordinate of the origin of the allocation box.
9331 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9332 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9333 * function will return that coordinate.
9335 * If both the allocation and a fixed position are missing, this function
9338 * Return value: the X coordinate, in pixels, ignoring any
9339 * transformation (i.e. scaling, rotation)
9342 clutter_actor_get_x (ClutterActor *self)
9344 ClutterActorPrivate *priv;
9346 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9350 if (priv->needs_allocation)
9352 if (priv->position_set)
9354 const ClutterLayoutInfo *info;
9356 info = _clutter_actor_get_layout_info_or_defaults (self);
9358 return info->fixed_x;
9364 return priv->allocation.x1;
9368 * clutter_actor_get_y:
9369 * @self: A #ClutterActor
9371 * Retrieves the Y coordinate of a #ClutterActor.
9373 * This function tries to "do what you mean", by returning the
9374 * correct value depending on the actor's state.
9376 * If the actor has a valid allocation, this function will return
9377 * the Y coordinate of the origin of the allocation box.
9379 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9380 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9381 * function will return that coordinate.
9383 * If both the allocation and a fixed position are missing, this function
9386 * Return value: the Y coordinate, in pixels, ignoring any
9387 * transformation (i.e. scaling, rotation)
9390 clutter_actor_get_y (ClutterActor *self)
9392 ClutterActorPrivate *priv;
9394 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9398 if (priv->needs_allocation)
9400 if (priv->position_set)
9402 const ClutterLayoutInfo *info;
9404 info = _clutter_actor_get_layout_info_or_defaults (self);
9406 return info->fixed_y;
9412 return priv->allocation.y1;
9416 * clutter_actor_set_scale:
9417 * @self: A #ClutterActor
9418 * @scale_x: double factor to scale actor by horizontally.
9419 * @scale_y: double factor to scale actor by vertically.
9421 * Scales an actor with the given factors. The scaling is relative to
9422 * the scale center and the anchor point. The scale center is
9423 * unchanged by this function and defaults to 0,0.
9425 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9431 clutter_actor_set_scale (ClutterActor *self,
9435 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9437 g_object_freeze_notify (G_OBJECT (self));
9439 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9440 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9442 g_object_thaw_notify (G_OBJECT (self));
9446 * clutter_actor_set_scale_full:
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 * @center_x: X coordinate of the center of the scale.
9451 * @center_y: Y coordinate of the center of the scale
9453 * Scales an actor with the given factors around the given center
9454 * point. The center point is specified in pixels relative to the
9455 * anchor point (usually the top left corner of the actor).
9457 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9463 clutter_actor_set_scale_full (ClutterActor *self,
9469 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9471 g_object_freeze_notify (G_OBJECT (self));
9473 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9474 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9475 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9476 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9478 g_object_thaw_notify (G_OBJECT (self));
9482 * clutter_actor_set_scale_with_gravity:
9483 * @self: A #ClutterActor
9484 * @scale_x: double factor to scale actor by horizontally.
9485 * @scale_y: double factor to scale actor by vertically.
9486 * @gravity: the location of the scale center expressed as a compass
9489 * Scales an actor with the given factors around the given
9490 * center point. The center point is specified as one of the compass
9491 * directions in #ClutterGravity. For example, setting it to north
9492 * will cause the top of the actor to remain unchanged and the rest of
9493 * the actor to expand left, right and downwards.
9495 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9501 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9504 ClutterGravity gravity)
9506 ClutterTransformInfo *info;
9509 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9511 obj = G_OBJECT (self);
9513 g_object_freeze_notify (obj);
9515 info = _clutter_actor_get_transform_info (self);
9516 info->scale_x = scale_x;
9517 info->scale_y = scale_y;
9519 if (gravity == CLUTTER_GRAVITY_NONE)
9520 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9522 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9524 self->priv->transform_valid = FALSE;
9526 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9527 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9528 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9529 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9530 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9532 clutter_actor_queue_redraw (self);
9534 g_object_thaw_notify (obj);
9538 * clutter_actor_get_scale:
9539 * @self: A #ClutterActor
9540 * @scale_x: (out) (allow-none): Location to store horizonal
9541 * scale factor, or %NULL.
9542 * @scale_y: (out) (allow-none): Location to store vertical
9543 * scale factor, or %NULL.
9545 * Retrieves an actors scale factors.
9550 clutter_actor_get_scale (ClutterActor *self,
9554 const ClutterTransformInfo *info;
9556 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9558 info = _clutter_actor_get_transform_info_or_defaults (self);
9561 *scale_x = info->scale_x;
9564 *scale_y = info->scale_y;
9568 * clutter_actor_get_scale_center:
9569 * @self: A #ClutterActor
9570 * @center_x: (out) (allow-none): Location to store the X position
9571 * of the scale center, or %NULL.
9572 * @center_y: (out) (allow-none): Location to store the Y position
9573 * of the scale center, or %NULL.
9575 * Retrieves the scale center coordinate in pixels relative to the top
9576 * left corner of the actor. If the scale center was specified using a
9577 * #ClutterGravity this will calculate the pixel offset using the
9578 * current size of the actor.
9583 clutter_actor_get_scale_center (ClutterActor *self,
9587 const ClutterTransformInfo *info;
9589 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9591 info = _clutter_actor_get_transform_info_or_defaults (self);
9593 clutter_anchor_coord_get_units (self, &info->scale_center,
9600 * clutter_actor_get_scale_gravity:
9601 * @self: A #ClutterActor
9603 * Retrieves the scale center as a compass direction. If the scale
9604 * center was specified in pixels or units this will return
9605 * %CLUTTER_GRAVITY_NONE.
9607 * Return value: the scale gravity
9612 clutter_actor_get_scale_gravity (ClutterActor *self)
9614 const ClutterTransformInfo *info;
9616 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9618 info = _clutter_actor_get_transform_info_or_defaults (self);
9620 return clutter_anchor_coord_get_gravity (&info->scale_center);
9624 clutter_actor_set_opacity_internal (ClutterActor *self,
9627 ClutterActorPrivate *priv = self->priv;
9629 if (priv->opacity != opacity)
9631 priv->opacity = opacity;
9633 /* Queue a redraw from the flatten effect so that it can use
9634 its cached image if available instead of having to redraw the
9635 actual actor. If it doesn't end up using the FBO then the
9636 effect is still able to continue the paint anyway. If there
9637 is no flatten effect yet then this is equivalent to queueing
9639 _clutter_actor_queue_redraw_full (self,
9642 priv->flatten_effect);
9644 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9649 * clutter_actor_set_opacity:
9650 * @self: A #ClutterActor
9651 * @opacity: New opacity value for the actor.
9653 * Sets the actor's opacity, with zero being completely transparent and
9654 * 255 (0xff) being fully opaque.
9656 * The #ClutterActor:opacity property is animatable.
9659 clutter_actor_set_opacity (ClutterActor *self,
9662 ClutterActorPrivate *priv;
9664 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9668 if (clutter_actor_get_easing_duration (self) != 0)
9670 ClutterTransition *transition;
9672 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9673 if (transition == NULL)
9675 transition = _clutter_actor_create_transition (self,
9676 obj_props[PROP_OPACITY],
9679 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9682 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9684 clutter_actor_queue_redraw (self);
9687 clutter_actor_set_opacity_internal (self, opacity);
9691 * clutter_actor_get_paint_opacity_internal:
9692 * @self: a #ClutterActor
9694 * Retrieves the absolute opacity of the actor, as it appears on the stage
9696 * This function does not do type checks
9698 * Return value: the absolute opacity of the actor
9701 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9703 ClutterActorPrivate *priv = self->priv;
9704 ClutterActor *parent;
9706 /* override the top-level opacity to always be 255; even in
9707 * case of ClutterStage:use-alpha being TRUE we want the rest
9708 * of the scene to be painted
9710 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9713 if (priv->opacity_override >= 0)
9714 return priv->opacity_override;
9716 parent = priv->parent;
9718 /* Factor in the actual actors opacity with parents */
9721 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9723 if (opacity != 0xff)
9724 return (opacity * priv->opacity) / 0xff;
9727 return priv->opacity;
9732 * clutter_actor_get_paint_opacity:
9733 * @self: A #ClutterActor
9735 * Retrieves the absolute opacity of the actor, as it appears on the stage.
9737 * This function traverses the hierarchy chain and composites the opacity of
9738 * the actor with that of its parents.
9740 * This function is intended for subclasses to use in the paint virtual
9741 * function, to paint themselves with the correct opacity.
9743 * Return value: The actor opacity value.
9748 clutter_actor_get_paint_opacity (ClutterActor *self)
9750 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9752 return clutter_actor_get_paint_opacity_internal (self);
9756 * clutter_actor_get_opacity:
9757 * @self: a #ClutterActor
9759 * Retrieves the opacity value of an actor, as set by
9760 * clutter_actor_set_opacity().
9762 * For retrieving the absolute opacity of the actor inside a paint
9763 * virtual function, see clutter_actor_get_paint_opacity().
9765 * Return value: the opacity of the actor
9768 clutter_actor_get_opacity (ClutterActor *self)
9770 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9772 return self->priv->opacity;
9776 * clutter_actor_set_offscreen_redirect:
9777 * @self: A #ClutterActor
9778 * @redirect: New offscreen redirect flags for the actor.
9780 * Defines the circumstances where the actor should be redirected into
9781 * an offscreen image. The offscreen image is used to flatten the
9782 * actor into a single image while painting for two main reasons.
9783 * Firstly, when the actor is painted a second time without any of its
9784 * contents changing it can simply repaint the cached image without
9785 * descending further down the actor hierarchy. Secondly, it will make
9786 * the opacity look correct even if there are overlapping primitives
9789 * Caching the actor could in some cases be a performance win and in
9790 * some cases be a performance lose so it is important to determine
9791 * which value is right for an actor before modifying this value. For
9792 * example, there is never any reason to flatten an actor that is just
9793 * a single texture (such as a #ClutterTexture) because it is
9794 * effectively already cached in an image so the offscreen would be
9795 * redundant. Also if the actor contains primitives that are far apart
9796 * with a large transparent area in the middle (such as a large
9797 * CluterGroup with a small actor in the top left and a small actor in
9798 * the bottom right) then the cached image will contain the entire
9799 * image of the large area and the paint will waste time blending all
9800 * of the transparent pixels in the middle.
9802 * The default method of implementing opacity on a container simply
9803 * forwards on the opacity to all of the children. If the children are
9804 * overlapping then it will appear as if they are two separate glassy
9805 * objects and there will be a break in the color where they
9806 * overlap. By redirecting to an offscreen buffer it will be as if the
9807 * two opaque objects are combined into one and then made transparent
9808 * which is usually what is expected.
9810 * The image below demonstrates the difference between redirecting and
9811 * not. The image shows two Clutter groups, each containing a red and
9812 * a green rectangle which overlap. The opacity on the group is set to
9813 * 128 (which is 50%). When the offscreen redirect is not used, the
9814 * red rectangle can be seen through the blue rectangle as if the two
9815 * rectangles were separately transparent. When the redirect is used
9816 * the group as a whole is transparent instead so the red rectangle is
9817 * not visible where they overlap.
9819 * <figure id="offscreen-redirect">
9820 * <title>Sample of using an offscreen redirect for transparency</title>
9821 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
9824 * The default value for this property is 0, so we effectively will
9825 * never redirect an actor offscreen by default. This means that there
9826 * are times that transparent actors may look glassy as described
9827 * above. The reason this is the default is because there is a
9828 * performance trade off between quality and performance here. In many
9829 * cases the default form of glassy opacity looks good enough, but if
9830 * it's not you will need to set the
9831 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
9832 * redirection for opacity.
9834 * Custom actors that don't contain any overlapping primitives are
9835 * recommended to override the has_overlaps() virtual to return %FALSE
9836 * for maximum efficiency.
9841 clutter_actor_set_offscreen_redirect (ClutterActor *self,
9842 ClutterOffscreenRedirect redirect)
9844 ClutterActorPrivate *priv;
9846 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9850 if (priv->offscreen_redirect != redirect)
9852 priv->offscreen_redirect = redirect;
9854 /* Queue a redraw from the effect so that it can use its cached
9855 image if available instead of having to redraw the actual
9856 actor. If it doesn't end up using the FBO then the effect is
9857 still able to continue the paint anyway. If there is no
9858 effect then this is equivalent to queuing a full redraw */
9859 _clutter_actor_queue_redraw_full (self,
9862 priv->flatten_effect);
9864 g_object_notify_by_pspec (G_OBJECT (self),
9865 obj_props[PROP_OFFSCREEN_REDIRECT]);
9870 * clutter_actor_get_offscreen_redirect:
9871 * @self: a #ClutterActor
9873 * Retrieves whether to redirect the actor to an offscreen buffer, as
9874 * set by clutter_actor_set_offscreen_redirect().
9876 * Return value: the value of the offscreen-redirect property of the actor
9880 ClutterOffscreenRedirect
9881 clutter_actor_get_offscreen_redirect (ClutterActor *self)
9883 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9885 return self->priv->offscreen_redirect;
9889 * clutter_actor_set_name:
9890 * @self: A #ClutterActor
9891 * @name: Textual tag to apply to actor
9893 * Sets the given name to @self. The name can be used to identify
9897 clutter_actor_set_name (ClutterActor *self,
9900 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9902 g_free (self->priv->name);
9903 self->priv->name = g_strdup (name);
9905 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
9909 * clutter_actor_get_name:
9910 * @self: A #ClutterActor
9912 * Retrieves the name of @self.
9914 * Return value: the name of the actor, or %NULL. The returned string is
9915 * owned by the actor and should not be modified or freed.
9918 clutter_actor_get_name (ClutterActor *self)
9920 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
9922 return self->priv->name;
9926 * clutter_actor_get_gid:
9927 * @self: A #ClutterActor
9929 * Retrieves the unique id for @self.
9931 * Return value: Globally unique value for this object instance.
9935 * Deprecated: 1.8: The id is not used any longer.
9938 clutter_actor_get_gid (ClutterActor *self)
9940 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9942 return self->priv->id;
9946 clutter_actor_set_depth_internal (ClutterActor *self,
9949 ClutterTransformInfo *info;
9951 info = _clutter_actor_get_transform_info (self);
9953 if (info->depth != depth)
9955 /* Sets Z value - XXX 2.0: should we invert? */
9956 info->depth = depth;
9958 self->priv->transform_valid = FALSE;
9960 /* FIXME - remove this crap; sadly, there are still containers
9961 * in Clutter that depend on this utter brain damage
9963 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
9965 clutter_actor_queue_redraw (self);
9967 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
9972 * clutter_actor_set_depth:
9973 * @self: a #ClutterActor
9976 * Sets the Z coordinate of @self to @depth.
9978 * The unit used by @depth is dependant on the perspective setup. See
9979 * also clutter_stage_set_perspective().
9982 clutter_actor_set_depth (ClutterActor *self,
9985 const ClutterTransformInfo *tinfo;
9987 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9989 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
9991 if (clutter_actor_get_easing_duration (self) != 0)
9993 ClutterTransition *transition;
9995 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
9996 if (transition == NULL)
9998 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10001 clutter_timeline_start (CLUTTER_TIMELINE (transition));
10004 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10006 clutter_actor_queue_redraw (self);
10009 clutter_actor_set_depth_internal (self, depth);
10013 * clutter_actor_get_depth:
10014 * @self: a #ClutterActor
10016 * Retrieves the depth of @self.
10018 * Return value: the depth of the actor
10021 clutter_actor_get_depth (ClutterActor *self)
10023 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10025 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10029 * clutter_actor_set_rotation:
10030 * @self: a #ClutterActor
10031 * @axis: the axis of rotation
10032 * @angle: the angle of rotation
10033 * @x: X coordinate of the rotation center
10034 * @y: Y coordinate of the rotation center
10035 * @z: Z coordinate of the rotation center
10037 * Sets the rotation angle of @self around the given axis.
10039 * The rotation center coordinates used depend on the value of @axis:
10041 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10042 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10043 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10046 * The rotation coordinates are relative to the anchor point of the
10047 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10048 * point is set, the upper left corner is assumed as the origin.
10053 clutter_actor_set_rotation (ClutterActor *self,
10054 ClutterRotateAxis axis,
10062 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10068 g_object_freeze_notify (G_OBJECT (self));
10070 clutter_actor_set_rotation_angle (self, axis, angle);
10071 clutter_actor_set_rotation_center_internal (self, axis, &v);
10073 g_object_thaw_notify (G_OBJECT (self));
10077 * clutter_actor_set_z_rotation_from_gravity:
10078 * @self: a #ClutterActor
10079 * @angle: the angle of rotation
10080 * @gravity: the center point of the rotation
10082 * Sets the rotation angle of @self around the Z axis using the center
10083 * point specified as a compass point. For example to rotate such that
10084 * the center of the actor remains static you can use
10085 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10086 * will move accordingly.
10091 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10093 ClutterGravity gravity)
10095 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10097 if (gravity == CLUTTER_GRAVITY_NONE)
10098 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10101 GObject *obj = G_OBJECT (self);
10102 ClutterTransformInfo *info;
10104 info = _clutter_actor_get_transform_info (self);
10106 g_object_freeze_notify (obj);
10108 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10110 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10111 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10112 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10114 g_object_thaw_notify (obj);
10119 * clutter_actor_get_rotation:
10120 * @self: a #ClutterActor
10121 * @axis: the axis of rotation
10122 * @x: (out): return value for the X coordinate of the center of rotation
10123 * @y: (out): return value for the Y coordinate of the center of rotation
10124 * @z: (out): return value for the Z coordinate of the center of rotation
10126 * Retrieves the angle and center of rotation on the given axis,
10127 * set using clutter_actor_set_rotation().
10129 * Return value: the angle of rotation
10134 clutter_actor_get_rotation (ClutterActor *self,
10135 ClutterRotateAxis axis,
10140 const ClutterTransformInfo *info;
10141 const AnchorCoord *anchor_coord;
10142 gdouble retval = 0;
10144 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10146 info = _clutter_actor_get_transform_info_or_defaults (self);
10150 case CLUTTER_X_AXIS:
10151 anchor_coord = &info->rx_center;
10152 retval = info->rx_angle;
10155 case CLUTTER_Y_AXIS:
10156 anchor_coord = &info->ry_center;
10157 retval = info->ry_angle;
10160 case CLUTTER_Z_AXIS:
10161 anchor_coord = &info->rz_center;
10162 retval = info->rz_angle;
10166 anchor_coord = NULL;
10171 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10177 * clutter_actor_get_z_rotation_gravity:
10178 * @self: A #ClutterActor
10180 * Retrieves the center for the rotation around the Z axis as a
10181 * compass direction. If the center was specified in pixels or units
10182 * this will return %CLUTTER_GRAVITY_NONE.
10184 * Return value: the Z rotation center
10189 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10191 const ClutterTransformInfo *info;
10193 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10195 info = _clutter_actor_get_transform_info_or_defaults (self);
10197 return clutter_anchor_coord_get_gravity (&info->rz_center);
10201 * clutter_actor_set_clip:
10202 * @self: A #ClutterActor
10203 * @xoff: X offset of the clip rectangle
10204 * @yoff: Y offset of the clip rectangle
10205 * @width: Width of the clip rectangle
10206 * @height: Height of the clip rectangle
10208 * Sets clip area for @self. The clip area is always computed from the
10209 * upper left corner of the actor, even if the anchor point is set
10215 clutter_actor_set_clip (ClutterActor *self,
10221 ClutterActorPrivate *priv;
10223 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10227 if (priv->has_clip &&
10228 priv->clip.x == xoff &&
10229 priv->clip.y == yoff &&
10230 priv->clip.width == width &&
10231 priv->clip.height == height)
10234 priv->clip.x = xoff;
10235 priv->clip.y = yoff;
10236 priv->clip.width = width;
10237 priv->clip.height = height;
10239 priv->has_clip = TRUE;
10241 clutter_actor_queue_redraw (self);
10243 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10244 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10248 * clutter_actor_remove_clip:
10249 * @self: A #ClutterActor
10251 * Removes clip area from @self.
10254 clutter_actor_remove_clip (ClutterActor *self)
10256 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10258 if (!self->priv->has_clip)
10261 self->priv->has_clip = FALSE;
10263 clutter_actor_queue_redraw (self);
10265 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10269 * clutter_actor_has_clip:
10270 * @self: a #ClutterActor
10272 * Determines whether the actor has a clip area set or not.
10274 * Return value: %TRUE if the actor has a clip area set.
10279 clutter_actor_has_clip (ClutterActor *self)
10281 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10283 return self->priv->has_clip;
10287 * clutter_actor_get_clip:
10288 * @self: a #ClutterActor
10289 * @xoff: (out) (allow-none): return location for the X offset of
10290 * the clip rectangle, or %NULL
10291 * @yoff: (out) (allow-none): return location for the Y offset of
10292 * the clip rectangle, or %NULL
10293 * @width: (out) (allow-none): return location for the width of
10294 * the clip rectangle, or %NULL
10295 * @height: (out) (allow-none): return location for the height of
10296 * the clip rectangle, or %NULL
10298 * Gets the clip area for @self, if any is set
10303 clutter_actor_get_clip (ClutterActor *self,
10309 ClutterActorPrivate *priv;
10311 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10315 if (!priv->has_clip)
10319 *xoff = priv->clip.x;
10322 *yoff = priv->clip.y;
10325 *width = priv->clip.width;
10327 if (height != NULL)
10328 *height = priv->clip.height;
10332 * clutter_actor_get_children:
10333 * @self: a #ClutterActor
10335 * Retrieves the list of children of @self.
10337 * Return value: (transfer container) (element-type ClutterActor): A newly
10338 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10344 clutter_actor_get_children (ClutterActor *self)
10346 ClutterActor *iter;
10349 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10351 /* we walk the list backward so that we can use prepend(),
10354 for (iter = self->priv->last_child, res = NULL;
10356 iter = iter->priv->prev_sibling)
10358 res = g_list_prepend (res, iter);
10365 * insert_child_at_depth:
10366 * @self: a #ClutterActor
10367 * @child: a #ClutterActor
10369 * Inserts @child inside the list of children held by @self, using
10370 * the depth as the insertion criteria.
10372 * This sadly makes the insertion not O(1), but we can keep the
10373 * list sorted so that the painters algorithm we use for painting
10374 * the children will work correctly.
10377 insert_child_at_depth (ClutterActor *self,
10378 ClutterActor *child,
10379 gpointer dummy G_GNUC_UNUSED)
10381 ClutterActor *iter;
10384 child->priv->parent = self;
10387 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10389 /* special-case the first child */
10390 if (self->priv->n_children == 0)
10392 self->priv->first_child = child;
10393 self->priv->last_child = child;
10395 child->priv->next_sibling = NULL;
10396 child->priv->prev_sibling = NULL;
10401 /* Find the right place to insert the child so that it will still be
10402 sorted and the child will be after all of the actors at the same
10404 for (iter = self->priv->first_child;
10406 iter = iter->priv->next_sibling)
10411 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10413 if (iter_depth > child_depth)
10419 ClutterActor *tmp = iter->priv->prev_sibling;
10422 tmp->priv->next_sibling = child;
10424 /* Insert the node before the found one */
10425 child->priv->prev_sibling = iter->priv->prev_sibling;
10426 child->priv->next_sibling = iter;
10427 iter->priv->prev_sibling = child;
10431 ClutterActor *tmp = self->priv->last_child;
10434 tmp->priv->next_sibling = child;
10436 /* insert the node at the end of the list */
10437 child->priv->prev_sibling = self->priv->last_child;
10438 child->priv->next_sibling = NULL;
10441 if (child->priv->prev_sibling == NULL)
10442 self->priv->first_child = child;
10444 if (child->priv->next_sibling == NULL)
10445 self->priv->last_child = child;
10449 insert_child_at_index (ClutterActor *self,
10450 ClutterActor *child,
10453 gint index_ = GPOINTER_TO_INT (data_);
10455 child->priv->parent = self;
10459 ClutterActor *tmp = self->priv->first_child;
10462 tmp->priv->prev_sibling = child;
10464 child->priv->prev_sibling = NULL;
10465 child->priv->next_sibling = tmp;
10467 else if (index_ < 0 || index_ >= self->priv->n_children)
10469 ClutterActor *tmp = self->priv->last_child;
10472 tmp->priv->next_sibling = child;
10474 child->priv->prev_sibling = tmp;
10475 child->priv->next_sibling = NULL;
10479 ClutterActor *iter;
10482 for (iter = self->priv->first_child, i = 0;
10484 iter = iter->priv->next_sibling, i += 1)
10488 ClutterActor *tmp = iter->priv->prev_sibling;
10490 child->priv->prev_sibling = tmp;
10491 child->priv->next_sibling = iter;
10493 iter->priv->prev_sibling = child;
10496 tmp->priv->next_sibling = child;
10503 if (child->priv->prev_sibling == NULL)
10504 self->priv->first_child = child;
10506 if (child->priv->next_sibling == NULL)
10507 self->priv->last_child = child;
10511 insert_child_above (ClutterActor *self,
10512 ClutterActor *child,
10515 ClutterActor *sibling = data;
10517 child->priv->parent = self;
10519 if (sibling == NULL)
10520 sibling = self->priv->last_child;
10522 child->priv->prev_sibling = sibling;
10524 if (sibling != NULL)
10526 ClutterActor *tmp = sibling->priv->next_sibling;
10528 child->priv->next_sibling = tmp;
10531 tmp->priv->prev_sibling = child;
10533 sibling->priv->next_sibling = child;
10536 child->priv->next_sibling = NULL;
10538 if (child->priv->prev_sibling == NULL)
10539 self->priv->first_child = child;
10541 if (child->priv->next_sibling == NULL)
10542 self->priv->last_child = child;
10546 insert_child_below (ClutterActor *self,
10547 ClutterActor *child,
10550 ClutterActor *sibling = data;
10552 child->priv->parent = self;
10554 if (sibling == NULL)
10555 sibling = self->priv->first_child;
10557 child->priv->next_sibling = sibling;
10559 if (sibling != NULL)
10561 ClutterActor *tmp = sibling->priv->prev_sibling;
10563 child->priv->prev_sibling = tmp;
10566 tmp->priv->next_sibling = child;
10568 sibling->priv->prev_sibling = child;
10571 child->priv->prev_sibling = NULL;
10573 if (child->priv->prev_sibling == NULL)
10574 self->priv->first_child = child;
10576 if (child->priv->next_sibling == NULL)
10577 self->priv->last_child = child;
10580 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10581 ClutterActor *child,
10585 ADD_CHILD_CREATE_META = 1 << 0,
10586 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10587 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10588 ADD_CHILD_CHECK_STATE = 1 << 3,
10589 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10591 /* default flags for public API */
10592 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10593 ADD_CHILD_EMIT_PARENT_SET |
10594 ADD_CHILD_EMIT_ACTOR_ADDED |
10595 ADD_CHILD_CHECK_STATE |
10596 ADD_CHILD_NOTIFY_FIRST_LAST,
10598 /* flags for legacy/deprecated API */
10599 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10600 ADD_CHILD_CHECK_STATE |
10601 ADD_CHILD_NOTIFY_FIRST_LAST
10602 } ClutterActorAddChildFlags;
10605 * clutter_actor_add_child_internal:
10606 * @self: a #ClutterActor
10607 * @child: a #ClutterActor
10608 * @flags: control flags for actions
10609 * @add_func: delegate function
10610 * @data: (closure): data to pass to @add_func
10612 * Adds @child to the list of children of @self.
10614 * The actual insertion inside the list is delegated to @add_func: this
10615 * function will just set up the state, perform basic checks, and emit
10618 * The @flags argument is used to perform additional operations.
10621 clutter_actor_add_child_internal (ClutterActor *self,
10622 ClutterActor *child,
10623 ClutterActorAddChildFlags flags,
10624 ClutterActorAddChildFunc add_func,
10627 ClutterTextDirection text_dir;
10628 gboolean create_meta;
10629 gboolean emit_parent_set, emit_actor_added;
10630 gboolean check_state;
10631 gboolean notify_first_last;
10632 ClutterActor *old_first_child, *old_last_child;
10634 if (child->priv->parent != NULL)
10636 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10637 "use clutter_actor_remove_child() first.",
10638 _clutter_actor_get_debug_name (child),
10639 _clutter_actor_get_debug_name (child->priv->parent));
10643 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10645 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10646 "a child of another actor.",
10647 _clutter_actor_get_debug_name (child));
10652 /* XXX - this check disallows calling methods that change the stacking
10653 * order within the destruction sequence, by triggering a critical
10654 * warning first, and leaving the actor in an undefined state, which
10655 * then ends up being caught by an assertion.
10657 * the reproducible sequence is:
10659 * - actor gets destroyed;
10660 * - another actor, linked to the first, will try to change the
10661 * stacking order of the first actor;
10662 * - changing the stacking order is a composite operation composed
10663 * by the following steps:
10664 * 1. ref() the child;
10665 * 2. remove_child_internal(), which removes the reference;
10666 * 3. add_child_internal(), which adds a reference;
10667 * - the state of the actor is not changed between (2) and (3), as
10668 * it could be an expensive recomputation;
10669 * - if (3) bails out, then the actor is in an undefined state, but
10671 * - the destruction sequence terminates, but the actor is unparented
10672 * while its state indicates being parented instead.
10673 * - assertion failure.
10675 * the obvious fix would be to decompose each set_child_*_sibling()
10676 * method into proper remove_child()/add_child(), with state validation;
10677 * this may cause excessive work, though, and trigger a cascade of other
10678 * bugs in code that assumes that a change in the stacking order is an
10679 * atomic operation.
10681 * another potential fix is to just remove this check here, and let
10682 * code doing stacking order changes inside the destruction sequence
10683 * of an actor continue doing the work.
10685 * the third fix is to silently bail out early from every
10686 * set_child_*_sibling() and set_child_at_index() method, and avoid
10689 * I have a preference for the second solution, since it involves the
10690 * least amount of work, and the least amount of code duplication.
10692 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10694 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10696 g_warning ("The actor '%s' is currently being destroyed, and "
10697 "cannot be added as a child of another actor.",
10698 _clutter_actor_get_debug_name (child));
10703 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10704 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10705 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10706 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10707 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10709 old_first_child = self->priv->first_child;
10710 old_last_child = self->priv->last_child;
10712 g_object_freeze_notify (G_OBJECT (self));
10715 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10717 g_object_ref_sink (child);
10718 child->priv->parent = NULL;
10719 child->priv->next_sibling = NULL;
10720 child->priv->prev_sibling = NULL;
10722 /* delegate the actual insertion */
10723 add_func (self, child, data);
10725 g_assert (child->priv->parent == self);
10727 self->priv->n_children += 1;
10729 self->priv->age += 1;
10731 /* if push_internal() has been called then we automatically set
10732 * the flag on the actor
10734 if (self->priv->internal_child)
10735 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10737 /* clutter_actor_reparent() will emit ::parent-set for us */
10738 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10739 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10743 /* If parent is mapped or realized, we need to also be mapped or
10744 * realized once we're inside the parent.
10746 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10748 /* propagate the parent's text direction to the child */
10749 text_dir = clutter_actor_get_text_direction (self);
10750 clutter_actor_set_text_direction (child, text_dir);
10753 if (child->priv->show_on_set_parent)
10754 clutter_actor_show (child);
10756 if (CLUTTER_ACTOR_IS_MAPPED (child))
10757 clutter_actor_queue_redraw (child);
10759 /* maintain the invariant that if an actor needs layout,
10760 * its parents do as well
10762 if (child->priv->needs_width_request ||
10763 child->priv->needs_height_request ||
10764 child->priv->needs_allocation)
10766 /* we work around the short-circuiting we do
10767 * in clutter_actor_queue_relayout() since we
10768 * want to force a relayout
10770 child->priv->needs_width_request = TRUE;
10771 child->priv->needs_height_request = TRUE;
10772 child->priv->needs_allocation = TRUE;
10774 clutter_actor_queue_relayout (child->priv->parent);
10777 if (emit_actor_added)
10778 g_signal_emit_by_name (self, "actor-added", child);
10780 if (notify_first_last)
10782 if (old_first_child != self->priv->first_child)
10783 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
10785 if (old_last_child != self->priv->last_child)
10786 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
10789 g_object_thaw_notify (G_OBJECT (self));
10793 * clutter_actor_add_child:
10794 * @self: a #ClutterActor
10795 * @child: a #ClutterActor
10797 * Adds @child to the children of @self.
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 take into consideration the #ClutterActor:depth
10803 * of @child, and will keep the list of children sorted.
10805 * This function will emit the #ClutterContainer::actor-added signal
10811 clutter_actor_add_child (ClutterActor *self,
10812 ClutterActor *child)
10814 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10815 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10816 g_return_if_fail (self != child);
10817 g_return_if_fail (child->priv->parent == NULL);
10819 clutter_actor_add_child_internal (self, child,
10820 ADD_CHILD_DEFAULT_FLAGS,
10821 insert_child_at_depth,
10826 * clutter_actor_insert_child_at_index:
10827 * @self: a #ClutterActor
10828 * @child: a #ClutterActor
10829 * @index_: the index
10831 * Inserts @child into the list of children of @self, using the
10832 * given @index_. If @index_ is greater than the number of children
10833 * in @self, or is less than 0, then the new child is added at the end.
10835 * This function will acquire a reference on @child that will only
10836 * be released when calling clutter_actor_remove_child().
10838 * This function will not take into consideration the #ClutterActor:depth
10841 * This function will emit the #ClutterContainer::actor-added signal
10847 clutter_actor_insert_child_at_index (ClutterActor *self,
10848 ClutterActor *child,
10851 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10852 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10853 g_return_if_fail (self != child);
10854 g_return_if_fail (child->priv->parent == NULL);
10856 clutter_actor_add_child_internal (self, child,
10857 ADD_CHILD_DEFAULT_FLAGS,
10858 insert_child_at_index,
10859 GINT_TO_POINTER (index_));
10863 * clutter_actor_insert_child_above:
10864 * @self: a #ClutterActor
10865 * @child: a #ClutterActor
10866 * @sibling: (allow-none): a child of @self, or %NULL
10868 * Inserts @child into the list of children of @self, above another
10869 * child of @self or, if @sibling is %NULL, above all the children
10872 * This function will acquire a reference on @child that will only
10873 * be released when calling clutter_actor_remove_child().
10875 * This function will not take into consideration the #ClutterActor:depth
10878 * This function will emit the #ClutterContainer::actor-added signal
10884 clutter_actor_insert_child_above (ClutterActor *self,
10885 ClutterActor *child,
10886 ClutterActor *sibling)
10888 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10889 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10890 g_return_if_fail (self != child);
10891 g_return_if_fail (child != sibling);
10892 g_return_if_fail (child->priv->parent == NULL);
10893 g_return_if_fail (sibling == NULL ||
10894 (CLUTTER_IS_ACTOR (sibling) &&
10895 sibling->priv->parent == self));
10897 clutter_actor_add_child_internal (self, child,
10898 ADD_CHILD_DEFAULT_FLAGS,
10899 insert_child_above,
10904 * clutter_actor_insert_child_below:
10905 * @self: a #ClutterActor
10906 * @child: a #ClutterActor
10907 * @sibling: (allow-none): a child of @self, or %NULL
10909 * Inserts @child into the list of children of @self, below another
10910 * child of @self or, if @sibling is %NULL, below all the children
10913 * This function will acquire a reference on @child that will only
10914 * be released when calling clutter_actor_remove_child().
10916 * This function will not take into consideration the #ClutterActor:depth
10919 * This function will emit the #ClutterContainer::actor-added signal
10925 clutter_actor_insert_child_below (ClutterActor *self,
10926 ClutterActor *child,
10927 ClutterActor *sibling)
10929 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10930 g_return_if_fail (CLUTTER_IS_ACTOR (child));
10931 g_return_if_fail (self != child);
10932 g_return_if_fail (child != sibling);
10933 g_return_if_fail (child->priv->parent == NULL);
10934 g_return_if_fail (sibling == NULL ||
10935 (CLUTTER_IS_ACTOR (sibling) &&
10936 sibling->priv->parent == self));
10938 clutter_actor_add_child_internal (self, child,
10939 ADD_CHILD_DEFAULT_FLAGS,
10940 insert_child_below,
10945 * clutter_actor_set_parent:
10946 * @self: A #ClutterActor
10947 * @parent: A new #ClutterActor parent
10949 * Sets the parent of @self to @parent.
10951 * This function will result in @parent acquiring a reference on @self,
10952 * eventually by sinking its floating reference first. The reference
10953 * will be released by clutter_actor_unparent().
10955 * This function should only be called by legacy #ClutterActor<!-- -->s
10956 * implementing the #ClutterContainer interface.
10958 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
10961 clutter_actor_set_parent (ClutterActor *self,
10962 ClutterActor *parent)
10964 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10965 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
10966 g_return_if_fail (self != parent);
10967 g_return_if_fail (self->priv->parent == NULL);
10969 /* as this function will be called inside ClutterContainer::add
10970 * implementations or when building up a composite actor, we have
10971 * to preserve the old behaviour, and not create child meta or
10972 * emit the ::actor-added signal, to avoid recursion or double
10975 clutter_actor_add_child_internal (parent, self,
10976 ADD_CHILD_LEGACY_FLAGS,
10977 insert_child_at_depth,
10982 * clutter_actor_get_parent:
10983 * @self: A #ClutterActor
10985 * Retrieves the parent of @self.
10987 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
10988 * if no parent is set
10991 clutter_actor_get_parent (ClutterActor *self)
10993 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10995 return self->priv->parent;
10999 * clutter_actor_get_paint_visibility:
11000 * @self: A #ClutterActor
11002 * Retrieves the 'paint' visibility of an actor recursively checking for non
11005 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11007 * Return Value: %TRUE if the actor is visibile and will be painted.
11012 clutter_actor_get_paint_visibility (ClutterActor *actor)
11014 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11016 return CLUTTER_ACTOR_IS_MAPPED (actor);
11020 * clutter_actor_remove_child:
11021 * @self: a #ClutterActor
11022 * @child: a #ClutterActor
11024 * Removes @child from the children of @self.
11026 * This function will release the reference added by
11027 * clutter_actor_add_child(), so if you want to keep using @child
11028 * you will have to acquire a referenced on it before calling this
11031 * This function will emit the #ClutterContainer::actor-removed
11037 clutter_actor_remove_child (ClutterActor *self,
11038 ClutterActor *child)
11040 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11041 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11042 g_return_if_fail (self != child);
11043 g_return_if_fail (child->priv->parent != NULL);
11044 g_return_if_fail (child->priv->parent == self);
11046 clutter_actor_remove_child_internal (self, child,
11047 REMOVE_CHILD_DEFAULT_FLAGS);
11051 * clutter_actor_remove_all_children:
11052 * @self: a #ClutterActor
11054 * Removes all children of @self.
11056 * This function releases the reference added by inserting a child actor
11057 * in the list of children of @self.
11059 * If the reference count of a child drops to zero, the child will be
11060 * destroyed. If you want to ensure the destruction of all the children
11061 * of @self, use clutter_actor_destroy_all_children().
11066 clutter_actor_remove_all_children (ClutterActor *self)
11068 ClutterActorIter iter;
11070 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11072 if (self->priv->n_children == 0)
11075 g_object_freeze_notify (G_OBJECT (self));
11077 clutter_actor_iter_init (&iter, self);
11078 while (clutter_actor_iter_next (&iter, NULL))
11079 clutter_actor_iter_remove (&iter);
11081 g_object_thaw_notify (G_OBJECT (self));
11084 g_assert (self->priv->first_child == NULL);
11085 g_assert (self->priv->last_child == NULL);
11086 g_assert (self->priv->n_children == 0);
11090 * clutter_actor_destroy_all_children:
11091 * @self: a #ClutterActor
11093 * Destroys all children of @self.
11095 * This function releases the reference added by inserting a child
11096 * actor in the list of children of @self, and ensures that the
11097 * #ClutterActor::destroy signal is emitted on each child of the
11100 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11101 * when its reference count drops to 0; the default handler of the
11102 * #ClutterActor::destroy signal will destroy all the children of an
11103 * actor. This function ensures that all children are destroyed, instead
11104 * of just removed from @self, unlike clutter_actor_remove_all_children()
11105 * which will merely release the reference and remove each child.
11107 * Unless you acquired an additional reference on each child of @self
11108 * prior to calling clutter_actor_remove_all_children() and want to reuse
11109 * the actors, you should use clutter_actor_destroy_all_children() in
11110 * order to make sure that children are destroyed and signal handlers
11111 * are disconnected even in cases where circular references prevent this
11112 * from automatically happening through reference counting alone.
11117 clutter_actor_destroy_all_children (ClutterActor *self)
11119 ClutterActorIter iter;
11121 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11123 if (self->priv->n_children == 0)
11126 g_object_freeze_notify (G_OBJECT (self));
11128 clutter_actor_iter_init (&iter, self);
11129 while (clutter_actor_iter_next (&iter, NULL))
11130 clutter_actor_iter_destroy (&iter);
11132 g_object_thaw_notify (G_OBJECT (self));
11135 g_assert (self->priv->first_child == NULL);
11136 g_assert (self->priv->last_child == NULL);
11137 g_assert (self->priv->n_children == 0);
11140 typedef struct _InsertBetweenData {
11141 ClutterActor *prev_sibling;
11142 ClutterActor *next_sibling;
11143 } InsertBetweenData;
11146 insert_child_between (ClutterActor *self,
11147 ClutterActor *child,
11150 InsertBetweenData *data = data_;
11151 ClutterActor *prev_sibling = data->prev_sibling;
11152 ClutterActor *next_sibling = data->next_sibling;
11154 child->priv->parent = self;
11155 child->priv->prev_sibling = prev_sibling;
11156 child->priv->next_sibling = next_sibling;
11158 if (prev_sibling != NULL)
11159 prev_sibling->priv->next_sibling = child;
11161 if (next_sibling != NULL)
11162 next_sibling->priv->prev_sibling = child;
11164 if (child->priv->prev_sibling == NULL)
11165 self->priv->first_child = child;
11167 if (child->priv->next_sibling == NULL)
11168 self->priv->last_child = child;
11172 * clutter_actor_replace_child:
11173 * @self: a #ClutterActor
11174 * @old_child: the child of @self to replace
11175 * @new_child: the #ClutterActor to replace @old_child
11177 * Replaces @old_child with @new_child in the list of children of @self.
11182 clutter_actor_replace_child (ClutterActor *self,
11183 ClutterActor *old_child,
11184 ClutterActor *new_child)
11186 ClutterActor *prev_sibling, *next_sibling;
11187 InsertBetweenData clos;
11189 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11190 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11191 g_return_if_fail (old_child->priv->parent == self);
11192 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11193 g_return_if_fail (old_child != new_child);
11194 g_return_if_fail (new_child != self);
11195 g_return_if_fail (new_child->priv->parent == NULL);
11197 prev_sibling = old_child->priv->prev_sibling;
11198 next_sibling = old_child->priv->next_sibling;
11199 clutter_actor_remove_child_internal (self, old_child,
11200 REMOVE_CHILD_DEFAULT_FLAGS);
11202 clos.prev_sibling = prev_sibling;
11203 clos.next_sibling = next_sibling;
11204 clutter_actor_add_child_internal (self, new_child,
11205 ADD_CHILD_DEFAULT_FLAGS,
11206 insert_child_between,
11211 * clutter_actor_unparent:
11212 * @self: a #ClutterActor
11214 * Removes the parent of @self.
11216 * This will cause the parent of @self to release the reference
11217 * acquired when calling clutter_actor_set_parent(), so if you
11218 * want to keep @self you will have to acquire a reference of
11219 * your own, through g_object_ref().
11221 * This function should only be called by legacy #ClutterActor<!-- -->s
11222 * implementing the #ClutterContainer interface.
11226 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11229 clutter_actor_unparent (ClutterActor *self)
11231 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11233 if (self->priv->parent == NULL)
11236 clutter_actor_remove_child_internal (self->priv->parent, self,
11237 REMOVE_CHILD_LEGACY_FLAGS);
11241 * clutter_actor_reparent:
11242 * @self: a #ClutterActor
11243 * @new_parent: the new #ClutterActor parent
11245 * Resets the parent actor of @self.
11247 * This function is logically equivalent to calling clutter_actor_unparent()
11248 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11249 * ensures the child is not finalized when unparented, and emits the
11250 * #ClutterActor::parent-set signal only once.
11252 * In reality, calling this function is less useful than it sounds, as some
11253 * application code may rely on changes in the intermediate state between
11254 * removal and addition of the actor from its old parent to the @new_parent.
11255 * Thus, it is strongly encouraged to avoid using this function in application
11260 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11261 * clutter_actor_add_child() instead; remember to take a reference on
11262 * the actor being removed before calling clutter_actor_remove_child()
11263 * to avoid the reference count dropping to zero and the actor being
11267 clutter_actor_reparent (ClutterActor *self,
11268 ClutterActor *new_parent)
11270 ClutterActorPrivate *priv;
11272 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11273 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11274 g_return_if_fail (self != new_parent);
11276 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11278 g_warning ("Cannot set a parent on a toplevel actor");
11282 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11284 g_warning ("Cannot set a parent currently being destroyed");
11290 if (priv->parent != new_parent)
11292 ClutterActor *old_parent;
11294 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11296 old_parent = priv->parent;
11298 g_object_ref (self);
11300 if (old_parent != NULL)
11302 /* go through the Container implementation if this is a regular
11303 * child and not an internal one
11305 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11307 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11309 /* this will have to call unparent() */
11310 clutter_container_remove_actor (parent, self);
11313 clutter_actor_remove_child_internal (old_parent, self,
11314 REMOVE_CHILD_LEGACY_FLAGS);
11317 /* Note, will call set_parent() */
11318 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11319 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11321 clutter_actor_add_child_internal (new_parent, self,
11322 ADD_CHILD_LEGACY_FLAGS,
11323 insert_child_at_depth,
11326 /* we emit the ::parent-set signal once */
11327 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11329 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11331 /* the IN_REPARENT flag suspends state updates */
11332 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11334 g_object_unref (self);
11339 * clutter_actor_contains:
11340 * @self: A #ClutterActor
11341 * @descendant: A #ClutterActor, possibly contained in @self
11343 * Determines if @descendant is contained inside @self (either as an
11344 * immediate child, or as a deeper descendant). If @self and
11345 * @descendant point to the same actor then it will also return %TRUE.
11347 * Return value: whether @descendent is contained within @self
11352 clutter_actor_contains (ClutterActor *self,
11353 ClutterActor *descendant)
11355 ClutterActor *actor;
11357 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11358 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11360 for (actor = descendant; actor; actor = actor->priv->parent)
11368 * clutter_actor_set_child_above_sibling:
11369 * @self: a #ClutterActor
11370 * @child: a #ClutterActor child of @self
11371 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11373 * Sets @child to be above @sibling in the list of children of @self.
11375 * If @sibling is %NULL, @child will be the new last child of @self.
11377 * This function is logically equivalent to removing @child and using
11378 * clutter_actor_insert_child_above(), but it will not emit signals
11379 * or change state on @child.
11384 clutter_actor_set_child_above_sibling (ClutterActor *self,
11385 ClutterActor *child,
11386 ClutterActor *sibling)
11388 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11389 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11390 g_return_if_fail (child->priv->parent == self);
11391 g_return_if_fail (child != sibling);
11392 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11394 if (sibling != NULL)
11395 g_return_if_fail (sibling->priv->parent == self);
11397 /* we don't want to change the state of child, or emit signals, or
11398 * regenerate ChildMeta instances here, but we still want to follow
11399 * the correct sequence of steps encoded in remove_child() and
11400 * add_child(), so that correctness is ensured, and we only go
11401 * through one known code path.
11403 g_object_ref (child);
11404 clutter_actor_remove_child_internal (self, child, 0);
11405 clutter_actor_add_child_internal (self, child,
11406 ADD_CHILD_NOTIFY_FIRST_LAST,
11407 insert_child_above,
11410 clutter_actor_queue_relayout (self);
11414 * clutter_actor_set_child_below_sibling:
11415 * @self: a #ClutterActor
11416 * @child: a #ClutterActor child of @self
11417 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11419 * Sets @child to be below @sibling in the list of children of @self.
11421 * If @sibling is %NULL, @child will be the new first child of @self.
11423 * This function is logically equivalent to removing @self and using
11424 * clutter_actor_insert_child_below(), but it will not emit signals
11425 * or change state on @child.
11430 clutter_actor_set_child_below_sibling (ClutterActor *self,
11431 ClutterActor *child,
11432 ClutterActor *sibling)
11434 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11435 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11436 g_return_if_fail (child->priv->parent == self);
11437 g_return_if_fail (child != sibling);
11438 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11440 if (sibling != NULL)
11441 g_return_if_fail (sibling->priv->parent == self);
11443 /* see the comment in set_child_above_sibling() */
11444 g_object_ref (child);
11445 clutter_actor_remove_child_internal (self, child, 0);
11446 clutter_actor_add_child_internal (self, child,
11447 ADD_CHILD_NOTIFY_FIRST_LAST,
11448 insert_child_below,
11451 clutter_actor_queue_relayout (self);
11455 * clutter_actor_set_child_at_index:
11456 * @self: a #ClutterActor
11457 * @child: a #ClutterActor child of @self
11458 * @index_: the new index for @child
11460 * Changes the index of @child in the list of children of @self.
11462 * This function is logically equivalent to removing @child and
11463 * calling clutter_actor_insert_child_at_index(), but it will not
11464 * emit signals or change state on @child.
11469 clutter_actor_set_child_at_index (ClutterActor *self,
11470 ClutterActor *child,
11473 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11474 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11475 g_return_if_fail (child->priv->parent == self);
11476 g_return_if_fail (index_ <= self->priv->n_children);
11478 g_object_ref (child);
11479 clutter_actor_remove_child_internal (self, child, 0);
11480 clutter_actor_add_child_internal (self, child,
11481 ADD_CHILD_NOTIFY_FIRST_LAST,
11482 insert_child_at_index,
11483 GINT_TO_POINTER (index_));
11485 clutter_actor_queue_relayout (self);
11489 * clutter_actor_raise:
11490 * @self: A #ClutterActor
11491 * @below: (allow-none): A #ClutterActor to raise above.
11493 * Puts @self above @below.
11495 * Both actors must have the same parent, and the parent must implement
11496 * the #ClutterContainer interface
11498 * This function calls clutter_container_raise_child() internally.
11500 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11503 clutter_actor_raise (ClutterActor *self,
11504 ClutterActor *below)
11506 ClutterActor *parent;
11508 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11510 parent = clutter_actor_get_parent (self);
11511 if (parent == NULL)
11513 g_warning ("%s: Actor '%s' is not inside a container",
11515 _clutter_actor_get_debug_name (self));
11521 if (parent != clutter_actor_get_parent (below))
11523 g_warning ("%s Actor '%s' is not in the same container as "
11526 _clutter_actor_get_debug_name (self),
11527 _clutter_actor_get_debug_name (below));
11532 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11536 * clutter_actor_lower:
11537 * @self: A #ClutterActor
11538 * @above: (allow-none): A #ClutterActor to lower below
11540 * Puts @self below @above.
11542 * Both actors must have the same parent, and the parent must implement
11543 * the #ClutterContainer interface.
11545 * This function calls clutter_container_lower_child() internally.
11547 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11550 clutter_actor_lower (ClutterActor *self,
11551 ClutterActor *above)
11553 ClutterActor *parent;
11555 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11557 parent = clutter_actor_get_parent (self);
11558 if (parent == NULL)
11560 g_warning ("%s: Actor of type %s is not inside a container",
11562 _clutter_actor_get_debug_name (self));
11568 if (parent != clutter_actor_get_parent (above))
11570 g_warning ("%s: Actor '%s' is not in the same container as "
11573 _clutter_actor_get_debug_name (self),
11574 _clutter_actor_get_debug_name (above));
11579 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11583 * clutter_actor_raise_top:
11584 * @self: A #ClutterActor
11586 * Raises @self to the top.
11588 * This function calls clutter_actor_raise() internally.
11590 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11591 * a %NULL sibling, instead.
11594 clutter_actor_raise_top (ClutterActor *self)
11596 clutter_actor_raise (self, NULL);
11600 * clutter_actor_lower_bottom:
11601 * @self: A #ClutterActor
11603 * Lowers @self to the bottom.
11605 * This function calls clutter_actor_lower() internally.
11607 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11608 * a %NULL sibling, instead.
11611 clutter_actor_lower_bottom (ClutterActor *self)
11613 clutter_actor_lower (self, NULL);
11621 * clutter_actor_event:
11622 * @actor: a #ClutterActor
11623 * @event: a #ClutterEvent
11624 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11626 * This function is used to emit an event on the main stage.
11627 * You should rarely need to use this function, except for
11628 * synthetising events.
11630 * Return value: the return value from the signal emission: %TRUE
11631 * if the actor handled the event, or %FALSE if the event was
11637 clutter_actor_event (ClutterActor *actor,
11638 ClutterEvent *event,
11641 gboolean retval = FALSE;
11642 gint signal_num = -1;
11644 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11645 g_return_val_if_fail (event != NULL, FALSE);
11647 g_object_ref (actor);
11651 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11657 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11661 switch (event->type)
11663 case CLUTTER_NOTHING:
11665 case CLUTTER_BUTTON_PRESS:
11666 signal_num = BUTTON_PRESS_EVENT;
11668 case CLUTTER_BUTTON_RELEASE:
11669 signal_num = BUTTON_RELEASE_EVENT;
11671 case CLUTTER_SCROLL:
11672 signal_num = SCROLL_EVENT;
11674 case CLUTTER_KEY_PRESS:
11675 signal_num = KEY_PRESS_EVENT;
11677 case CLUTTER_KEY_RELEASE:
11678 signal_num = KEY_RELEASE_EVENT;
11680 case CLUTTER_MOTION:
11681 signal_num = MOTION_EVENT;
11683 case CLUTTER_ENTER:
11684 signal_num = ENTER_EVENT;
11686 case CLUTTER_LEAVE:
11687 signal_num = LEAVE_EVENT;
11689 case CLUTTER_DELETE:
11690 case CLUTTER_DESTROY_NOTIFY:
11691 case CLUTTER_CLIENT_MESSAGE:
11697 if (signal_num != -1)
11698 g_signal_emit (actor, actor_signals[signal_num], 0,
11703 g_object_unref (actor);
11709 * clutter_actor_set_reactive:
11710 * @actor: a #ClutterActor
11711 * @reactive: whether the actor should be reactive to events
11713 * Sets @actor as reactive. Reactive actors will receive events.
11718 clutter_actor_set_reactive (ClutterActor *actor,
11721 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11723 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11727 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11729 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11731 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11735 * clutter_actor_get_reactive:
11736 * @actor: a #ClutterActor
11738 * Checks whether @actor is marked as reactive.
11740 * Return value: %TRUE if the actor is reactive
11745 clutter_actor_get_reactive (ClutterActor *actor)
11747 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11749 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
11753 * clutter_actor_get_anchor_point:
11754 * @self: a #ClutterActor
11755 * @anchor_x: (out): return location for the X coordinate of the anchor point
11756 * @anchor_y: (out): return location for the Y coordinate of the anchor point
11758 * Gets the current anchor point of the @actor in pixels.
11763 clutter_actor_get_anchor_point (ClutterActor *self,
11767 const ClutterTransformInfo *info;
11769 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11771 info = _clutter_actor_get_transform_info_or_defaults (self);
11772 clutter_anchor_coord_get_units (self, &info->anchor,
11779 * clutter_actor_set_anchor_point:
11780 * @self: a #ClutterActor
11781 * @anchor_x: X coordinate of the anchor point
11782 * @anchor_y: Y coordinate of the anchor point
11784 * Sets an anchor point for @self. The anchor point is a point in the
11785 * coordinate space of an actor to which the actor position within its
11786 * parent is relative; the default is (0, 0), i.e. the top-left corner
11792 clutter_actor_set_anchor_point (ClutterActor *self,
11796 ClutterTransformInfo *info;
11797 ClutterActorPrivate *priv;
11798 gboolean changed = FALSE;
11799 gfloat old_anchor_x, old_anchor_y;
11802 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11804 obj = G_OBJECT (self);
11806 info = _clutter_actor_get_transform_info (self);
11808 g_object_freeze_notify (obj);
11810 clutter_anchor_coord_get_units (self, &info->anchor,
11815 if (info->anchor.is_fractional)
11816 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11818 if (old_anchor_x != anchor_x)
11820 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11824 if (old_anchor_y != anchor_y)
11826 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11830 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
11834 priv->transform_valid = FALSE;
11835 clutter_actor_queue_redraw (self);
11838 g_object_thaw_notify (obj);
11842 * clutter_actor_get_anchor_point_gravity:
11843 * @self: a #ClutterActor
11845 * Retrieves the anchor position expressed as a #ClutterGravity. If
11846 * the anchor point was specified using pixels or units this will
11847 * return %CLUTTER_GRAVITY_NONE.
11849 * Return value: the #ClutterGravity used by the anchor point
11854 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
11856 const ClutterTransformInfo *info;
11858 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
11860 info = _clutter_actor_get_transform_info_or_defaults (self);
11862 return clutter_anchor_coord_get_gravity (&info->anchor);
11866 * clutter_actor_move_anchor_point:
11867 * @self: a #ClutterActor
11868 * @anchor_x: X coordinate of the anchor point
11869 * @anchor_y: Y coordinate of the anchor point
11871 * Sets an anchor point for the actor, and adjusts the actor postion so that
11872 * the relative position of the actor toward its parent remains the same.
11877 clutter_actor_move_anchor_point (ClutterActor *self,
11881 gfloat old_anchor_x, old_anchor_y;
11882 const ClutterTransformInfo *info;
11884 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11886 info = _clutter_actor_get_transform_info (self);
11887 clutter_anchor_coord_get_units (self, &info->anchor,
11892 g_object_freeze_notify (G_OBJECT (self));
11894 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
11896 if (self->priv->position_set)
11897 clutter_actor_move_by (self,
11898 anchor_x - old_anchor_x,
11899 anchor_y - old_anchor_y);
11901 g_object_thaw_notify (G_OBJECT (self));
11905 * clutter_actor_move_anchor_point_from_gravity:
11906 * @self: a #ClutterActor
11907 * @gravity: #ClutterGravity.
11909 * Sets an anchor point on the actor based on the given gravity, adjusting the
11910 * actor postion so that its relative position within its parent remains
11913 * Since version 1.0 the anchor point will be stored as a gravity so
11914 * that if the actor changes size then the anchor point will move. For
11915 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11916 * and later double the size of the actor, the anchor point will move
11917 * to the bottom right.
11922 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
11923 ClutterGravity gravity)
11925 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
11926 const ClutterTransformInfo *info;
11927 ClutterActorPrivate *priv;
11929 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11932 info = _clutter_actor_get_transform_info (self);
11934 g_object_freeze_notify (G_OBJECT (self));
11936 clutter_anchor_coord_get_units (self, &info->anchor,
11940 clutter_actor_set_anchor_point_from_gravity (self, gravity);
11941 clutter_anchor_coord_get_units (self, &info->anchor,
11946 if (priv->position_set)
11947 clutter_actor_move_by (self,
11948 new_anchor_x - old_anchor_x,
11949 new_anchor_y - old_anchor_y);
11951 g_object_thaw_notify (G_OBJECT (self));
11955 * clutter_actor_set_anchor_point_from_gravity:
11956 * @self: a #ClutterActor
11957 * @gravity: #ClutterGravity.
11959 * Sets an anchor point on the actor, based on the given gravity (this is a
11960 * convenience function wrapping clutter_actor_set_anchor_point()).
11962 * Since version 1.0 the anchor point will be stored as a gravity so
11963 * that if the actor changes size then the anchor point will move. For
11964 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
11965 * and later double the size of the actor, the anchor point will move
11966 * to the bottom right.
11971 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
11972 ClutterGravity gravity)
11974 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11976 if (gravity == CLUTTER_GRAVITY_NONE)
11977 clutter_actor_set_anchor_point (self, 0, 0);
11980 GObject *obj = G_OBJECT (self);
11981 ClutterTransformInfo *info;
11983 g_object_freeze_notify (obj);
11985 info = _clutter_actor_get_transform_info (self);
11986 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
11988 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
11989 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
11990 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
11992 self->priv->transform_valid = FALSE;
11994 clutter_actor_queue_redraw (self);
11996 g_object_thaw_notify (obj);
12001 clutter_container_iface_init (ClutterContainerIface *iface)
12003 /* we don't override anything, as ClutterContainer already has a default
12004 * implementation that we can use, and which calls into our own API.
12019 parse_units (ClutterActor *self,
12020 ParseDimension dimension,
12023 GValue value = { 0, };
12026 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12029 json_node_get_value (node, &value);
12031 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12033 retval = (gfloat) g_value_get_int64 (&value);
12035 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12037 retval = g_value_get_double (&value);
12039 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12041 ClutterUnits units;
12044 res = clutter_units_from_string (&units, g_value_get_string (&value));
12046 retval = clutter_units_to_pixels (&units);
12049 g_warning ("Invalid value '%s': integers, strings or floating point "
12050 "values can be used for the x, y, width and height "
12051 "properties. Valid modifiers for strings are 'px', 'mm', "
12053 g_value_get_string (&value));
12059 g_warning ("Invalid value of type '%s': integers, strings of floating "
12060 "point values can be used for the x, y, width, height "
12061 "anchor-x and anchor-y properties.",
12062 g_type_name (G_VALUE_TYPE (&value)));
12065 g_value_unset (&value);
12071 ClutterRotateAxis axis;
12080 static inline gboolean
12081 parse_rotation_array (ClutterActor *actor,
12083 RotationInfo *info)
12087 if (json_array_get_length (array) != 2)
12091 element = json_array_get_element (array, 0);
12092 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12093 info->angle = json_node_get_double (element);
12098 element = json_array_get_element (array, 1);
12099 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12101 JsonArray *center = json_node_get_array (element);
12103 if (json_array_get_length (center) != 2)
12106 switch (info->axis)
12108 case CLUTTER_X_AXIS:
12109 info->center_y = parse_units (actor, PARSE_Y,
12110 json_array_get_element (center, 0));
12111 info->center_z = parse_units (actor, PARSE_Y,
12112 json_array_get_element (center, 1));
12115 case CLUTTER_Y_AXIS:
12116 info->center_x = parse_units (actor, PARSE_X,
12117 json_array_get_element (center, 0));
12118 info->center_z = parse_units (actor, PARSE_X,
12119 json_array_get_element (center, 1));
12122 case CLUTTER_Z_AXIS:
12123 info->center_x = parse_units (actor, PARSE_X,
12124 json_array_get_element (center, 0));
12125 info->center_y = parse_units (actor, PARSE_Y,
12126 json_array_get_element (center, 1));
12135 parse_rotation (ClutterActor *actor,
12137 RotationInfo *info)
12141 gboolean retval = FALSE;
12143 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12145 g_warning ("Invalid node of type '%s' found, expecting an array",
12146 json_node_type_name (node));
12150 array = json_node_get_array (node);
12151 len = json_array_get_length (array);
12153 for (i = 0; i < len; i++)
12155 JsonNode *element = json_array_get_element (array, i);
12156 JsonObject *object;
12159 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12161 g_warning ("Invalid node of type '%s' found, expecting an object",
12162 json_node_type_name (element));
12166 object = json_node_get_object (element);
12168 if (json_object_has_member (object, "x-axis"))
12170 member = json_object_get_member (object, "x-axis");
12172 info->axis = CLUTTER_X_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),
12186 else if (json_object_has_member (object, "y-axis"))
12188 member = json_object_get_member (object, "y-axis");
12190 info->axis = CLUTTER_Y_AXIS;
12192 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12194 info->angle = json_node_get_double (member);
12197 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12198 retval = parse_rotation_array (actor,
12199 json_node_get_array (member),
12204 else if (json_object_has_member (object, "z-axis"))
12206 member = json_object_get_member (object, "z-axis");
12208 info->axis = CLUTTER_Z_AXIS;
12210 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12212 info->angle = json_node_get_double (member);
12215 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12216 retval = parse_rotation_array (actor,
12217 json_node_get_array (member),
12228 parse_actor_metas (ClutterScript *script,
12229 ClutterActor *actor,
12232 GList *elements, *l;
12233 GSList *retval = NULL;
12235 if (!JSON_NODE_HOLDS_ARRAY (node))
12238 elements = json_array_get_elements (json_node_get_array (node));
12240 for (l = elements; l != NULL; l = l->next)
12242 JsonNode *element = l->data;
12243 const gchar *id_ = _clutter_script_get_id_from_node (element);
12246 if (id_ == NULL || *id_ == '\0')
12249 meta = clutter_script_get_object (script, id_);
12253 retval = g_slist_prepend (retval, meta);
12256 g_list_free (elements);
12258 return g_slist_reverse (retval);
12262 parse_behaviours (ClutterScript *script,
12263 ClutterActor *actor,
12266 GList *elements, *l;
12267 GSList *retval = NULL;
12269 if (!JSON_NODE_HOLDS_ARRAY (node))
12272 elements = json_array_get_elements (json_node_get_array (node));
12274 for (l = elements; l != NULL; l = l->next)
12276 JsonNode *element = l->data;
12277 const gchar *id_ = _clutter_script_get_id_from_node (element);
12278 GObject *behaviour;
12280 if (id_ == NULL || *id_ == '\0')
12283 behaviour = clutter_script_get_object (script, id_);
12284 if (behaviour == NULL)
12287 retval = g_slist_prepend (retval, behaviour);
12290 g_list_free (elements);
12292 return g_slist_reverse (retval);
12296 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12297 ClutterScript *script,
12302 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12303 gboolean retval = FALSE;
12305 if ((name[0] == 'x' && name[1] == '\0') ||
12306 (name[0] == 'y' && name[1] == '\0') ||
12307 (strcmp (name, "width") == 0) ||
12308 (strcmp (name, "height") == 0) ||
12309 (strcmp (name, "anchor_x") == 0) ||
12310 (strcmp (name, "anchor_y") == 0))
12312 ParseDimension dimension;
12315 if (name[0] == 'x')
12316 dimension = PARSE_X;
12317 else if (name[0] == 'y')
12318 dimension = PARSE_Y;
12319 else if (name[0] == 'w')
12320 dimension = PARSE_WIDTH;
12321 else if (name[0] == 'h')
12322 dimension = PARSE_HEIGHT;
12323 else if (name[0] == 'a' && name[7] == 'x')
12324 dimension = PARSE_ANCHOR_X;
12325 else if (name[0] == 'a' && name[7] == 'y')
12326 dimension = PARSE_ANCHOR_Y;
12330 units = parse_units (actor, dimension, node);
12332 /* convert back to pixels: all properties are pixel-based */
12333 g_value_init (value, G_TYPE_FLOAT);
12334 g_value_set_float (value, units);
12338 else if (strcmp (name, "rotation") == 0)
12340 RotationInfo *info;
12342 info = g_slice_new0 (RotationInfo);
12343 retval = parse_rotation (actor, node, info);
12347 g_value_init (value, G_TYPE_POINTER);
12348 g_value_set_pointer (value, info);
12351 g_slice_free (RotationInfo, info);
12353 else if (strcmp (name, "behaviours") == 0)
12357 #ifdef CLUTTER_ENABLE_DEBUG
12358 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12359 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12360 "and it should not be used in newly "
12361 "written ClutterScript definitions.");
12364 l = parse_behaviours (script, actor, node);
12366 g_value_init (value, G_TYPE_POINTER);
12367 g_value_set_pointer (value, l);
12371 else if (strcmp (name, "actions") == 0 ||
12372 strcmp (name, "constraints") == 0 ||
12373 strcmp (name, "effects") == 0)
12377 l = parse_actor_metas (script, actor, node);
12379 g_value_init (value, G_TYPE_POINTER);
12380 g_value_set_pointer (value, l);
12389 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12390 ClutterScript *script,
12392 const GValue *value)
12394 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12396 #ifdef CLUTTER_ENABLE_DEBUG
12397 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12399 gchar *tmp = g_strdup_value_contents (value);
12401 CLUTTER_NOTE (SCRIPT,
12402 "in ClutterActor::set_custom_property('%s') = %s",
12408 #endif /* CLUTTER_ENABLE_DEBUG */
12410 if (strcmp (name, "rotation") == 0)
12412 RotationInfo *info;
12414 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12417 info = g_value_get_pointer (value);
12419 clutter_actor_set_rotation (actor,
12420 info->axis, info->angle,
12425 g_slice_free (RotationInfo, info);
12430 if (strcmp (name, "behaviours") == 0)
12432 GSList *behaviours, *l;
12434 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12437 behaviours = g_value_get_pointer (value);
12438 for (l = behaviours; l != NULL; l = l->next)
12440 ClutterBehaviour *behaviour = l->data;
12442 clutter_behaviour_apply (behaviour, actor);
12445 g_slist_free (behaviours);
12450 if (strcmp (name, "actions") == 0 ||
12451 strcmp (name, "constraints") == 0 ||
12452 strcmp (name, "effects") == 0)
12456 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12459 metas = g_value_get_pointer (value);
12460 for (l = metas; l != NULL; l = l->next)
12462 if (name[0] == 'a')
12463 clutter_actor_add_action (actor, l->data);
12465 if (name[0] == 'c')
12466 clutter_actor_add_constraint (actor, l->data);
12468 if (name[0] == 'e')
12469 clutter_actor_add_effect (actor, l->data);
12472 g_slist_free (metas);
12477 g_object_set_property (G_OBJECT (scriptable), name, value);
12481 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12483 iface->parse_custom_node = clutter_actor_parse_custom_node;
12484 iface->set_custom_property = clutter_actor_set_custom_property;
12487 static ClutterActorMeta *
12488 get_meta_from_animation_property (ClutterActor *actor,
12492 ClutterActorPrivate *priv = actor->priv;
12493 ClutterActorMeta *meta = NULL;
12496 /* if this is not a special property, fall through */
12497 if (name[0] != '@')
12500 /* detect the properties named using the following spec:
12502 * @<section>.<meta-name>.<property-name>
12504 * where <section> can be one of the following:
12510 * and <meta-name> is the name set on a specific ActorMeta
12513 tokens = g_strsplit (name + 1, ".", -1);
12514 if (tokens == NULL || g_strv_length (tokens) != 3)
12516 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12518 g_strfreev (tokens);
12522 if (strcmp (tokens[0], "actions") == 0)
12523 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12525 if (strcmp (tokens[0], "constraints") == 0)
12526 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12528 if (strcmp (tokens[0], "effects") == 0)
12529 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12531 if (name_p != NULL)
12532 *name_p = g_strdup (tokens[2]);
12534 CLUTTER_NOTE (ANIMATION,
12535 "Looking for property '%s' of object '%s' in section '%s'",
12540 g_strfreev (tokens);
12545 static GParamSpec *
12546 clutter_actor_find_property (ClutterAnimatable *animatable,
12547 const gchar *property_name)
12549 ClutterActorMeta *meta = NULL;
12550 GObjectClass *klass = NULL;
12551 GParamSpec *pspec = NULL;
12552 gchar *p_name = NULL;
12554 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12560 klass = G_OBJECT_GET_CLASS (meta);
12562 pspec = g_object_class_find_property (klass, p_name);
12566 klass = G_OBJECT_GET_CLASS (animatable);
12568 pspec = g_object_class_find_property (klass, property_name);
12577 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12578 const gchar *property_name,
12581 ClutterActorMeta *meta = NULL;
12582 gchar *p_name = NULL;
12584 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12589 g_object_get_property (G_OBJECT (meta), p_name, initial);
12591 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12597 * clutter_actor_set_animatable_property:
12598 * @actor: a #ClutterActor
12599 * @prop_id: the paramspec id
12600 * @value: the value to set
12601 * @pspec: the paramspec
12603 * Sets values of animatable properties.
12605 * This is a variant of clutter_actor_set_property() that gets called
12606 * by the #ClutterAnimatable implementation of #ClutterActor for the
12607 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12610 * Unlike the implementation of #GObjectClass.set_property(), this
12611 * function will not update the interval if a transition involving an
12612 * animatable property is in progress - this avoids cycles with the
12613 * transition API calling the public API.
12616 clutter_actor_set_animatable_property (ClutterActor *actor,
12618 const GValue *value,
12624 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12628 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12632 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12636 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12640 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12644 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12647 case PROP_BACKGROUND_COLOR:
12648 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12652 clutter_actor_set_scale_factor_internal (actor,
12653 g_value_get_double (value),
12658 clutter_actor_set_scale_factor_internal (actor,
12659 g_value_get_double (value),
12663 case PROP_ROTATION_ANGLE_X:
12664 clutter_actor_set_rotation_angle_internal (actor,
12666 g_value_get_double (value));
12669 case PROP_ROTATION_ANGLE_Y:
12670 clutter_actor_set_rotation_angle_internal (actor,
12672 g_value_get_double (value));
12675 case PROP_ROTATION_ANGLE_Z:
12676 clutter_actor_set_rotation_angle_internal (actor,
12678 g_value_get_double (value));
12682 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12688 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12689 const gchar *property_name,
12690 const GValue *final)
12692 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12693 ClutterActorMeta *meta = NULL;
12694 gchar *p_name = NULL;
12696 meta = get_meta_from_animation_property (actor,
12700 g_object_set_property (G_OBJECT (meta), p_name, final);
12703 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12706 pspec = g_object_class_find_property (obj_class, property_name);
12708 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12710 /* XXX - I'm going to the special hell for this */
12711 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12714 g_object_set_property (G_OBJECT (animatable), property_name, final);
12721 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12723 iface->find_property = clutter_actor_find_property;
12724 iface->get_initial_state = clutter_actor_get_initial_state;
12725 iface->set_final_state = clutter_actor_set_final_state;
12729 * clutter_actor_transform_stage_point:
12730 * @self: A #ClutterActor
12731 * @x: (in): x screen coordinate of the point to unproject
12732 * @y: (in): y screen coordinate of the point to unproject
12733 * @x_out: (out): return location for the unprojected x coordinance
12734 * @y_out: (out): return location for the unprojected y coordinance
12736 * This function translates screen coordinates (@x, @y) to
12737 * coordinates relative to the actor. For example, it can be used to translate
12738 * screen events from global screen coordinates into actor-local coordinates.
12740 * The conversion can fail, notably if the transform stack results in the
12741 * actor being projected on the screen as a mere line.
12743 * The conversion should not be expected to be pixel-perfect due to the
12744 * nature of the operation. In general the error grows when the skewing
12745 * of the actor rectangle on screen increases.
12747 * <note><para>This function can be computationally intensive.</para></note>
12749 * <note><para>This function only works when the allocation is up-to-date,
12750 * i.e. inside of paint().</para></note>
12752 * Return value: %TRUE if conversion was successful.
12757 clutter_actor_transform_stage_point (ClutterActor *self,
12763 ClutterVertex v[4];
12766 int du, dv, xi, yi;
12768 float xf, yf, wf, det;
12769 ClutterActorPrivate *priv;
12771 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12775 /* This implementation is based on the quad -> quad projection algorithm
12776 * described by Paul Heckbert in:
12778 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
12780 * and the sample implementation at:
12782 * http://www.cs.cmu.edu/~ph/src/texfund/
12784 * Our texture is a rectangle with origin [0, 0], so we are mapping from
12785 * quad to rectangle only, which significantly simplifies things; the
12786 * function calls have been unrolled, and most of the math is done in fixed
12790 clutter_actor_get_abs_allocation_vertices (self, v);
12792 /* Keeping these as ints simplifies the multiplication (no significant
12793 * loss of precision here).
12795 du = (int) (priv->allocation.x2 - priv->allocation.x1);
12796 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
12801 #define UX2FP(x) (x)
12802 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
12804 /* First, find mapping from unit uv square to xy quadrilateral; this
12805 * equivalent to the pmap_square_quad() functions in the sample
12806 * implementation, which we can simplify, since our target is always
12809 px = v[0].x - v[1].x + v[3].x - v[2].x;
12810 py = v[0].y - v[1].y + v[3].y - v[2].y;
12814 /* affine transform */
12815 RQ[0][0] = UX2FP (v[1].x - v[0].x);
12816 RQ[1][0] = UX2FP (v[3].x - v[1].x);
12817 RQ[2][0] = UX2FP (v[0].x);
12818 RQ[0][1] = UX2FP (v[1].y - v[0].y);
12819 RQ[1][1] = UX2FP (v[3].y - v[1].y);
12820 RQ[2][1] = UX2FP (v[0].y);
12827 /* projective transform */
12828 double dx1, dx2, dy1, dy2, del;
12830 dx1 = UX2FP (v[1].x - v[3].x);
12831 dx2 = UX2FP (v[2].x - v[3].x);
12832 dy1 = UX2FP (v[1].y - v[3].y);
12833 dy2 = UX2FP (v[2].y - v[3].y);
12835 del = DET2FP (dx1, dx2, dy1, dy2);
12840 * The division here needs to be done in floating point for
12841 * precisions reasons.
12843 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
12844 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12845 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
12847 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
12848 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
12849 RQ[2][0] = UX2FP (v[0].x);
12850 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
12851 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
12852 RQ[2][1] = UX2FP (v[0].y);
12856 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
12857 * square. Since our rectangle is based at 0,0 we only need to scale.
12867 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
12870 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
12871 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
12872 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
12873 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
12874 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
12875 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
12876 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
12877 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
12878 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
12881 * Check the resulting matrix is OK.
12883 det = (RQ[0][0] * ST[0][0])
12884 + (RQ[0][1] * ST[0][1])
12885 + (RQ[0][2] * ST[0][2]);
12890 * Now transform our point with the ST matrix; the notional w
12891 * coordinate is 1, hence the last part is simply added.
12896 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
12897 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
12898 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
12916 static ClutterGeometry*
12917 clutter_geometry_copy (const ClutterGeometry *geometry)
12919 return g_slice_dup (ClutterGeometry, geometry);
12923 clutter_geometry_free (ClutterGeometry *geometry)
12925 if (G_LIKELY (geometry != NULL))
12926 g_slice_free (ClutterGeometry, geometry);
12930 * clutter_geometry_union:
12931 * @geometry_a: a #ClutterGeometry
12932 * @geometry_b: another #ClutterGeometry
12933 * @result: (out): location to store the result
12935 * Find the union of two rectangles represented as #ClutterGeometry.
12940 clutter_geometry_union (const ClutterGeometry *geometry_a,
12941 const ClutterGeometry *geometry_b,
12942 ClutterGeometry *result)
12944 /* We don't try to handle rectangles that can't be represented
12945 * as a signed integer box */
12946 gint x_1 = MIN (geometry_a->x, geometry_b->x);
12947 gint y_1 = MIN (geometry_a->y, geometry_b->y);
12948 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
12949 geometry_b->x + (gint)geometry_b->width);
12950 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
12951 geometry_b->y + (gint)geometry_b->height);
12954 result->width = x_2 - x_1;
12955 result->height = y_2 - y_1;
12959 * clutter_geometry_intersects:
12960 * @geometry0: The first geometry to test
12961 * @geometry1: The second geometry to test
12963 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
12964 * they do else %FALSE.
12966 * Return value: %TRUE of @geometry0 and geometry1 intersect else
12972 clutter_geometry_intersects (const ClutterGeometry *geometry0,
12973 const ClutterGeometry *geometry1)
12975 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
12976 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
12977 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
12978 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
12985 clutter_geometry_progress (const GValue *a,
12990 const ClutterGeometry *a_geom = g_value_get_boxed (a);
12991 const ClutterGeometry *b_geom = g_value_get_boxed (b);
12992 ClutterGeometry res = { 0, };
12993 gint a_width = a_geom->width;
12994 gint b_width = b_geom->width;
12995 gint a_height = a_geom->height;
12996 gint b_height = b_geom->height;
12998 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
12999 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13001 res.width = a_width + (b_width - a_width) * progress;
13002 res.height = a_height + (b_height - a_height) * progress;
13004 g_value_set_boxed (retval, &res);
13009 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13010 clutter_geometry_copy,
13011 clutter_geometry_free,
13012 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13019 * clutter_vertex_new:
13024 * Creates a new #ClutterVertex for the point in 3D space
13025 * identified by the 3 coordinates @x, @y, @z
13027 * Return value: the newly allocate #ClutterVertex. Use
13028 * clutter_vertex_free() to free the resources
13033 clutter_vertex_new (gfloat x,
13037 ClutterVertex *vertex;
13039 vertex = g_slice_new (ClutterVertex);
13048 * clutter_vertex_copy:
13049 * @vertex: a #ClutterVertex
13053 * Return value: a newly allocated copy of #ClutterVertex. Use
13054 * clutter_vertex_free() to free the allocated resources
13059 clutter_vertex_copy (const ClutterVertex *vertex)
13061 if (G_LIKELY (vertex != NULL))
13062 return g_slice_dup (ClutterVertex, vertex);
13068 * clutter_vertex_free:
13069 * @vertex: a #ClutterVertex
13071 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13076 clutter_vertex_free (ClutterVertex *vertex)
13078 if (G_UNLIKELY (vertex != NULL))
13079 g_slice_free (ClutterVertex, vertex);
13083 * clutter_vertex_equal:
13084 * @vertex_a: a #ClutterVertex
13085 * @vertex_b: a #ClutterVertex
13087 * Compares @vertex_a and @vertex_b for equality
13089 * Return value: %TRUE if the passed #ClutterVertex are equal
13094 clutter_vertex_equal (const ClutterVertex *vertex_a,
13095 const ClutterVertex *vertex_b)
13097 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13099 if (vertex_a == vertex_b)
13102 return vertex_a->x == vertex_b->x &&
13103 vertex_a->y == vertex_b->y &&
13104 vertex_a->z == vertex_b->z;
13108 clutter_vertex_progress (const GValue *a,
13113 const ClutterVertex *av = g_value_get_boxed (a);
13114 const ClutterVertex *bv = g_value_get_boxed (b);
13115 ClutterVertex res = { 0, };
13117 res.x = av->x + (bv->x - av->x) * progress;
13118 res.y = av->y + (bv->y - av->y) * progress;
13119 res.z = av->z + (bv->z - av->z) * progress;
13121 g_value_set_boxed (retval, &res);
13126 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13127 clutter_vertex_copy,
13128 clutter_vertex_free,
13129 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13132 * clutter_actor_is_rotated:
13133 * @self: a #ClutterActor
13135 * Checks whether any rotation is applied to the actor.
13137 * Return value: %TRUE if the actor is rotated.
13142 clutter_actor_is_rotated (ClutterActor *self)
13144 const ClutterTransformInfo *info;
13146 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13148 info = _clutter_actor_get_transform_info_or_defaults (self);
13150 if (info->rx_angle || info->ry_angle || info->rz_angle)
13157 * clutter_actor_is_scaled:
13158 * @self: a #ClutterActor
13160 * Checks whether the actor is scaled in either dimension.
13162 * Return value: %TRUE if the actor is scaled.
13167 clutter_actor_is_scaled (ClutterActor *self)
13169 const ClutterTransformInfo *info;
13171 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13173 info = _clutter_actor_get_transform_info_or_defaults (self);
13175 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13182 _clutter_actor_get_stage_internal (ClutterActor *actor)
13184 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13185 actor = actor->priv->parent;
13191 * clutter_actor_get_stage:
13192 * @actor: a #ClutterActor
13194 * Retrieves the #ClutterStage where @actor is contained.
13196 * Return value: (transfer none) (type Clutter.Stage): the stage
13197 * containing the actor, or %NULL
13202 clutter_actor_get_stage (ClutterActor *actor)
13204 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13206 return _clutter_actor_get_stage_internal (actor);
13210 * clutter_actor_allocate_available_size:
13211 * @self: a #ClutterActor
13212 * @x: the actor's X coordinate
13213 * @y: the actor's Y coordinate
13214 * @available_width: the maximum available width, or -1 to use the
13215 * actor's natural width
13216 * @available_height: the maximum available height, or -1 to use the
13217 * actor's natural height
13218 * @flags: flags controlling the allocation
13220 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13221 * preferred size, but limiting it to the maximum available width
13222 * and height provided.
13224 * This function will do the right thing when dealing with the
13225 * actor's request mode.
13227 * The implementation of this function is equivalent to:
13230 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13232 * clutter_actor_get_preferred_width (self, available_height,
13234 * &natural_width);
13235 * width = CLAMP (natural_width, min_width, available_width);
13237 * clutter_actor_get_preferred_height (self, width,
13239 * &natural_height);
13240 * height = CLAMP (natural_height, min_height, available_height);
13244 * clutter_actor_get_preferred_height (self, available_width,
13246 * &natural_height);
13247 * height = CLAMP (natural_height, min_height, available_height);
13249 * clutter_actor_get_preferred_width (self, height,
13251 * &natural_width);
13252 * width = CLAMP (natural_width, min_width, available_width);
13255 * box.x1 = x; box.y1 = y;
13256 * box.x2 = box.x1 + available_width;
13257 * box.y2 = box.y1 + available_height;
13258 * clutter_actor_allocate (self, &box, flags);
13261 * This function can be used by fluid layout managers to allocate
13262 * an actor's preferred size without making it bigger than the area
13263 * available for the container.
13268 clutter_actor_allocate_available_size (ClutterActor *self,
13271 gfloat available_width,
13272 gfloat available_height,
13273 ClutterAllocationFlags flags)
13275 ClutterActorPrivate *priv;
13276 gfloat width, height;
13277 gfloat min_width, min_height;
13278 gfloat natural_width, natural_height;
13279 ClutterActorBox box;
13281 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13285 width = height = 0.0;
13287 switch (priv->request_mode)
13289 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13290 clutter_actor_get_preferred_width (self, available_height,
13293 width = CLAMP (natural_width, min_width, available_width);
13295 clutter_actor_get_preferred_height (self, width,
13298 height = CLAMP (natural_height, min_height, available_height);
13301 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13302 clutter_actor_get_preferred_height (self, available_width,
13305 height = CLAMP (natural_height, min_height, available_height);
13307 clutter_actor_get_preferred_width (self, height,
13310 width = CLAMP (natural_width, min_width, available_width);
13317 box.x2 = box.x1 + width;
13318 box.y2 = box.y1 + height;
13319 clutter_actor_allocate (self, &box, flags);
13323 * clutter_actor_allocate_preferred_size:
13324 * @self: a #ClutterActor
13325 * @flags: flags controlling the allocation
13327 * Allocates the natural size of @self.
13329 * This function is a utility call for #ClutterActor implementations
13330 * that allocates the actor's preferred natural size. It can be used
13331 * by fixed layout managers (like #ClutterGroup or so called
13332 * 'composite actors') inside the ClutterActor::allocate
13333 * implementation to give each child exactly how much space it
13336 * This function is not meant to be used by applications. It is also
13337 * not meant to be used outside the implementation of the
13338 * ClutterActor::allocate virtual function.
13343 clutter_actor_allocate_preferred_size (ClutterActor *self,
13344 ClutterAllocationFlags flags)
13346 gfloat actor_x, actor_y;
13347 gfloat natural_width, natural_height;
13348 ClutterActorBox actor_box;
13350 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13352 actor_x = clutter_actor_get_x (self);
13353 actor_y = clutter_actor_get_y (self);
13355 clutter_actor_get_preferred_size (self,
13360 actor_box.x1 = actor_x;
13361 actor_box.y1 = actor_y;
13362 actor_box.x2 = actor_box.x1 + natural_width;
13363 actor_box.y2 = actor_box.y1 + natural_height;
13365 clutter_actor_allocate (self, &actor_box, flags);
13369 * clutter_actor_allocate_align_fill:
13370 * @self: a #ClutterActor
13371 * @box: a #ClutterActorBox, containing the available width and height
13372 * @x_align: the horizontal alignment, between 0 and 1
13373 * @y_align: the vertical alignment, between 0 and 1
13374 * @x_fill: whether the actor should fill horizontally
13375 * @y_fill: whether the actor should fill vertically
13376 * @flags: allocation flags to be passed to clutter_actor_allocate()
13378 * Allocates @self by taking into consideration the available allocation
13379 * area; an alignment factor on either axis; and whether the actor should
13380 * fill the allocation on either axis.
13382 * The @box should contain the available allocation width and height;
13383 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13384 * allocation will be offset by their value.
13386 * This function takes into consideration the geometry request specified by
13387 * the #ClutterActor:request-mode property, and the text direction.
13389 * This function is useful for fluid layout managers, like #ClutterBinLayout
13390 * or #ClutterTableLayout
13395 clutter_actor_allocate_align_fill (ClutterActor *self,
13396 const ClutterActorBox *box,
13401 ClutterAllocationFlags flags)
13403 ClutterActorPrivate *priv;
13404 ClutterActorBox allocation = { 0, };
13405 gfloat x_offset, y_offset;
13406 gfloat available_width, available_height;
13407 gfloat child_width, child_height;
13409 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13410 g_return_if_fail (box != NULL);
13411 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13412 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13416 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13417 clutter_actor_box_get_size (box, &available_width, &available_height);
13419 if (available_width < 0)
13420 available_width = 0;
13422 if (available_height < 0)
13423 available_height = 0;
13427 allocation.x1 = x_offset;
13428 allocation.x2 = allocation.x1 + available_width;
13433 allocation.y1 = y_offset;
13434 allocation.y2 = allocation.y1 + available_height;
13437 /* if we are filling horizontally and vertically then we're done */
13438 if (x_fill && y_fill)
13441 child_width = child_height = 0.0f;
13443 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13445 gfloat min_width, natural_width;
13446 gfloat min_height, natural_height;
13448 clutter_actor_get_preferred_width (self, available_height,
13452 child_width = CLAMP (natural_width, min_width, available_width);
13456 clutter_actor_get_preferred_height (self, child_width,
13460 child_height = CLAMP (natural_height, min_height, available_height);
13465 gfloat min_width, natural_width;
13466 gfloat min_height, natural_height;
13468 clutter_actor_get_preferred_height (self, available_width,
13472 child_height = CLAMP (natural_height, min_height, available_height);
13476 clutter_actor_get_preferred_width (self, child_height,
13480 child_width = CLAMP (natural_width, min_width, available_width);
13484 /* invert the horizontal alignment for RTL languages */
13485 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13486 x_align = 1.0 - x_align;
13490 allocation.x1 = x_offset
13491 + ((available_width - child_width) * x_align);
13492 allocation.x2 = allocation.x1 + child_width;
13497 allocation.y1 = y_offset
13498 + ((available_height - child_height) * y_align);
13499 allocation.y2 = allocation.y1 + child_height;
13503 clutter_actor_box_clamp_to_pixel (&allocation);
13504 clutter_actor_allocate (self, &allocation, flags);
13508 * clutter_actor_grab_key_focus:
13509 * @self: a #ClutterActor
13511 * Sets the key focus of the #ClutterStage including @self
13512 * to this #ClutterActor.
13517 clutter_actor_grab_key_focus (ClutterActor *self)
13519 ClutterActor *stage;
13521 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13523 stage = _clutter_actor_get_stage_internal (self);
13525 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13529 * clutter_actor_get_pango_context:
13530 * @self: a #ClutterActor
13532 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13533 * is already configured using the appropriate font map, resolution
13534 * and font options.
13536 * Unlike clutter_actor_create_pango_context(), this context is owend
13537 * by the #ClutterActor and it will be updated each time the options
13538 * stored by the #ClutterBackend change.
13540 * You can use the returned #PangoContext to create a #PangoLayout
13541 * and render text using cogl_pango_render_layout() to reuse the
13542 * glyphs cache also used by Clutter.
13544 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13545 * The returned #PangoContext is owned by the actor and should not be
13546 * unreferenced by the application code
13551 clutter_actor_get_pango_context (ClutterActor *self)
13553 ClutterActorPrivate *priv;
13555 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13559 if (priv->pango_context != NULL)
13560 return priv->pango_context;
13562 priv->pango_context = _clutter_context_get_pango_context ();
13563 g_object_ref (priv->pango_context);
13565 return priv->pango_context;
13569 * clutter_actor_create_pango_context:
13570 * @self: a #ClutterActor
13572 * Creates a #PangoContext for the given actor. The #PangoContext
13573 * is already configured using the appropriate font map, resolution
13574 * and font options.
13576 * See also clutter_actor_get_pango_context().
13578 * Return value: (transfer full): the newly created #PangoContext.
13579 * Use g_object_unref() on the returned value to deallocate its
13585 clutter_actor_create_pango_context (ClutterActor *self)
13587 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13589 return _clutter_context_create_pango_context ();
13593 * clutter_actor_create_pango_layout:
13594 * @self: a #ClutterActor
13595 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13597 * Creates a new #PangoLayout from the same #PangoContext used
13598 * by the #ClutterActor. The #PangoLayout is already configured
13599 * with the font map, resolution and font options, and the
13602 * If you want to keep around a #PangoLayout created by this
13603 * function you will have to connect to the #ClutterBackend::font-changed
13604 * and #ClutterBackend::resolution-changed signals, and call
13605 * pango_layout_context_changed() in response to them.
13607 * Return value: (transfer full): the newly created #PangoLayout.
13608 * Use g_object_unref() when done
13613 clutter_actor_create_pango_layout (ClutterActor *self,
13616 PangoContext *context;
13617 PangoLayout *layout;
13619 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13621 context = clutter_actor_get_pango_context (self);
13622 layout = pango_layout_new (context);
13625 pango_layout_set_text (layout, text, -1);
13630 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13631 * ClutterOffscreenEffect.
13634 _clutter_actor_set_opacity_override (ClutterActor *self,
13637 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13639 self->priv->opacity_override = opacity;
13643 _clutter_actor_get_opacity_override (ClutterActor *self)
13645 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13647 return self->priv->opacity_override;
13650 /* Allows you to disable applying the actors model view transform during
13651 * a paint. Used by ClutterClone. */
13653 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13656 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13658 self->priv->enable_model_view_transform = enable;
13662 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13665 ClutterActorPrivate *priv;
13667 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13671 priv->enable_paint_unmapped = enable;
13673 if (priv->enable_paint_unmapped)
13675 /* Make sure that the parents of the widget are realized first;
13676 * otherwise checks in clutter_actor_update_map_state() will
13679 clutter_actor_realize (self);
13681 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13685 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13690 clutter_anchor_coord_get_units (ClutterActor *self,
13691 const AnchorCoord *coord,
13696 if (coord->is_fractional)
13698 gfloat actor_width, actor_height;
13700 clutter_actor_get_size (self, &actor_width, &actor_height);
13703 *x = actor_width * coord->v.fraction.x;
13706 *y = actor_height * coord->v.fraction.y;
13714 *x = coord->v.units.x;
13717 *y = coord->v.units.y;
13720 *z = coord->v.units.z;
13725 clutter_anchor_coord_set_units (AnchorCoord *coord,
13730 coord->is_fractional = FALSE;
13731 coord->v.units.x = x;
13732 coord->v.units.y = y;
13733 coord->v.units.z = z;
13736 static ClutterGravity
13737 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13739 if (coord->is_fractional)
13741 if (coord->v.fraction.x == 0.0)
13743 if (coord->v.fraction.y == 0.0)
13744 return CLUTTER_GRAVITY_NORTH_WEST;
13745 else if (coord->v.fraction.y == 0.5)
13746 return CLUTTER_GRAVITY_WEST;
13747 else if (coord->v.fraction.y == 1.0)
13748 return CLUTTER_GRAVITY_SOUTH_WEST;
13750 return CLUTTER_GRAVITY_NONE;
13752 else if (coord->v.fraction.x == 0.5)
13754 if (coord->v.fraction.y == 0.0)
13755 return CLUTTER_GRAVITY_NORTH;
13756 else if (coord->v.fraction.y == 0.5)
13757 return CLUTTER_GRAVITY_CENTER;
13758 else if (coord->v.fraction.y == 1.0)
13759 return CLUTTER_GRAVITY_SOUTH;
13761 return CLUTTER_GRAVITY_NONE;
13763 else if (coord->v.fraction.x == 1.0)
13765 if (coord->v.fraction.y == 0.0)
13766 return CLUTTER_GRAVITY_NORTH_EAST;
13767 else if (coord->v.fraction.y == 0.5)
13768 return CLUTTER_GRAVITY_EAST;
13769 else if (coord->v.fraction.y == 1.0)
13770 return CLUTTER_GRAVITY_SOUTH_EAST;
13772 return CLUTTER_GRAVITY_NONE;
13775 return CLUTTER_GRAVITY_NONE;
13778 return CLUTTER_GRAVITY_NONE;
13782 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
13783 ClutterGravity gravity)
13787 case CLUTTER_GRAVITY_NORTH:
13788 coord->v.fraction.x = 0.5;
13789 coord->v.fraction.y = 0.0;
13792 case CLUTTER_GRAVITY_NORTH_EAST:
13793 coord->v.fraction.x = 1.0;
13794 coord->v.fraction.y = 0.0;
13797 case CLUTTER_GRAVITY_EAST:
13798 coord->v.fraction.x = 1.0;
13799 coord->v.fraction.y = 0.5;
13802 case CLUTTER_GRAVITY_SOUTH_EAST:
13803 coord->v.fraction.x = 1.0;
13804 coord->v.fraction.y = 1.0;
13807 case CLUTTER_GRAVITY_SOUTH:
13808 coord->v.fraction.x = 0.5;
13809 coord->v.fraction.y = 1.0;
13812 case CLUTTER_GRAVITY_SOUTH_WEST:
13813 coord->v.fraction.x = 0.0;
13814 coord->v.fraction.y = 1.0;
13817 case CLUTTER_GRAVITY_WEST:
13818 coord->v.fraction.x = 0.0;
13819 coord->v.fraction.y = 0.5;
13822 case CLUTTER_GRAVITY_NORTH_WEST:
13823 coord->v.fraction.x = 0.0;
13824 coord->v.fraction.y = 0.0;
13827 case CLUTTER_GRAVITY_CENTER:
13828 coord->v.fraction.x = 0.5;
13829 coord->v.fraction.y = 0.5;
13833 coord->v.fraction.x = 0.0;
13834 coord->v.fraction.y = 0.0;
13838 coord->is_fractional = TRUE;
13842 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
13844 if (coord->is_fractional)
13845 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
13847 return (coord->v.units.x == 0.0
13848 && coord->v.units.y == 0.0
13849 && coord->v.units.z == 0.0);
13853 * clutter_actor_get_flags:
13854 * @self: a #ClutterActor
13856 * Retrieves the flags set on @self
13858 * Return value: a bitwise or of #ClutterActorFlags or 0
13863 clutter_actor_get_flags (ClutterActor *self)
13865 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
13867 return self->flags;
13871 * clutter_actor_set_flags:
13872 * @self: a #ClutterActor
13873 * @flags: the flags to set
13875 * Sets @flags on @self
13877 * This function will emit notifications for the changed properties
13882 clutter_actor_set_flags (ClutterActor *self,
13883 ClutterActorFlags flags)
13885 ClutterActorFlags old_flags;
13887 gboolean was_reactive_set, reactive_set;
13888 gboolean was_realized_set, realized_set;
13889 gboolean was_mapped_set, mapped_set;
13890 gboolean was_visible_set, visible_set;
13892 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13894 if (self->flags == flags)
13897 obj = G_OBJECT (self);
13898 g_object_ref (obj);
13899 g_object_freeze_notify (obj);
13901 old_flags = self->flags;
13903 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13904 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13905 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
13906 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
13908 self->flags |= flags;
13910 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13911 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13912 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
13913 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
13915 if (reactive_set != was_reactive_set)
13916 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13918 if (realized_set != was_realized_set)
13919 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13921 if (mapped_set != was_mapped_set)
13922 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13924 if (visible_set != was_visible_set)
13925 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13927 g_object_thaw_notify (obj);
13928 g_object_unref (obj);
13932 * clutter_actor_unset_flags:
13933 * @self: a #ClutterActor
13934 * @flags: the flags to unset
13936 * Unsets @flags on @self
13938 * This function will emit notifications for the changed properties
13943 clutter_actor_unset_flags (ClutterActor *self,
13944 ClutterActorFlags flags)
13946 ClutterActorFlags old_flags;
13948 gboolean was_reactive_set, reactive_set;
13949 gboolean was_realized_set, realized_set;
13950 gboolean was_mapped_set, mapped_set;
13951 gboolean was_visible_set, visible_set;
13953 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13955 obj = G_OBJECT (self);
13956 g_object_freeze_notify (obj);
13958 old_flags = self->flags;
13960 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
13961 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
13962 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
13963 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
13965 self->flags &= ~flags;
13967 if (self->flags == old_flags)
13970 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
13971 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
13972 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
13973 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
13975 if (reactive_set != was_reactive_set)
13976 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
13978 if (realized_set != was_realized_set)
13979 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
13981 if (mapped_set != was_mapped_set)
13982 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
13984 if (visible_set != was_visible_set)
13985 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
13987 g_object_thaw_notify (obj);
13991 * clutter_actor_get_transformation_matrix:
13992 * @self: a #ClutterActor
13993 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
13995 * Retrieves the transformations applied to @self relative to its
14001 clutter_actor_get_transformation_matrix (ClutterActor *self,
14002 CoglMatrix *matrix)
14004 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14006 cogl_matrix_init_identity (matrix);
14008 _clutter_actor_apply_modelview_transform (self, matrix);
14012 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14013 gboolean is_in_clone_paint)
14015 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14016 self->priv->in_clone_paint = is_in_clone_paint;
14020 * clutter_actor_is_in_clone_paint:
14021 * @self: a #ClutterActor
14023 * Checks whether @self is being currently painted by a #ClutterClone
14025 * This function is useful only inside the ::paint virtual function
14026 * implementations or within handlers for the #ClutterActor::paint
14029 * This function should not be used by applications
14031 * Return value: %TRUE if the #ClutterActor is currently being painted
14032 * by a #ClutterClone, and %FALSE otherwise
14037 clutter_actor_is_in_clone_paint (ClutterActor *self)
14039 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14041 return self->priv->in_clone_paint;
14045 set_direction_recursive (ClutterActor *actor,
14046 gpointer user_data)
14048 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14050 clutter_actor_set_text_direction (actor, text_dir);
14056 * clutter_actor_set_text_direction:
14057 * @self: a #ClutterActor
14058 * @text_dir: the text direction for @self
14060 * Sets the #ClutterTextDirection for an actor
14062 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14064 * If @self implements #ClutterContainer then this function will recurse
14065 * inside all the children of @self (including the internal ones).
14067 * Composite actors not implementing #ClutterContainer, or actors requiring
14068 * special handling when the text direction changes, should connect to
14069 * the #GObject::notify signal for the #ClutterActor:text-direction property
14074 clutter_actor_set_text_direction (ClutterActor *self,
14075 ClutterTextDirection text_dir)
14077 ClutterActorPrivate *priv;
14079 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14080 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14084 if (priv->text_direction != text_dir)
14086 priv->text_direction = text_dir;
14088 /* we need to emit the notify::text-direction first, so that
14089 * the sub-classes can catch that and do specific handling of
14090 * the text direction; see clutter_text_direction_changed_cb()
14091 * inside clutter-text.c
14093 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14095 _clutter_actor_foreach_child (self, set_direction_recursive,
14096 GINT_TO_POINTER (text_dir));
14098 clutter_actor_queue_relayout (self);
14103 _clutter_actor_set_has_pointer (ClutterActor *self,
14104 gboolean has_pointer)
14106 ClutterActorPrivate *priv = self->priv;
14108 if (priv->has_pointer != has_pointer)
14110 priv->has_pointer = has_pointer;
14112 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14117 * clutter_actor_get_text_direction:
14118 * @self: a #ClutterActor
14120 * Retrieves the value set using clutter_actor_set_text_direction()
14122 * If no text direction has been previously set, the default text
14123 * direction, as returned by clutter_get_default_text_direction(), will
14124 * be returned instead
14126 * Return value: the #ClutterTextDirection for the actor
14130 ClutterTextDirection
14131 clutter_actor_get_text_direction (ClutterActor *self)
14133 ClutterActorPrivate *priv;
14135 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14136 CLUTTER_TEXT_DIRECTION_LTR);
14140 /* if no direction has been set yet use the default */
14141 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14142 priv->text_direction = clutter_get_default_text_direction ();
14144 return priv->text_direction;
14148 * clutter_actor_push_internal:
14149 * @self: a #ClutterActor
14151 * Should be used by actors implementing the #ClutterContainer and with
14152 * internal children added through clutter_actor_set_parent(), for instance:
14156 * my_actor_init (MyActor *self)
14158 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14160 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14162 * /* calling clutter_actor_set_parent() now will result in
14163 * * the internal flag being set on a child of MyActor
14166 * /* internal child - a background texture */
14167 * self->priv->background_tex = clutter_texture_new ();
14168 * clutter_actor_set_parent (self->priv->background_tex,
14169 * CLUTTER_ACTOR (self));
14171 * /* internal child - a label */
14172 * self->priv->label = clutter_text_new ();
14173 * clutter_actor_set_parent (self->priv->label,
14174 * CLUTTER_ACTOR (self));
14176 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14178 * /* calling clutter_actor_set_parent() now will not result in
14179 * * the internal flag being set on a child of MyActor
14184 * This function will be used by Clutter to toggle an "internal child"
14185 * flag whenever clutter_actor_set_parent() is called; internal children
14186 * are handled differently by Clutter, specifically when destroying their
14189 * Call clutter_actor_pop_internal() when you finished adding internal
14192 * Nested calls to clutter_actor_push_internal() are allowed, but each
14193 * one must by followed by a clutter_actor_pop_internal() call.
14197 * Deprecated: 1.10: All children of an actor are accessible through
14198 * the #ClutterActor API, and #ClutterActor implements the
14199 * #ClutterContainer interface, so this function is only useful
14200 * for legacy containers overriding the default implementation.
14203 clutter_actor_push_internal (ClutterActor *self)
14205 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14207 self->priv->internal_child += 1;
14211 * clutter_actor_pop_internal:
14212 * @self: a #ClutterActor
14214 * Disables the effects of clutter_actor_push_internal().
14218 * Deprecated: 1.10: All children of an actor are accessible through
14219 * the #ClutterActor API. This function is only useful for legacy
14220 * containers overriding the default implementation of the
14221 * #ClutterContainer interface.
14224 clutter_actor_pop_internal (ClutterActor *self)
14226 ClutterActorPrivate *priv;
14228 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14232 if (priv->internal_child == 0)
14234 g_warning ("Mismatched %s: you need to call "
14235 "clutter_actor_push_composite() at least once before "
14236 "calling this function", G_STRFUNC);
14240 priv->internal_child -= 1;
14244 * clutter_actor_has_pointer:
14245 * @self: a #ClutterActor
14247 * Checks whether an actor contains the pointer of a
14248 * #ClutterInputDevice
14250 * Return value: %TRUE if the actor contains the pointer, and
14256 clutter_actor_has_pointer (ClutterActor *self)
14258 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14260 return self->priv->has_pointer;
14263 /* XXX: This is a workaround for not being able to break the ABI of
14264 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14265 * clutter_actor_queue_clipped_redraw() for details.
14267 ClutterPaintVolume *
14268 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14270 return g_object_get_data (G_OBJECT (self),
14271 "-clutter-actor-queue-redraw-clip");
14275 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14276 ClutterPaintVolume *clip)
14278 g_object_set_data (G_OBJECT (self),
14279 "-clutter-actor-queue-redraw-clip",
14284 * clutter_actor_has_allocation:
14285 * @self: a #ClutterActor
14287 * Checks if the actor has an up-to-date allocation assigned to
14288 * it. This means that the actor should have an allocation: it's
14289 * visible and has a parent. It also means that there is no
14290 * outstanding relayout request in progress for the actor or its
14291 * children (There might be other outstanding layout requests in
14292 * progress that will cause the actor to get a new allocation
14293 * when the stage is laid out, however).
14295 * If this function returns %FALSE, then the actor will normally
14296 * be allocated before it is next drawn on the screen.
14298 * Return value: %TRUE if the actor has an up-to-date allocation
14303 clutter_actor_has_allocation (ClutterActor *self)
14305 ClutterActorPrivate *priv;
14307 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14311 return priv->parent != NULL &&
14312 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14313 !priv->needs_allocation;
14317 * clutter_actor_add_action:
14318 * @self: a #ClutterActor
14319 * @action: a #ClutterAction
14321 * Adds @action to the list of actions applied to @self
14323 * A #ClutterAction can only belong to one actor at a time
14325 * The #ClutterActor will hold a reference on @action until either
14326 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14332 clutter_actor_add_action (ClutterActor *self,
14333 ClutterAction *action)
14335 ClutterActorPrivate *priv;
14337 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14338 g_return_if_fail (CLUTTER_IS_ACTION (action));
14342 if (priv->actions == NULL)
14344 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14345 priv->actions->actor = self;
14348 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14350 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14354 * clutter_actor_add_action_with_name:
14355 * @self: a #ClutterActor
14356 * @name: the name to set on the action
14357 * @action: a #ClutterAction
14359 * A convenience function for setting the name of a #ClutterAction
14360 * while adding it to the list of actions applied to @self
14362 * This function is the logical equivalent of:
14365 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14366 * clutter_actor_add_action (self, action);
14372 clutter_actor_add_action_with_name (ClutterActor *self,
14374 ClutterAction *action)
14376 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14377 g_return_if_fail (name != NULL);
14378 g_return_if_fail (CLUTTER_IS_ACTION (action));
14380 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14381 clutter_actor_add_action (self, action);
14385 * clutter_actor_remove_action:
14386 * @self: a #ClutterActor
14387 * @action: a #ClutterAction
14389 * Removes @action from the list of actions applied to @self
14391 * The reference held by @self on the #ClutterAction will be released
14396 clutter_actor_remove_action (ClutterActor *self,
14397 ClutterAction *action)
14399 ClutterActorPrivate *priv;
14401 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14402 g_return_if_fail (CLUTTER_IS_ACTION (action));
14406 if (priv->actions == NULL)
14409 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14411 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14415 * clutter_actor_remove_action_by_name:
14416 * @self: a #ClutterActor
14417 * @name: the name of the action to remove
14419 * Removes the #ClutterAction with the given name from the list
14420 * of actions applied to @self
14425 clutter_actor_remove_action_by_name (ClutterActor *self,
14428 ClutterActorPrivate *priv;
14429 ClutterActorMeta *meta;
14431 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14432 g_return_if_fail (name != NULL);
14436 if (priv->actions == NULL)
14439 meta = _clutter_meta_group_get_meta (priv->actions, name);
14443 _clutter_meta_group_remove_meta (priv->actions, meta);
14445 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14449 * clutter_actor_get_actions:
14450 * @self: a #ClutterActor
14452 * Retrieves the list of actions applied to @self
14454 * Return value: (transfer container) (element-type Clutter.Action): a copy
14455 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14456 * owned by the #ClutterActor. Use g_list_free() to free the resources
14457 * allocated by the returned #GList
14462 clutter_actor_get_actions (ClutterActor *self)
14464 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14466 if (self->priv->actions == NULL)
14469 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14473 * clutter_actor_get_action:
14474 * @self: a #ClutterActor
14475 * @name: the name of the action to retrieve
14477 * Retrieves the #ClutterAction with the given name in the list
14478 * of actions applied to @self
14480 * Return value: (transfer none): a #ClutterAction for the given
14481 * name, or %NULL. The returned #ClutterAction is owned by the
14482 * actor and it should not be unreferenced directly
14487 clutter_actor_get_action (ClutterActor *self,
14490 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14491 g_return_val_if_fail (name != NULL, NULL);
14493 if (self->priv->actions == NULL)
14496 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14500 * clutter_actor_clear_actions:
14501 * @self: a #ClutterActor
14503 * Clears the list of actions applied to @self
14508 clutter_actor_clear_actions (ClutterActor *self)
14510 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14512 if (self->priv->actions == NULL)
14515 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14519 * clutter_actor_add_constraint:
14520 * @self: a #ClutterActor
14521 * @constraint: a #ClutterConstraint
14523 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14526 * The #ClutterActor will hold a reference on the @constraint until
14527 * either clutter_actor_remove_constraint() or
14528 * clutter_actor_clear_constraints() is called.
14533 clutter_actor_add_constraint (ClutterActor *self,
14534 ClutterConstraint *constraint)
14536 ClutterActorPrivate *priv;
14538 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14539 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14543 if (priv->constraints == NULL)
14545 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14546 priv->constraints->actor = self;
14549 _clutter_meta_group_add_meta (priv->constraints,
14550 CLUTTER_ACTOR_META (constraint));
14551 clutter_actor_queue_relayout (self);
14553 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14557 * clutter_actor_add_constraint_with_name:
14558 * @self: a #ClutterActor
14559 * @name: the name to set on the constraint
14560 * @constraint: a #ClutterConstraint
14562 * A convenience function for setting the name of a #ClutterConstraint
14563 * while adding it to the list of constraints applied to @self
14565 * This function is the logical equivalent of:
14568 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14569 * clutter_actor_add_constraint (self, constraint);
14575 clutter_actor_add_constraint_with_name (ClutterActor *self,
14577 ClutterConstraint *constraint)
14579 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14580 g_return_if_fail (name != NULL);
14581 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14583 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14584 clutter_actor_add_constraint (self, constraint);
14588 * clutter_actor_remove_constraint:
14589 * @self: a #ClutterActor
14590 * @constraint: a #ClutterConstraint
14592 * Removes @constraint from the list of constraints applied to @self
14594 * The reference held by @self on the #ClutterConstraint will be released
14599 clutter_actor_remove_constraint (ClutterActor *self,
14600 ClutterConstraint *constraint)
14602 ClutterActorPrivate *priv;
14604 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14605 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14609 if (priv->constraints == NULL)
14612 _clutter_meta_group_remove_meta (priv->constraints,
14613 CLUTTER_ACTOR_META (constraint));
14614 clutter_actor_queue_relayout (self);
14616 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14620 * clutter_actor_remove_constraint_by_name:
14621 * @self: a #ClutterActor
14622 * @name: the name of the constraint to remove
14624 * Removes the #ClutterConstraint with the given name from the list
14625 * of constraints applied to @self
14630 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14633 ClutterActorPrivate *priv;
14634 ClutterActorMeta *meta;
14636 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14637 g_return_if_fail (name != NULL);
14641 if (priv->constraints == NULL)
14644 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14648 _clutter_meta_group_remove_meta (priv->constraints, meta);
14649 clutter_actor_queue_relayout (self);
14653 * clutter_actor_get_constraints:
14654 * @self: a #ClutterActor
14656 * Retrieves the list of constraints applied to @self
14658 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14659 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14660 * owned by the #ClutterActor. Use g_list_free() to free the resources
14661 * allocated by the returned #GList
14666 clutter_actor_get_constraints (ClutterActor *self)
14668 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14670 if (self->priv->constraints == NULL)
14673 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14677 * clutter_actor_get_constraint:
14678 * @self: a #ClutterActor
14679 * @name: the name of the constraint to retrieve
14681 * Retrieves the #ClutterConstraint with the given name in the list
14682 * of constraints applied to @self
14684 * Return value: (transfer none): a #ClutterConstraint for the given
14685 * name, or %NULL. The returned #ClutterConstraint is owned by the
14686 * actor and it should not be unreferenced directly
14690 ClutterConstraint *
14691 clutter_actor_get_constraint (ClutterActor *self,
14694 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14695 g_return_val_if_fail (name != NULL, NULL);
14697 if (self->priv->constraints == NULL)
14700 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14704 * clutter_actor_clear_constraints:
14705 * @self: a #ClutterActor
14707 * Clears the list of constraints applied to @self
14712 clutter_actor_clear_constraints (ClutterActor *self)
14714 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14716 if (self->priv->constraints == NULL)
14719 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14721 clutter_actor_queue_relayout (self);
14725 * clutter_actor_set_clip_to_allocation:
14726 * @self: a #ClutterActor
14727 * @clip_set: %TRUE to apply a clip tracking the allocation
14729 * Sets whether @self should be clipped to the same size as its
14735 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14738 ClutterActorPrivate *priv;
14740 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14742 clip_set = !!clip_set;
14746 if (priv->clip_to_allocation != clip_set)
14748 priv->clip_to_allocation = clip_set;
14750 clutter_actor_queue_redraw (self);
14752 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
14757 * clutter_actor_get_clip_to_allocation:
14758 * @self: a #ClutterActor
14760 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
14762 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
14767 clutter_actor_get_clip_to_allocation (ClutterActor *self)
14769 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14771 return self->priv->clip_to_allocation;
14775 * clutter_actor_add_effect:
14776 * @self: a #ClutterActor
14777 * @effect: a #ClutterEffect
14779 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
14781 * The #ClutterActor will hold a reference on the @effect until either
14782 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
14788 clutter_actor_add_effect (ClutterActor *self,
14789 ClutterEffect *effect)
14791 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14792 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14794 _clutter_actor_add_effect_internal (self, effect);
14796 clutter_actor_queue_redraw (self);
14798 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14802 * clutter_actor_add_effect_with_name:
14803 * @self: a #ClutterActor
14804 * @name: the name to set on the effect
14805 * @effect: a #ClutterEffect
14807 * A convenience function for setting the name of a #ClutterEffect
14808 * while adding it to the list of effectss applied to @self
14810 * This function is the logical equivalent of:
14813 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14814 * clutter_actor_add_effect (self, effect);
14820 clutter_actor_add_effect_with_name (ClutterActor *self,
14822 ClutterEffect *effect)
14824 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14825 g_return_if_fail (name != NULL);
14826 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14828 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
14829 clutter_actor_add_effect (self, effect);
14833 * clutter_actor_remove_effect:
14834 * @self: a #ClutterActor
14835 * @effect: a #ClutterEffect
14837 * Removes @effect from the list of effects applied to @self
14839 * The reference held by @self on the #ClutterEffect will be released
14844 clutter_actor_remove_effect (ClutterActor *self,
14845 ClutterEffect *effect)
14847 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14848 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
14850 _clutter_actor_remove_effect_internal (self, effect);
14852 clutter_actor_queue_redraw (self);
14854 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
14858 * clutter_actor_remove_effect_by_name:
14859 * @self: a #ClutterActor
14860 * @name: the name of the effect to remove
14862 * Removes the #ClutterEffect with the given name from the list
14863 * of effects applied to @self
14868 clutter_actor_remove_effect_by_name (ClutterActor *self,
14871 ClutterActorPrivate *priv;
14872 ClutterActorMeta *meta;
14874 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14875 g_return_if_fail (name != NULL);
14879 if (priv->effects == NULL)
14882 meta = _clutter_meta_group_get_meta (priv->effects, name);
14886 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
14890 * clutter_actor_get_effects:
14891 * @self: a #ClutterActor
14893 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
14895 * Return value: (transfer container) (element-type Clutter.Effect): a list
14896 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
14897 * list are owned by Clutter and they should not be freed. You should
14898 * free the returned list using g_list_free() when done
14903 clutter_actor_get_effects (ClutterActor *self)
14905 ClutterActorPrivate *priv;
14907 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14911 if (priv->effects == NULL)
14914 return _clutter_meta_group_get_metas_no_internal (priv->effects);
14918 * clutter_actor_get_effect:
14919 * @self: a #ClutterActor
14920 * @name: the name of the effect to retrieve
14922 * Retrieves the #ClutterEffect with the given name in the list
14923 * of effects applied to @self
14925 * Return value: (transfer none): a #ClutterEffect for the given
14926 * name, or %NULL. The returned #ClutterEffect is owned by the
14927 * actor and it should not be unreferenced directly
14932 clutter_actor_get_effect (ClutterActor *self,
14935 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14936 g_return_val_if_fail (name != NULL, NULL);
14938 if (self->priv->effects == NULL)
14941 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
14945 * clutter_actor_clear_effects:
14946 * @self: a #ClutterActor
14948 * Clears the list of effects applied to @self
14953 clutter_actor_clear_effects (ClutterActor *self)
14955 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14957 if (self->priv->effects == NULL)
14960 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
14962 clutter_actor_queue_redraw (self);
14966 * clutter_actor_has_key_focus:
14967 * @self: a #ClutterActor
14969 * Checks whether @self is the #ClutterActor that has key focus
14971 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
14976 clutter_actor_has_key_focus (ClutterActor *self)
14978 ClutterActor *stage;
14980 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14982 stage = _clutter_actor_get_stage_internal (self);
14986 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
14990 _clutter_actor_get_paint_volume_real (ClutterActor *self,
14991 ClutterPaintVolume *pv)
14993 ClutterActorPrivate *priv = self->priv;
14995 /* Actors are only expected to report a valid paint volume
14996 * while they have a valid allocation. */
14997 if (G_UNLIKELY (priv->needs_allocation))
14999 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15000 "Actor needs allocation",
15001 _clutter_actor_get_debug_name (self));
15005 /* Check if there are any handlers connected to the paint
15006 * signal. If there are then all bets are off for what the paint
15007 * volume for this actor might possibly be!
15009 * XXX: It's expected that this is going to end up being quite a
15010 * costly check to have to do here, but we haven't come up with
15011 * another solution that can reliably catch paint signal handlers at
15012 * the right time to either avoid artefacts due to invalid stage
15013 * clipping or due to incorrect culling.
15015 * Previously we checked in clutter_actor_paint(), but at that time
15016 * we may already be using a stage clip that could be derived from
15017 * an invalid paint-volume. We used to try and handle that by
15018 * queuing a follow up, unclipped, redraw but still the previous
15019 * checking wasn't enough to catch invalid volumes involved in
15020 * culling (considering that containers may derive their volume from
15021 * children that haven't yet been painted)
15023 * Longer term, improved solutions could be:
15024 * - Disallow painting in the paint signal, only allow using it
15025 * for tracking when paints happen. We can add another API that
15026 * allows monkey patching the paint of arbitrary actors but in a
15027 * more controlled way and that also supports modifying the
15029 * - If we could be notified somehow when signal handlers are
15030 * connected we wouldn't have to poll for handlers like this.
15032 if (g_signal_has_handler_pending (self,
15033 actor_signals[PAINT],
15037 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15038 "Actor has \"paint\" signal handlers",
15039 _clutter_actor_get_debug_name (self));
15043 _clutter_paint_volume_init_static (pv, self);
15045 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15047 clutter_paint_volume_free (pv);
15048 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15049 "Actor failed to report a volume",
15050 _clutter_actor_get_debug_name (self));
15054 /* since effects can modify the paint volume, we allow them to actually
15055 * do this by making get_paint_volume() "context sensitive"
15057 if (priv->effects != NULL)
15059 if (priv->current_effect != NULL)
15061 const GList *effects, *l;
15063 /* if we are being called from within the paint sequence of
15064 * an actor, get the paint volume up to the current effect
15066 effects = _clutter_meta_group_peek_metas (priv->effects);
15068 l != NULL || (l != NULL && l->data != priv->current_effect);
15071 if (!_clutter_effect_get_paint_volume (l->data, pv))
15073 clutter_paint_volume_free (pv);
15074 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15075 "Effect (%s) failed to report a volume",
15076 _clutter_actor_get_debug_name (self),
15077 _clutter_actor_meta_get_debug_name (l->data));
15084 const GList *effects, *l;
15086 /* otherwise, get the cumulative volume */
15087 effects = _clutter_meta_group_peek_metas (priv->effects);
15088 for (l = effects; l != NULL; l = l->next)
15089 if (!_clutter_effect_get_paint_volume (l->data, pv))
15091 clutter_paint_volume_free (pv);
15092 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15093 "Effect (%s) failed to report a volume",
15094 _clutter_actor_get_debug_name (self),
15095 _clutter_actor_meta_get_debug_name (l->data));
15104 /* The public clutter_actor_get_paint_volume API returns a const
15105 * pointer since we return a pointer directly to the cached
15106 * PaintVolume associated with the actor and don't want the user to
15107 * inadvertently modify it, but for internal uses we sometimes need
15108 * access to the same PaintVolume but need to apply some book-keeping
15109 * modifications to it so we don't want a const pointer.
15111 static ClutterPaintVolume *
15112 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15114 ClutterActorPrivate *priv;
15118 if (priv->paint_volume_valid)
15119 clutter_paint_volume_free (&priv->paint_volume);
15121 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15123 priv->paint_volume_valid = TRUE;
15124 return &priv->paint_volume;
15128 priv->paint_volume_valid = FALSE;
15134 * clutter_actor_get_paint_volume:
15135 * @self: a #ClutterActor
15137 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15138 * when a paint volume can't be determined.
15140 * The paint volume is defined as the 3D space occupied by an actor
15141 * when being painted.
15143 * This function will call the <function>get_paint_volume()</function>
15144 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15145 * should not usually care about overriding the default implementation,
15146 * unless they are, for instance: painting outside their allocation, or
15147 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15150 * <note>2D actors overriding <function>get_paint_volume()</function>
15151 * ensure their volume has a depth of 0. (This will be true so long as
15152 * you don't call clutter_paint_volume_set_depth().)</note>
15154 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15155 * or %NULL if no volume could be determined. The returned pointer
15156 * is not guaranteed to be valid across multiple frames; if you want
15157 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15161 const ClutterPaintVolume *
15162 clutter_actor_get_paint_volume (ClutterActor *self)
15164 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15166 return _clutter_actor_get_paint_volume_mutable (self);
15170 * clutter_actor_get_transformed_paint_volume:
15171 * @self: a #ClutterActor
15172 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15173 * (or %NULL for the stage)
15175 * Retrieves the 3D paint volume of an actor like
15176 * clutter_actor_get_paint_volume() does (Please refer to the
15177 * documentation of clutter_actor_get_paint_volume() for more
15178 * details.) and it additionally transforms the paint volume into the
15179 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15180 * is passed for @relative_to_ancestor)
15182 * This can be used by containers that base their paint volume on
15183 * the volume of their children. Such containers can query the
15184 * transformed paint volume of all of its children and union them
15185 * together using clutter_paint_volume_union().
15187 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15188 * or %NULL if no volume could be determined. The returned pointer is
15189 * not guaranteed to be valid across multiple frames; if you wish to
15190 * keep it, you will have to copy it using clutter_paint_volume_copy().
15194 const ClutterPaintVolume *
15195 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15196 ClutterActor *relative_to_ancestor)
15198 const ClutterPaintVolume *volume;
15199 ClutterActor *stage;
15200 ClutterPaintVolume *transformed_volume;
15202 stage = _clutter_actor_get_stage_internal (self);
15203 if (G_UNLIKELY (stage == NULL))
15206 if (relative_to_ancestor == NULL)
15207 relative_to_ancestor = stage;
15209 volume = clutter_actor_get_paint_volume (self);
15210 if (volume == NULL)
15213 transformed_volume =
15214 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15216 _clutter_paint_volume_copy_static (volume, transformed_volume);
15218 _clutter_paint_volume_transform_relative (transformed_volume,
15219 relative_to_ancestor);
15221 return transformed_volume;
15225 * clutter_actor_get_paint_box:
15226 * @self: a #ClutterActor
15227 * @box: (out): return location for a #ClutterActorBox
15229 * Retrieves the paint volume of the passed #ClutterActor, and
15230 * transforms it into a 2D bounding box in stage coordinates.
15232 * This function is useful to determine the on screen area occupied by
15233 * the actor. The box is only an approximation and may often be
15234 * considerably larger due to the optimizations used to calculate the
15235 * box. The box is never smaller though, so it can reliably be used
15238 * There are times when a 2D paint box can't be determined, e.g.
15239 * because the actor isn't yet parented under a stage or because
15240 * the actor is unable to determine a paint volume.
15242 * Return value: %TRUE if a 2D paint box could be determined, else
15248 clutter_actor_get_paint_box (ClutterActor *self,
15249 ClutterActorBox *box)
15251 ClutterActor *stage;
15252 ClutterPaintVolume *pv;
15254 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15255 g_return_val_if_fail (box != NULL, FALSE);
15257 stage = _clutter_actor_get_stage_internal (self);
15258 if (G_UNLIKELY (!stage))
15261 pv = _clutter_actor_get_paint_volume_mutable (self);
15262 if (G_UNLIKELY (!pv))
15265 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15271 * clutter_actor_has_overlaps:
15272 * @self: A #ClutterActor
15274 * Asks the actor's implementation whether it may contain overlapping
15277 * For example; Clutter may use this to determine whether the painting
15278 * should be redirected to an offscreen buffer to correctly implement
15279 * the opacity property.
15281 * Custom actors can override the default response by implementing the
15282 * #ClutterActor <function>has_overlaps</function> virtual function. See
15283 * clutter_actor_set_offscreen_redirect() for more information.
15285 * Return value: %TRUE if the actor may have overlapping primitives, and
15291 clutter_actor_has_overlaps (ClutterActor *self)
15293 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15295 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15299 * clutter_actor_has_effects:
15300 * @self: A #ClutterActor
15302 * Returns whether the actor has any effects applied.
15304 * Return value: %TRUE if the actor has any effects,
15310 clutter_actor_has_effects (ClutterActor *self)
15312 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15314 if (self->priv->effects == NULL)
15317 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15321 * clutter_actor_has_constraints:
15322 * @self: A #ClutterActor
15324 * Returns whether the actor has any constraints applied.
15326 * Return value: %TRUE if the actor has any constraints,
15332 clutter_actor_has_constraints (ClutterActor *self)
15334 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15336 return self->priv->constraints != NULL;
15340 * clutter_actor_has_actions:
15341 * @self: A #ClutterActor
15343 * Returns whether the actor has any actions applied.
15345 * Return value: %TRUE if the actor has any actions,
15351 clutter_actor_has_actions (ClutterActor *self)
15353 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15355 return self->priv->actions != NULL;
15359 * clutter_actor_get_n_children:
15360 * @self: a #ClutterActor
15362 * Retrieves the number of children of @self.
15364 * Return value: the number of children of an actor
15369 clutter_actor_get_n_children (ClutterActor *self)
15371 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15373 return self->priv->n_children;
15377 * clutter_actor_get_child_at_index:
15378 * @self: a #ClutterActor
15379 * @index_: the position in the list of children
15381 * Retrieves the actor at the given @index_ inside the list of
15382 * children of @self.
15384 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15389 clutter_actor_get_child_at_index (ClutterActor *self,
15392 ClutterActor *iter;
15395 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15396 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15398 for (iter = self->priv->first_child, i = 0;
15399 iter != NULL && i < index_;
15400 iter = iter->priv->next_sibling, i += 1)
15407 * _clutter_actor_foreach_child:
15408 * @actor: The actor whos children you want to iterate
15409 * @callback: The function to call for each child
15410 * @user_data: Private data to pass to @callback
15412 * Calls a given @callback once for each child of the specified @actor and
15413 * passing the @user_data pointer each time.
15415 * Return value: returns %TRUE if all children were iterated, else
15416 * %FALSE if a callback broke out of iteration early.
15419 _clutter_actor_foreach_child (ClutterActor *self,
15420 ClutterForeachCallback callback,
15421 gpointer user_data)
15423 ClutterActorPrivate *priv = self->priv;
15424 ClutterActor *iter;
15427 for (cont = TRUE, iter = priv->first_child;
15428 cont && iter != NULL;
15429 iter = iter->priv->next_sibling)
15431 cont = callback (iter, user_data);
15438 /* For debugging purposes this gives us a simple way to print out
15439 * the scenegraph e.g in gdb using:
15441 * _clutter_actor_traverse (stage,
15443 * clutter_debug_print_actor_cb,
15448 static ClutterActorTraverseVisitFlags
15449 clutter_debug_print_actor_cb (ClutterActor *actor,
15453 g_print ("%*s%s:%p\n",
15455 _clutter_actor_get_debug_name (actor),
15458 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15463 _clutter_actor_traverse_breadth (ClutterActor *actor,
15464 ClutterTraverseCallback callback,
15465 gpointer user_data)
15467 GQueue *queue = g_queue_new ();
15468 ClutterActor dummy;
15469 int current_depth = 0;
15471 g_queue_push_tail (queue, actor);
15472 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15474 while ((actor = g_queue_pop_head (queue)))
15476 ClutterActorTraverseVisitFlags flags;
15478 if (actor == &dummy)
15481 g_queue_push_tail (queue, &dummy);
15485 flags = callback (actor, current_depth, user_data);
15486 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15488 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15490 ClutterActor *iter;
15492 for (iter = actor->priv->first_child;
15494 iter = iter->priv->next_sibling)
15496 g_queue_push_tail (queue, iter);
15501 g_queue_free (queue);
15504 static ClutterActorTraverseVisitFlags
15505 _clutter_actor_traverse_depth (ClutterActor *actor,
15506 ClutterTraverseCallback before_children_callback,
15507 ClutterTraverseCallback after_children_callback,
15509 gpointer user_data)
15511 ClutterActorTraverseVisitFlags flags;
15513 flags = before_children_callback (actor, current_depth, user_data);
15514 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15515 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15517 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15519 ClutterActor *iter;
15521 for (iter = actor->priv->first_child;
15523 iter = iter->priv->next_sibling)
15525 flags = _clutter_actor_traverse_depth (iter,
15526 before_children_callback,
15527 after_children_callback,
15531 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15532 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15536 if (after_children_callback)
15537 return after_children_callback (actor, current_depth, user_data);
15539 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15542 /* _clutter_actor_traverse:
15543 * @actor: The actor to start traversing the graph from
15544 * @flags: These flags may affect how the traversal is done
15545 * @before_children_callback: A function to call before visiting the
15546 * children of the current actor.
15547 * @after_children_callback: A function to call after visiting the
15548 * children of the current actor. (Ignored if
15549 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15550 * @user_data: The private data to pass to the callbacks
15552 * Traverses the scenegraph starting at the specified @actor and
15553 * descending through all its children and its children's children.
15554 * For each actor traversed @before_children_callback and
15555 * @after_children_callback are called with the specified
15556 * @user_data, before and after visiting that actor's children.
15558 * The callbacks can return flags that affect the ongoing traversal
15559 * such as by skipping over an actors children or bailing out of
15560 * any further traversing.
15563 _clutter_actor_traverse (ClutterActor *actor,
15564 ClutterActorTraverseFlags flags,
15565 ClutterTraverseCallback before_children_callback,
15566 ClutterTraverseCallback after_children_callback,
15567 gpointer user_data)
15569 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15570 _clutter_actor_traverse_breadth (actor,
15571 before_children_callback,
15573 else /* DEPTH_FIRST */
15574 _clutter_actor_traverse_depth (actor,
15575 before_children_callback,
15576 after_children_callback,
15577 0, /* start depth */
15582 on_layout_manager_changed (ClutterLayoutManager *manager,
15583 ClutterActor *self)
15585 clutter_actor_queue_relayout (self);
15589 * clutter_actor_set_layout_manager:
15590 * @self: a #ClutterActor
15591 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15593 * Sets the #ClutterLayoutManager delegate object that will be used to
15594 * lay out the children of @self.
15596 * The #ClutterActor will take a reference on the passed @manager which
15597 * will be released either when the layout manager is removed, or when
15598 * the actor is destroyed.
15603 clutter_actor_set_layout_manager (ClutterActor *self,
15604 ClutterLayoutManager *manager)
15606 ClutterActorPrivate *priv;
15608 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15609 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15613 if (priv->layout_manager != NULL)
15615 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15616 G_CALLBACK (on_layout_manager_changed),
15618 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15619 g_object_unref (priv->layout_manager);
15622 priv->layout_manager = manager;
15624 if (priv->layout_manager != NULL)
15626 g_object_ref_sink (priv->layout_manager);
15627 clutter_layout_manager_set_container (priv->layout_manager,
15628 CLUTTER_CONTAINER (self));
15629 g_signal_connect (priv->layout_manager, "layout-changed",
15630 G_CALLBACK (on_layout_manager_changed),
15634 clutter_actor_queue_relayout (self);
15636 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15640 * clutter_actor_get_layout_manager:
15641 * @self: a #ClutterActor
15643 * Retrieves the #ClutterLayoutManager used by @self.
15645 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15650 ClutterLayoutManager *
15651 clutter_actor_get_layout_manager (ClutterActor *self)
15653 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15655 return self->priv->layout_manager;
15658 static const ClutterLayoutInfo default_layout_info = {
15661 { 0, 0, 0, 0 }, /* margin */
15662 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15663 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15664 0.f, 0.f, /* min_width, natural_width */
15665 0.f, 0.f, /* natual_width, natural_height */
15669 layout_info_free (gpointer data)
15671 if (G_LIKELY (data != NULL))
15672 g_slice_free (ClutterLayoutInfo, data);
15676 * _clutter_actor_get_layout_info:
15677 * @self: a #ClutterActor
15679 * Retrieves a pointer to the ClutterLayoutInfo structure.
15681 * If the actor does not have a ClutterLayoutInfo associated to it, one
15682 * will be created and initialized to the default values.
15684 * This function should be used for setters.
15686 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15689 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15691 ClutterLayoutInfo *
15692 _clutter_actor_get_layout_info (ClutterActor *self)
15694 ClutterLayoutInfo *retval;
15696 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15697 if (retval == NULL)
15699 retval = g_slice_new (ClutterLayoutInfo);
15701 *retval = default_layout_info;
15703 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15712 * _clutter_actor_get_layout_info_or_defaults:
15713 * @self: a #ClutterActor
15715 * Retrieves the ClutterLayoutInfo structure associated to an actor.
15717 * If the actor does not have a ClutterLayoutInfo structure associated to it,
15718 * then the default structure will be returned.
15720 * This function should only be used for getters.
15722 * Return value: a const pointer to the ClutterLayoutInfo structure
15724 const ClutterLayoutInfo *
15725 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15727 const ClutterLayoutInfo *info;
15729 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15731 return &default_layout_info;
15737 * clutter_actor_set_x_align:
15738 * @self: a #ClutterActor
15739 * @x_align: the horizontal alignment policy
15741 * Sets the horizontal alignment policy of a #ClutterActor, in case the
15742 * actor received extra horizontal space.
15744 * See also the #ClutterActor:x-align property.
15749 clutter_actor_set_x_align (ClutterActor *self,
15750 ClutterActorAlign x_align)
15752 ClutterLayoutInfo *info;
15754 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15756 info = _clutter_actor_get_layout_info (self);
15758 if (info->x_align != x_align)
15760 info->x_align = x_align;
15762 clutter_actor_queue_relayout (self);
15764 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
15769 * clutter_actor_get_x_align:
15770 * @self: a #ClutterActor
15772 * Retrieves the horizontal alignment policy set using
15773 * clutter_actor_set_x_align().
15775 * Return value: the horizontal alignment policy.
15780 clutter_actor_get_x_align (ClutterActor *self)
15782 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15784 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
15788 * clutter_actor_set_y_align:
15789 * @self: a #ClutterActor
15790 * @y_align: the vertical alignment policy
15792 * Sets the vertical alignment policy of a #ClutterActor, in case the
15793 * actor received extra vertical space.
15795 * See also the #ClutterActor:y-align property.
15800 clutter_actor_set_y_align (ClutterActor *self,
15801 ClutterActorAlign y_align)
15803 ClutterLayoutInfo *info;
15805 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15807 info = _clutter_actor_get_layout_info (self);
15809 if (info->y_align != y_align)
15811 info->y_align = y_align;
15813 clutter_actor_queue_relayout (self);
15815 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
15820 * clutter_actor_get_y_align:
15821 * @self: a #ClutterActor
15823 * Retrieves the vertical alignment policy set using
15824 * clutter_actor_set_y_align().
15826 * Return value: the vertical alignment policy.
15831 clutter_actor_get_y_align (ClutterActor *self)
15833 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
15835 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
15840 * clutter_margin_new:
15842 * Creates a new #ClutterMargin.
15844 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
15845 * clutter_margin_free() to free the resources associated with it when
15851 clutter_margin_new (void)
15853 return g_slice_new0 (ClutterMargin);
15857 * clutter_margin_copy:
15858 * @margin_: a #ClutterMargin
15860 * Creates a new #ClutterMargin and copies the contents of @margin_ into
15861 * the newly created structure.
15863 * Return value: (transfer full): a copy of the #ClutterMargin.
15868 clutter_margin_copy (const ClutterMargin *margin_)
15870 if (G_LIKELY (margin_ != NULL))
15871 return g_slice_dup (ClutterMargin, margin_);
15877 * clutter_margin_free:
15878 * @margin_: a #ClutterMargin
15880 * Frees the resources allocated by clutter_margin_new() and
15881 * clutter_margin_copy().
15886 clutter_margin_free (ClutterMargin *margin_)
15888 if (G_LIKELY (margin_ != NULL))
15889 g_slice_free (ClutterMargin, margin_);
15892 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
15893 clutter_margin_copy,
15894 clutter_margin_free)
15897 * clutter_actor_set_margin:
15898 * @self: a #ClutterActor
15899 * @margin: a #ClutterMargin
15901 * Sets all the components of the margin of a #ClutterActor.
15906 clutter_actor_set_margin (ClutterActor *self,
15907 const ClutterMargin *margin)
15909 ClutterLayoutInfo *info;
15913 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15914 g_return_if_fail (margin != NULL);
15916 obj = G_OBJECT (self);
15919 g_object_freeze_notify (obj);
15921 info = _clutter_actor_get_layout_info (self);
15923 if (info->margin.top != margin->top)
15925 info->margin.top = margin->top;
15926 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
15930 if (info->margin.right != margin->right)
15932 info->margin.right = margin->right;
15933 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
15937 if (info->margin.bottom != margin->bottom)
15939 info->margin.bottom = margin->bottom;
15940 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
15944 if (info->margin.left != margin->left)
15946 info->margin.left = margin->left;
15947 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
15952 clutter_actor_queue_relayout (self);
15954 g_object_thaw_notify (obj);
15958 * clutter_actor_get_margin:
15959 * @self: a #ClutterActor
15960 * @margin: (out caller-allocates): return location for a #ClutterMargin
15962 * Retrieves all the components of the margin of a #ClutterActor.
15967 clutter_actor_get_margin (ClutterActor *self,
15968 ClutterMargin *margin)
15970 const ClutterLayoutInfo *info;
15972 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15973 g_return_if_fail (margin != NULL);
15975 info = _clutter_actor_get_layout_info_or_defaults (self);
15977 *margin = info->margin;
15981 * clutter_actor_set_margin_top:
15982 * @self: a #ClutterActor
15983 * @margin: the top margin
15985 * Sets the margin from the top of a #ClutterActor.
15990 clutter_actor_set_margin_top (ClutterActor *self,
15993 ClutterLayoutInfo *info;
15995 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15996 g_return_if_fail (margin >= 0.f);
15998 info = _clutter_actor_get_layout_info (self);
16000 if (info->margin.top == margin)
16003 info->margin.top = margin;
16005 clutter_actor_queue_relayout (self);
16007 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16011 * clutter_actor_get_margin_top:
16012 * @self: a #ClutterActor
16014 * Retrieves the top margin of a #ClutterActor.
16016 * Return value: the top margin
16021 clutter_actor_get_margin_top (ClutterActor *self)
16023 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16025 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16029 * clutter_actor_set_margin_bottom:
16030 * @self: a #ClutterActor
16031 * @margin: the bottom margin
16033 * Sets the margin from the bottom of a #ClutterActor.
16038 clutter_actor_set_margin_bottom (ClutterActor *self,
16041 ClutterLayoutInfo *info;
16043 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16044 g_return_if_fail (margin >= 0.f);
16046 info = _clutter_actor_get_layout_info (self);
16048 if (info->margin.bottom == margin)
16051 info->margin.bottom = margin;
16053 clutter_actor_queue_relayout (self);
16055 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16059 * clutter_actor_get_margin_bottom:
16060 * @self: a #ClutterActor
16062 * Retrieves the bottom margin of a #ClutterActor.
16064 * Return value: the bottom margin
16069 clutter_actor_get_margin_bottom (ClutterActor *self)
16071 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16073 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16077 * clutter_actor_set_margin_left:
16078 * @self: a #ClutterActor
16079 * @margin: the left margin
16081 * Sets the margin from the left of a #ClutterActor.
16086 clutter_actor_set_margin_left (ClutterActor *self,
16089 ClutterLayoutInfo *info;
16091 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16092 g_return_if_fail (margin >= 0.f);
16094 info = _clutter_actor_get_layout_info (self);
16096 if (info->margin.left == margin)
16099 info->margin.left = margin;
16101 clutter_actor_queue_relayout (self);
16103 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16107 * clutter_actor_get_margin_left:
16108 * @self: a #ClutterActor
16110 * Retrieves the left margin of a #ClutterActor.
16112 * Return value: the left margin
16117 clutter_actor_get_margin_left (ClutterActor *self)
16119 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16121 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16125 * clutter_actor_set_margin_right:
16126 * @self: a #ClutterActor
16127 * @margin: the right margin
16129 * Sets the margin from the right of a #ClutterActor.
16134 clutter_actor_set_margin_right (ClutterActor *self,
16137 ClutterLayoutInfo *info;
16139 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16140 g_return_if_fail (margin >= 0.f);
16142 info = _clutter_actor_get_layout_info (self);
16144 if (info->margin.right == margin)
16147 info->margin.right = margin;
16149 clutter_actor_queue_relayout (self);
16151 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16155 * clutter_actor_get_margin_right:
16156 * @self: a #ClutterActor
16158 * Retrieves the right margin of a #ClutterActor.
16160 * Return value: the right margin
16165 clutter_actor_get_margin_right (ClutterActor *self)
16167 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16169 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16173 clutter_actor_set_background_color_internal (ClutterActor *self,
16174 const ClutterColor *color)
16176 ClutterActorPrivate *priv = self->priv;
16179 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16182 obj = G_OBJECT (self);
16184 priv->bg_color = *color;
16185 priv->bg_color_set = TRUE;
16187 clutter_actor_queue_redraw (self);
16189 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16190 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16194 * clutter_actor_set_background_color:
16195 * @self: a #ClutterActor
16196 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16199 * Sets the background color of a #ClutterActor.
16201 * The background color will be used to cover the whole allocation of the
16202 * actor. The default background color of an actor is transparent.
16204 * To check whether an actor has a background color, you can use the
16205 * #ClutterActor:background-color-set actor property.
16207 * The #ClutterActor:background-color property is animatable.
16212 clutter_actor_set_background_color (ClutterActor *self,
16213 const ClutterColor *color)
16215 ClutterActorPrivate *priv;
16217 GParamSpec *bg_color_pspec;
16219 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16221 obj = G_OBJECT (self);
16227 priv->bg_color_set = FALSE;
16228 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16229 clutter_actor_queue_redraw (self);
16233 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16234 if (clutter_actor_get_easing_duration (self) != 0)
16236 ClutterTransition *transition;
16238 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16239 if (transition == NULL)
16241 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16244 clutter_timeline_start (CLUTTER_TIMELINE (transition));
16247 _clutter_actor_update_transition (self, bg_color_pspec, color);
16249 clutter_actor_queue_redraw (self);
16252 clutter_actor_set_background_color_internal (self, color);
16256 * clutter_actor_get_background_color:
16257 * @self: a #ClutterActor
16258 * @color: (out caller-allocates): return location for a #ClutterColor
16260 * Retrieves the color set using clutter_actor_set_background_color().
16265 clutter_actor_get_background_color (ClutterActor *self,
16266 ClutterColor *color)
16268 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16269 g_return_if_fail (color != NULL);
16271 *color = self->priv->bg_color;
16275 * clutter_actor_get_previous_sibling:
16276 * @self: a #ClutterActor
16278 * Retrieves the sibling of @self that comes before it in the list
16279 * of children of @self's parent.
16281 * The returned pointer is only valid until the scene graph changes; it
16282 * is not safe to modify the list of children of @self while iterating
16285 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16290 clutter_actor_get_previous_sibling (ClutterActor *self)
16292 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16294 return self->priv->prev_sibling;
16298 * clutter_actor_get_next_sibling:
16299 * @self: a #ClutterActor
16301 * Retrieves the sibling of @self that comes after it in the list
16302 * of children of @self's parent.
16304 * The returned pointer is only valid until the scene graph changes; it
16305 * is not safe to modify the list of children of @self while iterating
16308 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16313 clutter_actor_get_next_sibling (ClutterActor *self)
16315 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16317 return self->priv->next_sibling;
16321 * clutter_actor_get_first_child:
16322 * @self: a #ClutterActor
16324 * Retrieves the first child of @self.
16326 * The returned pointer is only valid until the scene graph changes; it
16327 * is not safe to modify the list of children of @self while iterating
16330 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16335 clutter_actor_get_first_child (ClutterActor *self)
16337 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16339 return self->priv->first_child;
16343 * clutter_actor_get_last_child:
16344 * @self: a #ClutterActor
16346 * Retrieves the last child of @self.
16348 * The returned pointer is only valid until the scene graph changes; it
16349 * is not safe to modify the list of children of @self while iterating
16352 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16357 clutter_actor_get_last_child (ClutterActor *self)
16359 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16361 return self->priv->last_child;
16364 /* easy way to have properly named fields instead of the dummy ones
16365 * we use in the public structure
16367 typedef struct _RealActorIter
16369 ClutterActor *root; /* dummy1 */
16370 ClutterActor *current; /* dummy2 */
16371 gpointer padding_1; /* dummy3 */
16372 gint age; /* dummy4 */
16373 gpointer padding_2; /* dummy5 */
16377 * clutter_actor_iter_init:
16378 * @iter: a #ClutterActorIter
16379 * @root: a #ClutterActor
16381 * Initializes a #ClutterActorIter, which can then be used to iterate
16382 * efficiently over a section of the scene graph, and associates it
16385 * Modifying the scene graph section that contains @root will invalidate
16389 * ClutterActorIter iter;
16390 * ClutterActor *child;
16392 * clutter_actor_iter_init (&iter, container);
16393 * while (clutter_actor_iter_next (&iter, &child))
16395 * /* do something with child */
16402 clutter_actor_iter_init (ClutterActorIter *iter,
16403 ClutterActor *root)
16405 RealActorIter *ri = (RealActorIter *) iter;
16407 g_return_if_fail (iter != NULL);
16408 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16411 ri->current = NULL;
16412 ri->age = root->priv->age;
16416 * clutter_actor_iter_next:
16417 * @iter: a #ClutterActorIter
16418 * @child: (out): return location for a #ClutterActor
16420 * Advances the @iter and retrieves the next child of the root #ClutterActor
16421 * that was used to initialize the #ClutterActorIterator.
16423 * If the iterator can advance, this function returns %TRUE and sets the
16426 * If the iterator cannot advance, this function returns %FALSE, and
16427 * the contents of @child are undefined.
16429 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16434 clutter_actor_iter_next (ClutterActorIter *iter,
16435 ClutterActor **child)
16437 RealActorIter *ri = (RealActorIter *) iter;
16439 g_return_val_if_fail (iter != NULL, FALSE);
16440 g_return_val_if_fail (ri->root != NULL, FALSE);
16441 #ifndef G_DISABLE_ASSERT
16442 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16445 if (ri->current == NULL)
16446 ri->current = ri->root->priv->first_child;
16448 ri->current = ri->current->priv->next_sibling;
16451 *child = ri->current;
16453 return ri->current != NULL;
16457 * clutter_actor_iter_prev:
16458 * @iter: a #ClutterActorIter
16459 * @child: (out): return location for a #ClutterActor
16461 * Advances the @iter and retrieves the previous child of the root
16462 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16464 * If the iterator can advance, this function returns %TRUE and sets the
16467 * If the iterator cannot advance, this function returns %FALSE, and
16468 * the contents of @child are undefined.
16470 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16475 clutter_actor_iter_prev (ClutterActorIter *iter,
16476 ClutterActor **child)
16478 RealActorIter *ri = (RealActorIter *) iter;
16480 g_return_val_if_fail (iter != NULL, FALSE);
16481 g_return_val_if_fail (ri->root != NULL, FALSE);
16482 #ifndef G_DISABLE_ASSERT
16483 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16486 if (ri->current == NULL)
16487 ri->current = ri->root->priv->last_child;
16489 ri->current = ri->current->priv->prev_sibling;
16492 *child = ri->current;
16494 return ri->current != NULL;
16498 * clutter_actor_iter_remove:
16499 * @iter: a #ClutterActorIter
16501 * Safely removes the #ClutterActor currently pointer to by the iterator
16504 * This function can only be called after clutter_actor_iter_next() or
16505 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16506 * than once for the same actor.
16508 * This function will call clutter_actor_remove_child() internally.
16513 clutter_actor_iter_remove (ClutterActorIter *iter)
16515 RealActorIter *ri = (RealActorIter *) iter;
16518 g_return_if_fail (iter != NULL);
16519 g_return_if_fail (ri->root != NULL);
16520 #ifndef G_DISABLE_ASSERT
16521 g_return_if_fail (ri->age == ri->root->priv->age);
16523 g_return_if_fail (ri->current != NULL);
16529 ri->current = cur->priv->prev_sibling;
16531 clutter_actor_remove_child_internal (ri->root, cur,
16532 REMOVE_CHILD_DEFAULT_FLAGS);
16539 * clutter_actor_iter_destroy:
16540 * @iter: a #ClutterActorIter
16542 * Safely destroys the #ClutterActor currently pointer to by the iterator
16545 * This function can only be called after clutter_actor_iter_next() or
16546 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16547 * than once for the same actor.
16549 * This function will call clutter_actor_destroy() internally.
16554 clutter_actor_iter_destroy (ClutterActorIter *iter)
16556 RealActorIter *ri = (RealActorIter *) iter;
16559 g_return_if_fail (iter != NULL);
16560 g_return_if_fail (ri->root != NULL);
16561 #ifndef G_DISABLE_ASSERT
16562 g_return_if_fail (ri->age == ri->root->priv->age);
16564 g_return_if_fail (ri->current != NULL);
16570 ri->current = cur->priv->prev_sibling;
16572 clutter_actor_destroy (cur);
16578 static const ClutterAnimationInfo default_animation_info = {
16579 NULL, /* transitions */
16581 NULL, /* cur_state */
16585 clutter_animation_info_free (gpointer data)
16589 ClutterAnimationInfo *info = data;
16591 if (info->transitions != NULL)
16592 g_hash_table_unref (info->transitions);
16594 if (info->states != NULL)
16595 g_array_unref (info->states);
16597 g_slice_free (ClutterAnimationInfo, info);
16601 const ClutterAnimationInfo *
16602 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16604 const ClutterAnimationInfo *res;
16605 GObject *obj = G_OBJECT (self);
16607 res = g_object_get_qdata (obj, quark_actor_animation_info);
16611 return &default_animation_info;
16614 ClutterAnimationInfo *
16615 _clutter_actor_get_animation_info (ClutterActor *self)
16617 GObject *obj = G_OBJECT (self);
16618 ClutterAnimationInfo *res;
16620 res = g_object_get_qdata (obj, quark_actor_animation_info);
16623 res = g_slice_new (ClutterAnimationInfo);
16625 *res = default_animation_info;
16627 g_object_set_qdata_full (obj, quark_actor_animation_info,
16629 clutter_animation_info_free);
16635 ClutterTransition *
16636 _clutter_actor_get_transition (ClutterActor *actor,
16639 const ClutterAnimationInfo *info;
16641 info = _clutter_actor_get_animation_info_or_defaults (actor);
16643 if (info->transitions == NULL)
16646 return g_hash_table_lookup (info->transitions, pspec->name);
16649 typedef struct _TransitionClosure
16651 ClutterActor *actor;
16652 ClutterTransition *transition;
16654 gulong completed_id;
16655 } TransitionClosure;
16658 transition_closure_free (gpointer data)
16660 if (G_LIKELY (data != NULL))
16662 TransitionClosure *clos = data;
16664 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16665 g_free (clos->name);
16667 g_slice_free (TransitionClosure, clos);
16672 on_transition_completed (ClutterTransition *transition,
16673 TransitionClosure *clos)
16675 ClutterAnimationInfo *info;
16677 info = _clutter_actor_get_animation_info (clos->actor);
16679 /* this will take care of cleaning clos for us */
16680 g_hash_table_remove (info->transitions, clos->name);
16684 _clutter_actor_update_transition (ClutterActor *actor,
16688 TransitionClosure *clos;
16689 ClutterInterval *interval;
16690 const ClutterAnimationInfo *info;
16693 GValue initial = G_VALUE_INIT;
16694 GValue final = G_VALUE_INIT;
16695 char *error = NULL;
16697 info = _clutter_actor_get_animation_info_or_defaults (actor);
16699 if (info->transitions == NULL)
16702 clos = g_hash_table_lookup (info->transitions, pspec->name);
16706 va_start (var_args, pspec);
16708 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16710 g_value_init (&initial, ptype);
16711 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16715 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16718 g_critical ("%s: %s", G_STRLOC, error);
16723 interval = clutter_transition_get_interval (clos->transition);
16724 clutter_interval_set_initial_value (interval, &initial);
16725 clutter_interval_set_final_value (interval, &final);
16727 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16730 g_value_unset (&initial);
16731 g_value_unset (&final);
16737 * _clutter_actor_create_transition:
16738 * @actor: a #ClutterActor
16739 * @pspec: the property used for the transition
16740 * @...: initial and final state
16742 * Creates a #ClutterTransition for the property represented by @pspec.
16744 * Return value: a #ClutterTransition
16746 ClutterTransition *
16747 _clutter_actor_create_transition (ClutterActor *actor,
16751 ClutterAnimationInfo *info;
16752 ClutterTransition *res = NULL;
16753 gboolean call_restore = FALSE;
16754 TransitionClosure *clos;
16757 info = _clutter_actor_get_animation_info (actor);
16759 if (info->states == NULL)
16761 clutter_actor_save_easing_state (actor);
16762 call_restore = TRUE;
16765 if (info->transitions == NULL)
16766 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16768 transition_closure_free);
16770 va_start (var_args, pspec);
16772 clos = g_hash_table_lookup (info->transitions, pspec->name);
16775 ClutterInterval *interval;
16776 GValue initial = G_VALUE_INIT;
16777 GValue final = G_VALUE_INIT;
16781 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16783 G_VALUE_COLLECT_INIT (&initial, ptype,
16788 g_critical ("%s: %s", G_STRLOC, error);
16793 G_VALUE_COLLECT_INIT (&final, ptype,
16799 g_critical ("%s: %s", G_STRLOC, error);
16800 g_value_unset (&initial);
16805 interval = clutter_interval_new_with_values (ptype, &initial, &final);
16807 g_value_unset (&initial);
16808 g_value_unset (&final);
16810 res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
16813 clutter_transition_set_interval (res, interval);
16814 clutter_transition_set_remove_on_complete (res, TRUE);
16816 clutter_actor_add_transition (actor, pspec->name, res);
16819 res = clos->transition;
16823 clutter_actor_restore_easing_state (actor);
16831 * clutter_actor_add_transition:
16832 * @self: a #ClutterActor
16833 * @name: the name of the transition to add
16834 * @transition: the #ClutterTransition to add
16836 * Adds a @transition to the #ClutterActor's list of animations.
16838 * The @name string is a per-actor unique identifier of the @transition: only
16839 * one #ClutterTransition can be associated to the specified @name.
16841 * The @transition will be given the easing duration, mode, and delay
16842 * associated to the actor's current easing state; it is possible to modify
16843 * these values after calling clutter_actor_add_transition().
16845 * This function is usually called implicitly when modifying an animatable
16851 clutter_actor_add_transition (ClutterActor *self,
16853 ClutterTransition *transition)
16855 ClutterTimeline *timeline;
16856 TransitionClosure *clos;
16857 ClutterAnimationInfo *info;
16859 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16860 g_return_if_fail (name != NULL);
16861 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
16863 info = _clutter_actor_get_animation_info (self);
16865 if (info->cur_state == NULL)
16867 g_warning ("No easing state is defined for the actor '%s'; you "
16868 "must call clutter_actor_save_easing_state() before "
16869 "calling clutter_actor_add_transition().",
16870 _clutter_actor_get_debug_name (self));
16874 if (info->transitions == NULL)
16875 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
16877 transition_closure_free);
16879 if (g_hash_table_lookup (info->transitions, name) != NULL)
16881 g_warning ("A transition with name '%s' already exists for "
16884 _clutter_actor_get_debug_name (self));
16888 timeline = CLUTTER_TIMELINE (transition);
16890 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
16891 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
16892 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
16894 clos = g_slice_new (TransitionClosure);
16895 clos->actor = self;
16896 clos->transition = transition;
16897 clos->name = g_strdup (name);
16898 clos->completed_id = g_signal_connect (timeline, "completed",
16899 G_CALLBACK (on_transition_completed),
16902 g_hash_table_insert (info->transitions, clos->name, clos);
16906 * clutter_actor_remove_transition:
16907 * @self: a #ClutterActor
16908 * @name: the name of the transition to remove
16910 * Removes the transition stored inside a #ClutterActor using @name
16916 clutter_actor_remove_transition (ClutterActor *self,
16919 const ClutterAnimationInfo *info;
16921 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16922 g_return_if_fail (name != NULL);
16924 info = _clutter_actor_get_animation_info_or_defaults (self);
16926 if (info->transitions == NULL)
16929 g_hash_table_remove (info->transitions, name);
16933 * clutter_actor_remove_all_transitions:
16934 * @self: a #ClutterActor
16936 * Removes all transitions associated to @self.
16941 clutter_actor_remove_all_transitions (ClutterActor *self)
16943 const ClutterAnimationInfo *info;
16945 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16947 info = _clutter_actor_get_animation_info_or_defaults (self);
16948 if (info->transitions == NULL)
16951 g_hash_table_remove_all (info->transitions);
16955 * clutter_actor_set_easing_duration:
16956 * @self: a #ClutterActor
16957 * @msecs: the duration of the easing, or %NULL
16959 * Sets the duration of the tweening for animatable properties
16960 * of @self for the current easing state.
16962 * Calling this function will implicitly call
16963 * clutter_actor_save_easing_state() if no previous call to
16964 * that function was made.
16969 clutter_actor_set_easing_duration (ClutterActor *self,
16972 ClutterAnimationInfo *info;
16974 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16976 info = _clutter_actor_get_animation_info (self);
16978 if (info->states == NULL)
16979 clutter_actor_save_easing_state (self);
16981 if (info->cur_state->easing_duration != msecs)
16982 info->cur_state->easing_duration = msecs;
16986 * clutter_actor_get_easing_duration:
16987 * @self: a #ClutterActor
16989 * Retrieves the duration of the tweening for animatable
16990 * properties of @self for the current easing state.
16992 * Return value: the duration of the tweening, in milliseconds
16997 clutter_actor_get_easing_duration (ClutterActor *self)
16999 const ClutterAnimationInfo *info;
17001 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17003 info = _clutter_actor_get_animation_info_or_defaults (self);
17005 if (info->cur_state != NULL)
17006 return info->cur_state->easing_duration;
17012 * clutter_actor_set_easing_mode:
17013 * @self: a #ClutterActor
17014 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17016 * Sets the easing mode for the tweening of animatable properties
17019 * Calling this function will implicitly call
17020 * clutter_actor_save_easing_state() if no previous calls to
17021 * that function were made.
17026 clutter_actor_set_easing_mode (ClutterActor *self,
17027 ClutterAnimationMode mode)
17029 ClutterAnimationInfo *info;
17031 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17032 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17033 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17035 info = _clutter_actor_get_animation_info (self);
17037 if (info->states == NULL)
17038 clutter_actor_save_easing_state (self);
17040 if (info->cur_state->easing_mode != mode)
17041 info->cur_state->easing_mode = mode;
17045 * clutter_actor_get_easing_mode:
17046 * @self: a #ClutterActor
17048 * Retrieves the easing mode for the tweening of animatable properties
17049 * of @self for the current easing state.
17051 * Return value: an easing mode
17055 ClutterAnimationMode
17056 clutter_actor_get_easing_mode (ClutterActor *self)
17058 const ClutterAnimationInfo *info;
17060 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17062 info = _clutter_actor_get_animation_info_or_defaults (self);
17064 if (info->cur_state != NULL)
17065 return info->cur_state->easing_mode;
17067 return CLUTTER_EASE_OUT_CUBIC;
17071 * clutter_actor_set_easing_delay:
17072 * @self: a #ClutterActor
17073 * @msecs: the delay before the start of the tweening, in milliseconds
17075 * Sets the delay that should be applied before tweening animatable
17078 * Calling this function will implicitly call
17079 * clutter_actor_save_easing_state() if no previous calls to
17080 * that function were made.
17085 clutter_actor_set_easing_delay (ClutterActor *self,
17088 ClutterAnimationInfo *info;
17090 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17092 info = _clutter_actor_get_animation_info (self);
17094 if (info->states == NULL)
17095 clutter_actor_save_easing_state (self);
17097 if (info->cur_state->easing_delay != msecs)
17098 info->cur_state->easing_delay = msecs;
17102 * clutter_actor_get_easing_delay:
17103 * @self: a #ClutterActor
17105 * Retrieves the delay that should be applied when tweening animatable
17108 * Return value: a delay, in milliseconds
17113 clutter_actor_get_easing_delay (ClutterActor *self)
17115 const ClutterAnimationInfo *info;
17117 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17119 info = _clutter_actor_get_animation_info_or_defaults (self);
17121 if (info->cur_state != NULL)
17122 return info->cur_state->easing_delay;
17128 * clutter_actor_get_transition:
17129 * @self: a #ClutterActor
17130 * @name: the name of the transition
17132 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17133 * transition @name.
17135 * Transitions created for animatable properties use the name of the
17136 * property itself, for instance the code below:
17139 * clutter_actor_set_easing_duration (actor, 1000);
17140 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17142 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17143 * g_signal_connect (transition, "completed",
17144 * G_CALLBACK (on_transition_complete),
17148 * will call the <function>on_transition_complete</function> callback when
17149 * the transition is complete.
17151 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17152 * was found to match the passed name; the returned instance is owned
17153 * by Clutter and it should not be freed
17157 ClutterTransition *
17158 clutter_actor_get_transition (ClutterActor *self,
17161 TransitionClosure *clos;
17162 const ClutterAnimationInfo *info;
17164 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17165 g_return_val_if_fail (name != NULL, NULL);
17167 info = _clutter_actor_get_animation_info_or_defaults (self);
17169 if (info->transitions == NULL)
17172 clos = g_hash_table_lookup (info->transitions, name);
17176 return clos->transition;
17180 * clutter_actor_save_easing_state:
17181 * @self: a #ClutterActor
17183 * Saves the current easing state for animatable properties, and creates
17184 * a new state with the default values for easing mode and duration.
17189 clutter_actor_save_easing_state (ClutterActor *self)
17191 ClutterAnimationInfo *info;
17194 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17196 info = _clutter_actor_get_animation_info (self);
17198 if (info->states == NULL)
17199 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17201 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17202 new_state.easing_duration = 250;
17203 new_state.easing_delay = 0;
17205 g_array_append_val (info->states, new_state);
17207 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17211 * clutter_actor_restore_easing_state:
17212 * @self: a #ClutterActor
17214 * Restores the easing state as it was prior to a call to
17215 * clutter_actor_save_easing_state().
17220 clutter_actor_restore_easing_state (ClutterActor *self)
17222 ClutterAnimationInfo *info;
17224 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17226 info = _clutter_actor_get_animation_info (self);
17228 if (info->states == NULL)
17230 g_critical ("The function clutter_actor_restore_easing_state() has "
17231 "called without a previous call to "
17232 "clutter_actor_save_easing_state().");
17236 g_array_remove_index (info->states, info->states->len - 1);
17237 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);