4 * An OpenGL based 'interactive canvas' library.
6 * Authored By Matthew Allum <mallum@openedhand.com>
8 * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9 * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
26 * SECTION:clutter-actor
27 * @short_description: Base abstract class for all visual stage actors.
29 * The ClutterActor class is the basic element of the scene graph in Clutter,
30 * and it encapsulates the position, size, and transformations of a node in
33 * <refsect2 id="ClutterActor-transformations">
34 * <title>Actor transformations</title>
35 * <para>Each actor can be transformed using methods like
36 * clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37 * in which the transformations are applied is decided by Clutter and it is
38 * the following:</para>
40 * <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41 * <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42 * <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43 * <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44 * <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45 * <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46 * <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
50 * <refsect2 id="ClutterActor-geometry">
51 * <title>Modifying an actor's geometry</title>
52 * <para>Each actor has a bounding box, called #ClutterActor:allocation
53 * which is either set by its parent or explicitly through the
54 * clutter_actor_set_position() and clutter_actor_set_size() methods.
55 * Each actor also has an implicit preferred size.</para>
56 * <para>An actor’s preferred size can be defined by any subclass by
57 * overriding the #ClutterActorClass.get_preferred_width() and the
58 * #ClutterActorClass.get_preferred_height() virtual functions, or it can
59 * be explicitly set by using clutter_actor_set_width() and
60 * clutter_actor_set_height().</para>
61 * <para>An actor’s position can be set explicitly by using
62 * clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63 * relative to the origin of the actor’s parent.</para>
66 * <refsect2 id="ClutterActor-children">
67 * <title>Managing actor children</title>
68 * <para>Each actor can have multiple children, by calling
69 * clutter_actor_add_child() to add a new child actor, and
70 * clutter_actor_remove_child() to remove an existing child. #ClutterActor
71 * will hold a reference on each child actor, which will be released when
72 * the child is removed from its parent, or destroyed using
73 * clutter_actor_destroy().</para>
74 * <informalexample><programlisting>
75 * ClutterActor *actor = clutter_actor_new ();
77 * /* set the bounding box of the actor */
78 * clutter_actor_set_position (actor, 0, 0);
79 * clutter_actor_set_size (actor, 480, 640);
81 * /* set the background color of the actor */
82 * clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
84 * /* set the bounding box of the child, relative to the parent */
85 * ClutterActor *child = clutter_actor_new ();
86 * clutter_actor_set_position (child, 20, 20);
87 * clutter_actor_set_size (child, 80, 240);
89 * /* set the background color of the child */
90 * clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
92 * /* add the child to the actor */
93 * clutter_actor_add_child (actor, child);
94 * </programlisting></informalexample>
95 * <para>Children can be inserted at a given index, or above and below
96 * another child actor. The order of insertion determines the order of the
97 * children when iterating over them. Iterating over children is performed
98 * by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99 * clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100 * also possible to retrieve a list of children by using
101 * clutter_actor_get_children(), as well as retrieving a specific child at a
102 * given index by using clutter_actor_get_child_at_index().</para>
103 * <para>If you need to track additions of children to a #ClutterActor, use
104 * the #ClutterContainer::actor-added signal; similarly, to track removals
105 * of children from a ClutterActor, use the #ClutterContainer::actor-removed
107 * <informalexample><programlisting>
108 * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109 * <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
111 * </programlisting></informalexample>
112 * <figure id="actor-example-image">
113 * <title>Actors</title>
114 * <graphic fileref="actor-example.png" format="PNG"/>
118 * <refsect2 id="ClutterActor-painting">
119 * <title>Painting an actor</title>
120 * <para>There are three ways to paint an actor:</para>
122 * <listitem><para>set a delegate #ClutterContent as the value for the
123 * #ClutterActor:content property of the actor;</para></listitem>
124 * <listitem><para>subclass #ClutterActor and override the
125 * #ClutterActorClass.paint_node() virtual function;</para></listitem>
126 * <listitem><para>subclass #ClutterActor and override the
127 * #ClutterActorClass.paint() virtual function.</para></listitem>
130 * <title>Setting the Content property</title>
131 * <para>A #ClutterContent is a delegate object that takes over the
132 * painting operation of one, or more actors. The #ClutterContent
133 * painting will be performed on top of the #ClutterActor:background-color
134 * of the actor, and before calling the #ClutterActorClass.paint_node()
135 * virtual function.</para>
136 * <informalexample><programlisting>
137 * ClutterActor *actor = clutter_actor_new ();
139 * /* set the bounding box */
140 * clutter_actor_set_position (actor, 50, 50);
141 * clutter_actor_set_size (actor, 100, 100);
143 * /* set the content; the image_content variable is set elsewhere */
144 * clutter_actor_set_content (actor, image_content);
145 * </programlisting></informalexample>
148 * <title>Overriding the paint_node virtual function</title>
149 * <para>The #ClutterActorClass.paint_node() virtual function is invoked
150 * whenever an actor needs to be painted. The implementation of the
151 * virtual function must only paint the contents of the actor itself,
152 * and not the contents of its children, if the actor has any.</para>
153 * <para>The #ClutterPaintNode passed to the virtual function is the
154 * local root of the render tree; any node added to it will be
155 * rendered at the correct position, as defined by the actor's
156 * #ClutterActor:allocation.</para>
157 * <informalexample><programlisting>
159 * my_actor_paint_node (ClutterActor *actor,
160 * ClutterPaintNode *root)
162 * ClutterPaintNode *node;
163 * ClutterActorBox box;
165 * /* where the content of the actor should be painted */
166 * clutter_actor_get_allocation_box (actor, &box);
168 * /* the cogl_texture variable is set elsewhere */
169 * node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170 * CLUTTER_SCALING_FILTER_BILINEAR,
171 * CLUTTER_SCALING_FILTER_LINEAR);
173 * /* paint the content of the node using the allocation */
174 * clutter_paint_node_add_rectangle (node, &box);
176 * /* add the node, and transfer ownership */
177 * clutter_paint_node_add_child (root, node);
178 * clutter_paint_node_unref (node);
180 * </programlisting></informalexample>
183 * <title>Overriding the paint virtual function</title>
184 * <para>The #ClutterActorClass.paint() virtual function is invoked
185 * when the #ClutterActor::paint signal is emitted, and after the other
186 * signal handlers have been invoked. Overriding the paint virtual
187 * function gives total control to the paint sequence of the actor
188 * itself, including the children of the actor, if any.</para>
189 * <warning><para>It is strongly discouraged to override the
190 * #ClutterActorClass.paint() virtual function, as well as connecting
191 * to the #ClutterActor::paint signal. These hooks into the paint
192 * sequence are considered legacy, and will be removed when the Clutter
193 * API changes.</para></warning>
197 * <refsect2 id="ClutterActor-events">
198 * <title>Handling events on an actor</title>
199 * <para>A #ClutterActor can receive and handle input device events, for
200 * instance pointer events and key events, as long as its
201 * #ClutterActor:reactive property is set to %TRUE.</para>
202 * <para>Once an actor has been determined to be the source of an event,
203 * Clutter will traverse the scene graph from the top-level actor towards the
204 * event source, emitting the #ClutterActor::captured-event signal on each
205 * ancestor until it reaches the source; this phase is also called
206 * <emphasis>the capture phase</emphasis>. If the event propagation was not
207 * stopped, the graph is walked backwards, from the source actor to the
208 * top-level, and the #ClutterActor::event signal, along with other event
209 * signals if needed, is emitted; this phase is also called <emphasis>the
210 * bubble phase</emphasis>. At any point of the signal emission, signal
211 * handlers can stop the propagation through the scene graph by returning
212 * %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213 * returning %CLUTTER_EVENT_PROPAGATE.</para>
216 * <refsect2 id="ClutterActor-subclassing">
217 * <title>Implementing an actor</title>
218 * <para>Careful consideration should be given when deciding to implement
219 * a #ClutterActor sub-class. It is generally recommended to implement a
220 * sub-class of #ClutterActor only for actors that should be used as leaf
221 * nodes of a scene graph.</para>
222 * <para>If your actor should be painted in a custom way, you should
223 * override the #ClutterActor::paint signal class handler. You can either
224 * opt to chain up to the parent class implementation or decide to fully
225 * override the default paint implementation; Clutter will set up the
226 * transformations and clip regions prior to emitting the #ClutterActor::paint
228 * <para>By overriding the #ClutterActorClass.get_preferred_width() and
229 * #ClutterActorClass.get_preferred_height() virtual functions it is
230 * possible to change or provide the preferred size of an actor; similarly,
231 * by overriding the #ClutterActorClass.allocate() virtual function it is
232 * possible to control the layout of the children of an actor. Make sure to
233 * always chain up to the parent implementation of the
234 * #ClutterActorClass.allocate() virtual function.</para>
235 * <para>In general, it is strongly encouraged to use delegation and
236 * composition instead of direct subclassing.</para>
239 * <refsect2 id="ClutterActor-script">
240 * <title>ClutterActor custom properties for #ClutterScript</title>
241 * <para>#ClutterActor defines a custom "rotation" property which
242 * allows a short-hand description of the rotations to be applied
243 * to an actor.</para>
244 * <para>The syntax of the "rotation" property is the following:</para>
248 * { "<axis>" : [ <angle>, [ <center> ] ] }
252 * <para>where the <emphasis>axis</emphasis> is the name of an enumeration
253 * value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
254 * floating point value representing the rotation angle on the given axis,
256 * <para>The <emphasis>center</emphasis> array is optional, and if present
257 * it must contain the center of rotation as described by two coordinates:
258 * Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
260 * <para>#ClutterActor will also parse every positional and dimensional
261 * property defined as a string through clutter_units_from_string(); you
262 * should read the documentation for the #ClutterUnits parser format for
263 * the valid units and syntax.</para>
266 * <refsect2 id="ClutterActor-animating">
267 * <title>Custom animatable properties</title>
268 * <para>#ClutterActor allows accessing properties of #ClutterAction
269 * and #ClutterConstraint instances associated to an actor instance
270 * for animation purposes.</para>
271 * <para>In order to access a specific #ClutterAction or a #ClutterConstraint
272 * property it is necessary to set the #ClutterActorMeta:name property on the
273 * given action or constraint.</para>
274 * <para>The property can be accessed using the following syntax:</para>
277 * @<section>.<meta-name>.<property-name>
280 * <para>The initial <emphasis>@</emphasis> is mandatory.</para>
281 * <para>The <emphasis>section</emphasis> fragment can be one between
282 * "actions", "constraints" and "effects".</para>
283 * <para>The <emphasis>meta-name</emphasis> fragment is the name of the
284 * action or constraint, as specified by the #ClutterActorMeta:name
286 * <para>The <emphasis>property-name</emphasis> fragment is the name of the
287 * action or constraint property to be animated.</para>
288 * <para>The example below animates a #ClutterBindConstraint applied to an
289 * actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
290 * a binding constraint for the <emphasis>origin</emphasis> actor, and in
291 * its initial state is fully transparent and overlapping the actor to
292 * which is bound to. </para>
293 * <informalexample><programlisting>
294 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
295 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
296 * clutter_actor_add_constraint (rect, constraint);
298 * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
299 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
300 * clutter_actor_add_constraint (rect, constraint);
302 * clutter_actor_set_reactive (rect, TRUE);
303 * clutter_actor_set_opacity (rect, 0);
305 * g_signal_connect (rect, "button-press-event",
306 * G_CALLBACK (on_button_press),
308 * </programlisting></informalexample>
309 * <para>On button press, the rectangle "slides" from behind the actor to
310 * which is bound to, using the #ClutterBindConstraint:offset property and
311 * the #ClutterActor:opacity property.</para>
312 * <informalexample><programlisting>
313 * float new_offset = clutter_actor_get_width (origin) + h_padding;
315 * clutter_actor_animate (rect, CLUTTER_EASE_OUT_CUBIC, 500,
317 * "@constraints.bind-x.offset", new_offset,
319 * </programlisting></informalexample>
322 * <refsect2 id="ClutterActor-animatable-properties">
323 * <title>Animatable properties</title>
324 * <para>Certain properties on #ClutterActor are marked as "animatable";
325 * these properties will be automatically tweened between the current
326 * value and the new value when one is set.</para>
327 * <para>For backward compatibility, animatable properties will only be
328 * tweened if the easing duration is greater than 0, or if a new easing
329 * state is set, for instance the following example:</para>
330 * <informalexample><programlisting>
331 * clutter_actor_save_easing_state (actor);
332 * clutter_actor_set_position (actor, 200, 200);
333 * clutter_actor_restore_easing_state (actor);
334 * </programlisting></informalexample>
335 * <para>will tween the actor to the (200, 200) coordinates using the default
336 * easing mode and duration of a new easing state. The example above is
337 * equivalent to the following code:</para>
338 * <informalexample><programlisting>
339 * clutter_actor_set_easing_mode (actor, CLUTTER_EASE_OUT_CUBIC);
340 * clutter_actor_set_easing_duration (actor, 250);
341 * clutter_actor_set_position (actor, 200, 200);
342 * clutter_actor_restore_easing_state (actor);
343 * </programlisting></informalexample>
344 * <para>It is possible to nest easing states to tween animatable
345 * properties using different modes and durations, for instance:</para>
346 * <informalexample><programlisting>
347 * clutter_actor_save_easing_state (actor); /* outer state */
349 * /* set the duration of the animation to 2 seconds and change position */
350 * clutter_actor_set_easing_duration (actor, 2000);
351 * clutter_actor_set_position (actor, 0, 0);
353 * clutter_actor_save_easing_state (actor); /* inner state */
355 * /* set the duration of the animation to 5 seconds and change depth and opacity */
356 * clutter_actor_set_easing_duration (actor, 5000);
357 * clutter_actor_set_depth (actor, 200);
358 * clutter_actor_set_opacity (actor, 0);
360 * clutter_actor_restore_easing_state (actor);
362 * clutter_actor_restore_easing_state (actor);
363 * </programlisting></informalexample>
368 * CLUTTER_ACTOR_IS_MAPPED:
369 * @a: a #ClutterActor
371 * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
373 * The mapped state is set when the actor is visible and all its parents up
374 * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
376 * This check can be used to see if an actor is going to be painted, as only
377 * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
379 * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
380 * not be checked directly; instead, the recommended usage is to connect a
381 * handler on the #GObject::notify signal for the #ClutterActor:mapped
382 * property of #ClutterActor, and check the presence of
383 * the %CLUTTER_ACTOR_MAPPED flag on state changes.
385 * It is also important to note that Clutter may delay the changes of
386 * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
387 * limitations, or during the reparenting of an actor, to optimize
388 * unnecessary (and potentially expensive) state changes.
394 * CLUTTER_ACTOR_IS_REALIZED:
395 * @a: a #ClutterActor
397 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
399 * The realized state has an actor-dependant interpretation. If an
400 * actor wants to delay allocating resources until it is attached to a
401 * stage, it may use the realize state to do so. However it is
402 * perfectly acceptable for an actor to allocate Cogl resources before
403 * being realized because there is only one drawing context used by Clutter
404 * so any resources will work on any stage. If an actor is mapped it
405 * must also be realized, but an actor can be realized and unmapped
406 * (this is so hiding an actor temporarily doesn't do an expensive
407 * unrealize/realize).
409 * To be realized an actor must be inside a stage, and all its parents
416 * CLUTTER_ACTOR_IS_VISIBLE:
417 * @a: a #ClutterActor
419 * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
420 * Equivalent to the ClutterActor::visible object property.
422 * Note that an actor is only painted onscreen if it's mapped, which
423 * means it's visible, and all its parents are visible, and one of the
424 * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
430 * CLUTTER_ACTOR_IS_REACTIVE:
431 * @a: a #ClutterActor
433 * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
435 * Only reactive actors will receive event-related signals.
446 #include <gobject/gvaluecollector.h>
448 #include <cogl/cogl.h>
450 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
451 #define CLUTTER_ENABLE_EXPERIMENTAL_API
453 #include "clutter-actor-private.h"
455 #include "clutter-action.h"
456 #include "clutter-actor-meta-private.h"
457 #include "clutter-animatable.h"
458 #include "clutter-color-static.h"
459 #include "clutter-color.h"
460 #include "clutter-constraint.h"
461 #include "clutter-container.h"
462 #include "clutter-content-private.h"
463 #include "clutter-debug.h"
464 #include "clutter-effect-private.h"
465 #include "clutter-enum-types.h"
466 #include "clutter-fixed-layout.h"
467 #include "clutter-flatten-effect.h"
468 #include "clutter-interval.h"
469 #include "clutter-main.h"
470 #include "clutter-marshal.h"
471 #include "clutter-paint-nodes.h"
472 #include "clutter-paint-node-private.h"
473 #include "clutter-paint-volume-private.h"
474 #include "clutter-private.h"
475 #include "clutter-profile.h"
476 #include "clutter-property-transition.h"
477 #include "clutter-scriptable.h"
478 #include "clutter-script-private.h"
479 #include "clutter-stage-private.h"
480 #include "clutter-timeline.h"
481 #include "clutter-transition.h"
482 #include "clutter-units.h"
484 #include "deprecated/clutter-actor.h"
485 #include "deprecated/clutter-behaviour.h"
486 #include "deprecated/clutter-container.h"
488 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
489 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
491 /* Internal enum used to control mapped state update. This is a hint
492 * which indicates when to do something other than just enforce
496 MAP_STATE_CHECK, /* just enforce invariants. */
497 MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
498 * used when about to unparent.
500 MAP_STATE_MAKE_MAPPED, /* set mapped, error if invariants not met;
501 * used to set mapped on toplevels.
503 MAP_STATE_MAKE_UNMAPPED /* set unmapped, even if parent is mapped,
504 * used just before unmapping parent.
508 /* 3 entries should be a good compromise, few layout managers
509 * will ask for 3 different preferred size in each allocation cycle */
510 #define N_CACHED_SIZE_REQUESTS 3
512 struct _ClutterActorPrivate
515 ClutterRequestMode request_mode;
517 /* our cached size requests for different width / height */
518 SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
519 SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
521 /* An age of 0 means the entry is not set */
522 guint cached_height_age;
523 guint cached_width_age;
525 /* the bounding box of the actor, relative to the parent's
528 ClutterActorBox allocation;
529 ClutterAllocationFlags allocation_flags;
531 /* clip, in actor coordinates */
532 cairo_rectangle_t clip;
534 /* the cached transformation matrix; see apply_transform() */
535 CoglMatrix transform;
538 gint opacity_override;
540 ClutterOffscreenRedirect offscreen_redirect;
542 /* This is an internal effect used to implement the
543 offscreen-redirect property */
544 ClutterEffect *flatten_effect;
547 ClutterActor *parent;
548 ClutterActor *prev_sibling;
549 ClutterActor *next_sibling;
550 ClutterActor *first_child;
551 ClutterActor *last_child;
555 /* tracks whenever the children of an actor are changed; the
556 * age is incremented by 1 whenever an actor is added or
557 * removed. the age is not incremented when the first or the
558 * last child pointers are changed, or when grandchildren of
559 * an actor are changed.
563 gchar *name; /* a non-unique name, used for debugging */
564 guint32 id; /* unique id, used for backward compatibility */
566 gint32 pick_id; /* per-stage unique id, used for picking */
568 /* a back-pointer to the Pango context that we can use
569 * to create pre-configured PangoLayout
571 PangoContext *pango_context;
573 /* the text direction configured for this child - either by
574 * application code, or by the actor's parent
576 ClutterTextDirection text_direction;
578 /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
582 ClutterMetaGroup *actions;
583 ClutterMetaGroup *constraints;
584 ClutterMetaGroup *effects;
586 /* delegate object used to allocate the children of this actor */
587 ClutterLayoutManager *layout_manager;
589 /* delegate object used to paint the contents of this actor */
590 ClutterContent *content;
592 ClutterContentGravity content_gravity;
593 ClutterScalingFilter min_filter;
594 ClutterScalingFilter mag_filter;
596 /* used when painting, to update the paint volume */
597 ClutterEffect *current_effect;
599 /* This is used to store an effect which needs to be redrawn. A
600 redraw can be queued to start from a particular effect. This is
601 used by parametrised effects that can cache an image of the
602 actor. If a parameter of the effect changes then it only needs to
603 redraw the cached image, not the actual actor. The pointer is
604 only valid if is_dirty == TRUE. If the pointer is NULL then the
605 whole actor is dirty. */
606 ClutterEffect *effect_to_redraw;
608 /* This is used when painting effects to implement the
609 clutter_actor_continue_paint() function. It points to the node in
610 the list of effects that is next in the chain */
611 const GList *next_effect_to_paint;
613 ClutterPaintVolume paint_volume;
615 /* NB: This volume isn't relative to this actor, it is in eye
616 * coordinates so that it can remain valid after the actor changes.
618 ClutterPaintVolume last_paint_volume;
620 ClutterStageQueueRedrawEntry *queue_redraw_entry;
622 ClutterColor bg_color;
626 /* fixed position and sizes */
627 guint position_set : 1;
628 guint min_width_set : 1;
629 guint min_height_set : 1;
630 guint natural_width_set : 1;
631 guint natural_height_set : 1;
632 /* cached request is invalid (implies allocation is too) */
633 guint needs_width_request : 1;
634 /* cached request is invalid (implies allocation is too) */
635 guint needs_height_request : 1;
636 /* cached allocation is invalid (request has changed, probably) */
637 guint needs_allocation : 1;
638 guint show_on_set_parent : 1;
640 guint clip_to_allocation : 1;
641 guint enable_model_view_transform : 1;
642 guint enable_paint_unmapped : 1;
643 guint has_pointer : 1;
644 guint propagated_one_redraw : 1;
645 guint paint_volume_valid : 1;
646 guint last_paint_volume_valid : 1;
647 guint in_clone_paint : 1;
648 guint transform_valid : 1;
649 /* This is TRUE if anything has queued a redraw since we were last
650 painted. In this case effect_to_redraw will point to an effect
651 the redraw was queued from or it will be NULL if the redraw was
652 queued without an effect. */
654 guint bg_color_set : 1;
663 /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
664 * when set they force a size request, when gotten they
665 * get the allocation if the allocation is valid, and the
673 /* Then the rest of these size-related properties are the "actual"
674 * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
679 PROP_FIXED_POSITION_SET,
688 PROP_NATURAL_WIDTH_SET,
691 PROP_NATURAL_HEIGHT_SET,
695 /* Allocation properties are read-only */
702 PROP_CLIP_TO_ALLOCATION,
706 PROP_OFFSCREEN_REDIRECT,
719 PROP_ROTATION_ANGLE_X,
720 PROP_ROTATION_ANGLE_Y,
721 PROP_ROTATION_ANGLE_Z,
722 PROP_ROTATION_CENTER_X,
723 PROP_ROTATION_CENTER_Y,
724 PROP_ROTATION_CENTER_Z,
725 /* This property only makes sense for the z rotation because the
726 others would depend on the actor having a size along the
728 PROP_ROTATION_CENTER_Z_GRAVITY,
734 PROP_SHOW_ON_SET_PARENT,
752 PROP_BACKGROUND_COLOR,
753 PROP_BACKGROUND_COLOR_SET,
759 PROP_CONTENT_GRAVITY,
761 PROP_MINIFICATION_FILTER,
762 PROP_MAGNIFICATION_FILTER,
767 static GParamSpec *obj_props[PROP_LAST];
786 BUTTON_RELEASE_EVENT,
798 static guint actor_signals[LAST_SIGNAL] = { 0, };
800 static void clutter_container_iface_init (ClutterContainerIface *iface);
801 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
802 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
803 static void atk_implementor_iface_init (AtkImplementorIface *iface);
805 /* These setters are all static for now, maybe they should be in the
806 * public API, but they are perhaps obscure enough to leave only as
809 static void clutter_actor_set_min_width (ClutterActor *self,
811 static void clutter_actor_set_min_height (ClutterActor *self,
813 static void clutter_actor_set_natural_width (ClutterActor *self,
814 gfloat natural_width);
815 static void clutter_actor_set_natural_height (ClutterActor *self,
816 gfloat natural_height);
817 static void clutter_actor_set_min_width_set (ClutterActor *self,
818 gboolean use_min_width);
819 static void clutter_actor_set_min_height_set (ClutterActor *self,
820 gboolean use_min_height);
821 static void clutter_actor_set_natural_width_set (ClutterActor *self,
822 gboolean use_natural_width);
823 static void clutter_actor_set_natural_height_set (ClutterActor *self,
824 gboolean use_natural_height);
825 static void clutter_actor_update_map_state (ClutterActor *self,
826 MapStateChange change);
827 static void clutter_actor_unrealize_not_hiding (ClutterActor *self);
829 /* Helper routines for managing anchor coords */
830 static void clutter_anchor_coord_get_units (ClutterActor *self,
831 const AnchorCoord *coord,
835 static void clutter_anchor_coord_set_units (AnchorCoord *coord,
840 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
841 static void clutter_anchor_coord_set_gravity (AnchorCoord *coord,
842 ClutterGravity gravity);
844 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
846 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
848 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
849 ClutterActor *ancestor,
852 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
854 static guint8 clutter_actor_get_paint_opacity_internal (ClutterActor *self);
856 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
857 const ClutterColor *color);
859 static void on_layout_manager_changed (ClutterLayoutManager *manager,
862 /* Helper macro which translates by the anchor coord, applies the
863 given transformation and then translates back */
864 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform) G_STMT_START { \
865 gfloat _tx, _ty, _tz; \
866 clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz); \
867 cogl_matrix_translate ((m), _tx, _ty, _tz); \
869 cogl_matrix_translate ((m), -_tx, -_ty, -_tz); } G_STMT_END
871 static GQuark quark_shader_data = 0;
872 static GQuark quark_actor_layout_info = 0;
873 static GQuark quark_actor_transform_info = 0;
874 static GQuark quark_actor_animation_info = 0;
876 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
878 G_TYPE_INITIALLY_UNOWNED,
879 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
880 clutter_container_iface_init)
881 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
882 clutter_scriptable_iface_init)
883 G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
884 clutter_animatable_iface_init)
885 G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
886 atk_implementor_iface_init));
889 * clutter_actor_get_debug_name:
890 * @actor: a #ClutterActor
892 * Retrieves a printable name of @actor for debugging messages
894 * Return value: a string with a printable name
897 _clutter_actor_get_debug_name (ClutterActor *actor)
899 return actor->priv->name != NULL ? actor->priv->name
900 : G_OBJECT_TYPE_NAME (actor);
903 #ifdef CLUTTER_ENABLE_DEBUG
904 /* XXX - this is for debugging only, remove once working (or leave
905 * in only in some debug mode). Should leave it for a little while
906 * until we're confident in the new map/realize/visible handling.
909 clutter_actor_verify_map_state (ClutterActor *self)
911 ClutterActorPrivate *priv = self->priv;
913 if (CLUTTER_ACTOR_IS_REALIZED (self))
915 /* all bets are off during reparent when we're potentially realized,
916 * but should not be according to invariants
918 if (!CLUTTER_ACTOR_IN_REPARENT (self))
920 if (priv->parent == NULL)
922 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
926 g_warning ("Realized non-toplevel actor '%s' should "
928 _clutter_actor_get_debug_name (self));
930 else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
932 g_warning ("Realized actor %s has an unrealized parent %s",
933 _clutter_actor_get_debug_name (self),
934 _clutter_actor_get_debug_name (priv->parent));
939 if (CLUTTER_ACTOR_IS_MAPPED (self))
941 if (!CLUTTER_ACTOR_IS_REALIZED (self))
942 g_warning ("Actor '%s' is mapped but not realized",
943 _clutter_actor_get_debug_name (self));
945 /* remaining bets are off during reparent when we're potentially
946 * mapped, but should not be according to invariants
948 if (!CLUTTER_ACTOR_IN_REPARENT (self))
950 if (priv->parent == NULL)
952 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
954 if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
955 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
957 g_warning ("Toplevel actor '%s' is mapped "
959 _clutter_actor_get_debug_name (self));
964 g_warning ("Mapped actor '%s' should have a parent",
965 _clutter_actor_get_debug_name (self));
970 ClutterActor *iter = self;
972 /* check for the enable_paint_unmapped flag on the actor
973 * and parents; if the flag is enabled at any point of this
974 * branch of the scene graph then all the later checks
979 if (iter->priv->enable_paint_unmapped)
982 iter = iter->priv->parent;
985 if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
987 g_warning ("Actor '%s' should not be mapped if parent '%s'"
989 _clutter_actor_get_debug_name (self),
990 _clutter_actor_get_debug_name (priv->parent));
993 if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
995 g_warning ("Actor '%s' should not be mapped if parent '%s'"
997 _clutter_actor_get_debug_name (self),
998 _clutter_actor_get_debug_name (priv->parent));
1001 if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1003 if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1004 g_warning ("Actor '%s' is mapped but its non-toplevel "
1005 "parent '%s' is not mapped",
1006 _clutter_actor_get_debug_name (self),
1007 _clutter_actor_get_debug_name (priv->parent));
1014 #endif /* CLUTTER_ENABLE_DEBUG */
1017 clutter_actor_set_mapped (ClutterActor *self,
1020 if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1025 CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1026 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1030 CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1031 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1035 /* this function updates the mapped and realized states according to
1036 * invariants, in the appropriate order.
1039 clutter_actor_update_map_state (ClutterActor *self,
1040 MapStateChange change)
1042 gboolean was_mapped;
1044 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1046 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1048 /* the mapped flag on top-level actors must be set by the
1049 * per-backend implementation because it might be asynchronous.
1051 * That is, the MAPPED flag on toplevels currently tracks the X
1052 * server mapped-ness of the window, while the expected behavior
1053 * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1054 * This creates some weird complexity by breaking the invariant
1055 * that if we're visible and all ancestors shown then we are
1056 * also mapped - instead, we are mapped if all ancestors
1057 * _possibly excepting_ the stage are mapped. The stage
1058 * will map/unmap for example when it is minimized or
1059 * moved to another workspace.
1061 * So, the only invariant on the stage is that if visible it
1062 * should be realized, and that it has to be visible to be
1065 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1066 clutter_actor_realize (self);
1070 case MAP_STATE_CHECK:
1073 case MAP_STATE_MAKE_MAPPED:
1074 g_assert (!was_mapped);
1075 clutter_actor_set_mapped (self, TRUE);
1078 case MAP_STATE_MAKE_UNMAPPED:
1079 g_assert (was_mapped);
1080 clutter_actor_set_mapped (self, FALSE);
1083 case MAP_STATE_MAKE_UNREALIZED:
1084 /* we only use MAKE_UNREALIZED in unparent,
1085 * and unparenting a stage isn't possible.
1086 * If someone wants to just unrealize a stage
1087 * then clutter_actor_unrealize() doesn't
1088 * go through this codepath.
1090 g_warning ("Trying to force unrealize stage is not allowed");
1094 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1095 !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1096 !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1098 g_warning ("Clutter toplevel of type '%s' is not visible, but "
1099 "it is somehow still mapped",
1100 _clutter_actor_get_debug_name (self));
1105 ClutterActorPrivate *priv = self->priv;
1106 ClutterActor *parent = priv->parent;
1107 gboolean should_be_mapped;
1108 gboolean may_be_realized;
1109 gboolean must_be_realized;
1111 should_be_mapped = FALSE;
1112 may_be_realized = TRUE;
1113 must_be_realized = FALSE;
1115 if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1117 may_be_realized = FALSE;
1121 /* Maintain invariant that if parent is mapped, and we are
1122 * visible, then we are mapped ... unless parent is a
1123 * stage, in which case we map regardless of parent's map
1124 * state but do require stage to be visible and realized.
1126 * If parent is realized, that does not force us to be
1127 * realized; but if parent is unrealized, that does force
1128 * us to be unrealized.
1130 * The reason we don't force children to realize with
1131 * parents is _clutter_actor_rerealize(); if we require that
1132 * a realized parent means children are realized, then to
1133 * unrealize an actor we would have to unrealize its
1134 * parents, which would end up meaning unrealizing and
1135 * hiding the entire stage. So we allow unrealizing a
1136 * child (as long as that child is not mapped) while that
1137 * child still has a realized parent.
1139 * Also, if we unrealize from leaf nodes to root, and
1140 * realize from root to leaf, the invariants are never
1141 * violated if we allow children to be unrealized
1142 * while parents are realized.
1144 * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1145 * to force us to unmap, even though parent is still
1146 * mapped. This is because we're unmapping from leaf nodes
1149 if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1150 change != MAP_STATE_MAKE_UNMAPPED)
1152 gboolean parent_is_visible_realized_toplevel;
1154 parent_is_visible_realized_toplevel =
1155 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1156 CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1157 CLUTTER_ACTOR_IS_REALIZED (parent));
1159 if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1160 parent_is_visible_realized_toplevel)
1162 must_be_realized = TRUE;
1163 should_be_mapped = TRUE;
1167 /* if the actor has been set to be painted even if unmapped
1168 * then we should map it and check for realization as well;
1169 * this is an override for the branch of the scene graph
1170 * which begins with this node
1172 if (priv->enable_paint_unmapped)
1174 if (priv->parent == NULL)
1175 g_warning ("Attempting to map an unparented actor '%s'",
1176 _clutter_actor_get_debug_name (self));
1178 should_be_mapped = TRUE;
1179 must_be_realized = TRUE;
1182 if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1183 may_be_realized = FALSE;
1186 if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1189 g_warning ("Attempting to map a child that does not "
1190 "meet the necessary invariants: the actor '%s' "
1192 _clutter_actor_get_debug_name (self));
1194 g_warning ("Attempting to map a child that does not "
1195 "meet the necessary invariants: the actor '%s' "
1196 "is parented to an unmapped actor '%s'",
1197 _clutter_actor_get_debug_name (self),
1198 _clutter_actor_get_debug_name (priv->parent));
1201 /* If in reparent, we temporarily suspend unmap and unrealize.
1203 * We want to go in the order "realize, map" and "unmap, unrealize"
1207 if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1208 clutter_actor_set_mapped (self, FALSE);
1211 if (must_be_realized)
1212 clutter_actor_realize (self);
1214 /* if we must be realized then we may be, presumably */
1215 g_assert (!(must_be_realized && !may_be_realized));
1218 if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1219 clutter_actor_unrealize_not_hiding (self);
1222 if (should_be_mapped)
1224 if (!must_be_realized)
1225 g_warning ("Somehow we think actor '%s' should be mapped but "
1226 "not realized, which isn't allowed",
1227 _clutter_actor_get_debug_name (self));
1229 /* realization is allowed to fail (though I don't know what
1230 * an app is supposed to do about that - shouldn't it just
1231 * be a g_error? anyway, we have to avoid mapping if this
1234 if (CLUTTER_ACTOR_IS_REALIZED (self))
1235 clutter_actor_set_mapped (self, TRUE);
1239 #ifdef CLUTTER_ENABLE_DEBUG
1240 /* check all invariants were kept */
1241 clutter_actor_verify_map_state (self);
1246 clutter_actor_real_map (ClutterActor *self)
1248 ClutterActorPrivate *priv = self->priv;
1249 ClutterActor *stage, *iter;
1251 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1253 CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1254 _clutter_actor_get_debug_name (self));
1256 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1258 stage = _clutter_actor_get_stage_internal (self);
1259 priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1261 CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1263 _clutter_actor_get_debug_name (self));
1265 /* notify on parent mapped before potentially mapping
1266 * children, so apps see a top-down notification.
1268 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1270 for (iter = self->priv->first_child;
1272 iter = iter->priv->next_sibling)
1274 clutter_actor_map (iter);
1279 * clutter_actor_map:
1280 * @self: A #ClutterActor
1282 * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1283 * and realizes its children if they are visible. Does nothing if the
1284 * actor is not visible.
1286 * Calling this function is strongly disencouraged: the default
1287 * implementation of #ClutterActorClass.map() will map all the children
1288 * of an actor when mapping its parent.
1290 * When overriding map, it is mandatory to chain up to the parent
1296 clutter_actor_map (ClutterActor *self)
1298 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1300 if (CLUTTER_ACTOR_IS_MAPPED (self))
1303 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1306 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1310 clutter_actor_real_unmap (ClutterActor *self)
1312 ClutterActorPrivate *priv = self->priv;
1315 g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1317 CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1318 _clutter_actor_get_debug_name (self));
1320 for (iter = self->priv->first_child;
1322 iter = iter->priv->next_sibling)
1324 clutter_actor_unmap (iter);
1327 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1329 /* clear the contents of the last paint volume, so that hiding + moving +
1330 * showing will not result in the wrong area being repainted
1332 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1333 priv->last_paint_volume_valid = TRUE;
1335 /* notify on parent mapped after potentially unmapping
1336 * children, so apps see a bottom-up notification.
1338 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1340 /* relinquish keyboard focus if we were unmapped while owning it */
1341 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1343 ClutterStage *stage;
1345 stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1348 _clutter_stage_release_pick_id (stage, priv->pick_id);
1352 if (stage != NULL &&
1353 clutter_stage_get_key_focus (stage) == self)
1355 clutter_stage_set_key_focus (stage, NULL);
1361 * clutter_actor_unmap:
1362 * @self: A #ClutterActor
1364 * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1365 * unmaps its children if they were mapped.
1367 * Calling this function is not encouraged: the default #ClutterActor
1368 * implementation of #ClutterActorClass.unmap() will also unmap any
1369 * eventual children by default when their parent is unmapped.
1371 * When overriding #ClutterActorClass.unmap(), it is mandatory to
1372 * chain up to the parent implementation.
1374 * <note>It is important to note that the implementation of the
1375 * #ClutterActorClass.unmap() virtual function may be called after
1376 * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1377 * implementation, but it is guaranteed to be called before the
1378 * #GObjectClass.finalize() implementation.</note>
1383 clutter_actor_unmap (ClutterActor *self)
1385 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1387 if (!CLUTTER_ACTOR_IS_MAPPED (self))
1390 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1394 clutter_actor_real_show (ClutterActor *self)
1396 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1398 ClutterActorPrivate *priv = self->priv;
1400 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1402 /* we notify on the "visible" flag in the clutter_actor_show()
1403 * wrapper so the entire show signal emission completes first
1406 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1408 /* we queue a relayout unless the actor is inside a
1409 * container that explicitly told us not to
1411 if (priv->parent != NULL &&
1412 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1414 /* While an actor is hidden the parent may not have
1415 * allocated/requested so we need to start from scratch
1416 * and avoid the short-circuiting in
1417 * clutter_actor_queue_relayout().
1419 priv->needs_width_request = FALSE;
1420 priv->needs_height_request = FALSE;
1421 priv->needs_allocation = FALSE;
1422 clutter_actor_queue_relayout (self);
1428 set_show_on_set_parent (ClutterActor *self,
1431 ClutterActorPrivate *priv = self->priv;
1433 set_show = !!set_show;
1435 if (priv->show_on_set_parent == set_show)
1438 if (priv->parent == NULL)
1440 priv->show_on_set_parent = set_show;
1441 g_object_notify_by_pspec (G_OBJECT (self),
1442 obj_props[PROP_SHOW_ON_SET_PARENT]);
1447 * clutter_actor_show:
1448 * @self: A #ClutterActor
1450 * Flags an actor to be displayed. An actor that isn't shown will not
1451 * be rendered on the stage.
1453 * Actors are visible by default.
1455 * If this function is called on an actor without a parent, the
1456 * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1460 clutter_actor_show (ClutterActor *self)
1462 ClutterActorPrivate *priv;
1464 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1466 /* simple optimization */
1467 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1469 /* we still need to set the :show-on-set-parent property, in
1470 * case show() is called on an unparented actor
1472 set_show_on_set_parent (self, TRUE);
1476 #ifdef CLUTTER_ENABLE_DEBUG
1477 clutter_actor_verify_map_state (self);
1482 g_object_freeze_notify (G_OBJECT (self));
1484 set_show_on_set_parent (self, TRUE);
1486 g_signal_emit (self, actor_signals[SHOW], 0);
1487 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1489 if (priv->parent != NULL)
1490 clutter_actor_queue_redraw (priv->parent);
1492 g_object_thaw_notify (G_OBJECT (self));
1496 * clutter_actor_show_all:
1497 * @self: a #ClutterActor
1499 * Calls clutter_actor_show() on all children of an actor (if any).
1503 * Deprecated: 1.10: Actors are visible by default
1506 clutter_actor_show_all (ClutterActor *self)
1508 ClutterActorClass *klass;
1510 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1512 klass = CLUTTER_ACTOR_GET_CLASS (self);
1513 if (klass->show_all)
1514 klass->show_all (self);
1518 clutter_actor_real_hide (ClutterActor *self)
1520 if (CLUTTER_ACTOR_IS_VISIBLE (self))
1522 ClutterActorPrivate *priv = self->priv;
1524 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1526 /* we notify on the "visible" flag in the clutter_actor_hide()
1527 * wrapper so the entire hide signal emission completes first
1530 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1532 /* we queue a relayout unless the actor is inside a
1533 * container that explicitly told us not to
1535 if (priv->parent != NULL &&
1536 (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1537 clutter_actor_queue_relayout (priv->parent);
1542 * clutter_actor_hide:
1543 * @self: A #ClutterActor
1545 * Flags an actor to be hidden. A hidden actor will not be
1546 * rendered on the stage.
1548 * Actors are visible by default.
1550 * If this function is called on an actor without a parent, the
1551 * #ClutterActor:show-on-set-parent property will be set to %FALSE
1555 clutter_actor_hide (ClutterActor *self)
1557 ClutterActorPrivate *priv;
1559 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1561 /* simple optimization */
1562 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1564 /* we still need to set the :show-on-set-parent property, in
1565 * case hide() is called on an unparented actor
1567 set_show_on_set_parent (self, FALSE);
1571 #ifdef CLUTTER_ENABLE_DEBUG
1572 clutter_actor_verify_map_state (self);
1577 g_object_freeze_notify (G_OBJECT (self));
1579 set_show_on_set_parent (self, FALSE);
1581 g_signal_emit (self, actor_signals[HIDE], 0);
1582 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1584 if (priv->parent != NULL)
1585 clutter_actor_queue_redraw (priv->parent);
1587 g_object_thaw_notify (G_OBJECT (self));
1591 * clutter_actor_hide_all:
1592 * @self: a #ClutterActor
1594 * Calls clutter_actor_hide() on all child actors (if any).
1598 * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1599 * prevent its children from being painted as well.
1602 clutter_actor_hide_all (ClutterActor *self)
1604 ClutterActorClass *klass;
1606 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1608 klass = CLUTTER_ACTOR_GET_CLASS (self);
1609 if (klass->hide_all)
1610 klass->hide_all (self);
1614 * clutter_actor_realize:
1615 * @self: A #ClutterActor
1617 * Realization informs the actor that it is attached to a stage. It
1618 * can use this to allocate resources if it wanted to delay allocation
1619 * until it would be rendered. However it is perfectly acceptable for
1620 * an actor to create resources before being realized because Clutter
1621 * only ever has a single rendering context so that actor is free to
1622 * be moved from one stage to another.
1624 * This function does nothing if the actor is already realized.
1626 * Because a realized actor must have realized parent actors, calling
1627 * clutter_actor_realize() will also realize all parents of the actor.
1629 * This function does not realize child actors, except in the special
1630 * case that realizing the stage, when the stage is visible, will
1631 * suddenly map (and thus realize) the children of the stage.
1634 clutter_actor_realize (ClutterActor *self)
1636 ClutterActorPrivate *priv;
1638 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1642 #ifdef CLUTTER_ENABLE_DEBUG
1643 clutter_actor_verify_map_state (self);
1646 if (CLUTTER_ACTOR_IS_REALIZED (self))
1649 /* To be realized, our parent actors must be realized first.
1650 * This will only succeed if we're inside a toplevel.
1652 if (priv->parent != NULL)
1653 clutter_actor_realize (priv->parent);
1655 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1657 /* toplevels can be realized at any time */
1661 /* "Fail" the realization if parent is missing or unrealized;
1662 * this should really be a g_warning() not some kind of runtime
1663 * failure; how can an app possibly recover? Instead it's a bug
1664 * in the app and the app should get an explanatory warning so
1665 * someone can fix it. But for now it's too hard to fix this
1666 * because e.g. ClutterTexture needs reworking.
1668 if (priv->parent == NULL ||
1669 !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1673 CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1675 CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1676 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1678 g_signal_emit (self, actor_signals[REALIZE], 0);
1680 /* Stage actor is allowed to unset the realized flag again in its
1681 * default signal handler, though that is a pathological situation.
1684 /* If realization "failed" we'll have to update child state. */
1685 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1689 clutter_actor_real_unrealize (ClutterActor *self)
1691 /* we must be unmapped (implying our children are also unmapped) */
1692 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1696 * clutter_actor_unrealize:
1697 * @self: A #ClutterActor
1699 * Unrealization informs the actor that it may be being destroyed or
1700 * moved to another stage. The actor may want to destroy any
1701 * underlying graphics resources at this point. However it is
1702 * perfectly acceptable for it to retain the resources until the actor
1703 * is destroyed because Clutter only ever uses a single rendering
1704 * context and all of the graphics resources are valid on any stage.
1706 * Because mapped actors must be realized, actors may not be
1707 * unrealized if they are mapped. This function hides the actor to be
1708 * sure it isn't mapped, an application-visible side effect that you
1709 * may not be expecting.
1711 * This function should not be called by application code.
1714 clutter_actor_unrealize (ClutterActor *self)
1716 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1717 g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1719 /* This function should not really be in the public API, because
1720 * there isn't a good reason to call it. ClutterActor will already
1721 * unrealize things for you when it's important to do so.
1723 * If you were using clutter_actor_unrealize() in a dispose
1724 * implementation, then don't, just chain up to ClutterActor's
1727 * If you were using clutter_actor_unrealize() to implement
1728 * unrealizing children of your container, then don't, ClutterActor
1729 * will already take care of that.
1731 * If you were using clutter_actor_unrealize() to re-realize to
1732 * create your resources in a different way, then use
1733 * _clutter_actor_rerealize() (inside Clutter) or just call your
1734 * code that recreates your resources directly (outside Clutter).
1737 #ifdef CLUTTER_ENABLE_DEBUG
1738 clutter_actor_verify_map_state (self);
1741 clutter_actor_hide (self);
1743 clutter_actor_unrealize_not_hiding (self);
1746 static ClutterActorTraverseVisitFlags
1747 unrealize_actor_before_children_cb (ClutterActor *self,
1751 /* If an actor is already unrealized we know its children have also
1752 * already been unrealized... */
1753 if (!CLUTTER_ACTOR_IS_REALIZED (self))
1754 return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1756 g_signal_emit (self, actor_signals[UNREALIZE], 0);
1758 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1761 static ClutterActorTraverseVisitFlags
1762 unrealize_actor_after_children_cb (ClutterActor *self,
1766 /* We want to unset the realized flag only _after_
1767 * child actors are unrealized, to maintain invariants.
1769 CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1770 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1771 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1775 * clutter_actor_unrealize_not_hiding:
1776 * @self: A #ClutterActor
1778 * Unrealization informs the actor that it may be being destroyed or
1779 * moved to another stage. The actor may want to destroy any
1780 * underlying graphics resources at this point. However it is
1781 * perfectly acceptable for it to retain the resources until the actor
1782 * is destroyed because Clutter only ever uses a single rendering
1783 * context and all of the graphics resources are valid on any stage.
1785 * Because mapped actors must be realized, actors may not be
1786 * unrealized if they are mapped. You must hide the actor or one of
1787 * its parents before attempting to unrealize.
1789 * This function is separate from clutter_actor_unrealize() because it
1790 * does not automatically hide the actor.
1791 * Actors need not be hidden to be unrealized, they just need to
1792 * be unmapped. In fact we don't want to mess up the application's
1793 * setting of the "visible" flag, so hiding is very undesirable.
1795 * clutter_actor_unrealize() does a clutter_actor_hide() just for
1796 * backward compatibility.
1799 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1801 _clutter_actor_traverse (self,
1802 CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1803 unrealize_actor_before_children_cb,
1804 unrealize_actor_after_children_cb,
1809 * _clutter_actor_rerealize:
1810 * @self: A #ClutterActor
1811 * @callback: Function to call while unrealized
1812 * @data: data for callback
1814 * If an actor is already unrealized, this just calls the callback.
1816 * If it is realized, it unrealizes temporarily, calls the callback,
1817 * and then re-realizes the actor.
1819 * As a side effect, leaves all children of the actor unrealized if
1820 * the actor was realized but not showing. This is because when we
1821 * unrealize the actor temporarily we must unrealize its children
1822 * (e.g. children of a stage can't be realized if stage window is
1823 * gone). And we aren't clever enough to save the realization state of
1824 * all children. In most cases this should not matter, because
1825 * the children will automatically realize when they next become mapped.
1828 _clutter_actor_rerealize (ClutterActor *self,
1829 ClutterCallback callback,
1832 gboolean was_mapped;
1833 gboolean was_showing;
1834 gboolean was_realized;
1836 g_return_if_fail (CLUTTER_IS_ACTOR (self));
1838 #ifdef CLUTTER_ENABLE_DEBUG
1839 clutter_actor_verify_map_state (self);
1842 was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1843 was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1844 was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1846 /* Must be unmapped to unrealize. Note we only have to hide this
1847 * actor if it was mapped (if all parents were showing). If actor
1848 * is merely visible (but not mapped), then that's fine, we can
1852 clutter_actor_hide (self);
1854 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1856 /* unrealize self and all children */
1857 clutter_actor_unrealize_not_hiding (self);
1859 if (callback != NULL)
1861 (* callback) (self, data);
1865 clutter_actor_show (self); /* will realize only if mapping implies it */
1866 else if (was_realized)
1867 clutter_actor_realize (self); /* realize self and all parents */
1871 clutter_actor_real_pick (ClutterActor *self,
1872 const ClutterColor *color)
1874 /* the default implementation is just to paint a rectangle
1875 * with the same size of the actor using the passed color
1877 if (clutter_actor_should_pick_paint (self))
1879 ClutterActorBox box = { 0, };
1880 float width, height;
1882 clutter_actor_get_allocation_box (self, &box);
1884 width = box.x2 - box.x1;
1885 height = box.y2 - box.y1;
1887 cogl_set_source_color4ub (color->red,
1892 cogl_rectangle (0, 0, width, height);
1895 /* XXX - this thoroughly sucks, but we need to maintain compatibility
1896 * with existing container classes that override the pick() virtual
1897 * and chain up to the default implementation - otherwise we'll end up
1898 * painting our children twice.
1900 * this has to go away for 2.0; hopefully along the pick() itself.
1902 if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
1906 for (iter = self->priv->first_child;
1908 iter = iter->priv->next_sibling)
1909 clutter_actor_paint (iter);
1914 * clutter_actor_should_pick_paint:
1915 * @self: A #ClutterActor
1917 * Should be called inside the implementation of the
1918 * #ClutterActor::pick virtual function in order to check whether
1919 * the actor should paint itself in pick mode or not.
1921 * This function should never be called directly by applications.
1923 * Return value: %TRUE if the actor should paint its silhouette,
1927 clutter_actor_should_pick_paint (ClutterActor *self)
1929 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
1931 if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1932 (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
1933 CLUTTER_ACTOR_IS_REACTIVE (self)))
1940 clutter_actor_real_get_preferred_width (ClutterActor *self,
1942 gfloat *min_width_p,
1943 gfloat *natural_width_p)
1945 ClutterActorPrivate *priv = self->priv;
1947 if (priv->n_children != 0 &&
1948 priv->layout_manager != NULL)
1950 ClutterContainer *container = CLUTTER_CONTAINER (self);
1952 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1953 "for the preferred width",
1954 G_OBJECT_TYPE_NAME (priv->layout_manager),
1955 priv->layout_manager);
1957 clutter_layout_manager_get_preferred_width (priv->layout_manager,
1966 /* Default implementation is always 0x0, usually an actor
1967 * using this default is relying on someone to set the
1970 CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
1975 if (natural_width_p)
1976 *natural_width_p = 0;
1980 clutter_actor_real_get_preferred_height (ClutterActor *self,
1982 gfloat *min_height_p,
1983 gfloat *natural_height_p)
1985 ClutterActorPrivate *priv = self->priv;
1987 if (priv->n_children != 0 &&
1988 priv->layout_manager != NULL)
1990 ClutterContainer *container = CLUTTER_CONTAINER (self);
1992 CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
1993 "for the preferred height",
1994 G_OBJECT_TYPE_NAME (priv->layout_manager),
1995 priv->layout_manager);
1997 clutter_layout_manager_get_preferred_height (priv->layout_manager,
2005 /* Default implementation is always 0x0, usually an actor
2006 * using this default is relying on someone to set the
2009 CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2014 if (natural_height_p)
2015 *natural_height_p = 0;
2019 clutter_actor_store_old_geometry (ClutterActor *self,
2020 ClutterActorBox *box)
2022 *box = self->priv->allocation;
2026 clutter_actor_notify_if_geometry_changed (ClutterActor *self,
2027 const ClutterActorBox *old)
2029 ClutterActorPrivate *priv = self->priv;
2030 GObject *obj = G_OBJECT (self);
2032 g_object_freeze_notify (obj);
2034 /* to avoid excessive requisition or allocation cycles we
2035 * use the cached values.
2037 * - if we don't have an allocation we assume that we need
2039 * - if we don't have a width or a height request we notify
2041 * - if we have a valid allocation then we check the old
2042 * bounding box with the current allocation and we notify
2045 if (priv->needs_allocation)
2047 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2048 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2049 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2050 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2052 else if (priv->needs_width_request || priv->needs_height_request)
2054 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2055 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2060 gfloat widthu, heightu;
2062 xu = priv->allocation.x1;
2063 yu = priv->allocation.y1;
2064 widthu = priv->allocation.x2 - priv->allocation.x1;
2065 heightu = priv->allocation.y2 - priv->allocation.y1;
2068 g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2071 g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2073 if (widthu != (old->x2 - old->x1))
2074 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2076 if (heightu != (old->y2 - old->y1))
2077 g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2080 g_object_thaw_notify (obj);
2084 * clutter_actor_set_allocation_internal:
2085 * @self: a #ClutterActor
2086 * @box: a #ClutterActorBox
2087 * @flags: allocation flags
2089 * Stores the allocation of @self.
2091 * This function only performs basic storage and property notification.
2093 * This function should be called by clutter_actor_set_allocation()
2094 * and by the default implementation of #ClutterActorClass.allocate().
2096 * Return value: %TRUE if the allocation of the #ClutterActor has been
2097 * changed, and %FALSE otherwise
2099 static inline gboolean
2100 clutter_actor_set_allocation_internal (ClutterActor *self,
2101 const ClutterActorBox *box,
2102 ClutterAllocationFlags flags)
2104 ClutterActorPrivate *priv = self->priv;
2106 gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2107 gboolean flags_changed;
2109 ClutterActorBox old_alloc = { 0, };
2111 obj = G_OBJECT (self);
2113 g_object_freeze_notify (obj);
2115 clutter_actor_store_old_geometry (self, &old_alloc);
2117 x1_changed = priv->allocation.x1 != box->x1;
2118 y1_changed = priv->allocation.y1 != box->y1;
2119 x2_changed = priv->allocation.x2 != box->x2;
2120 y2_changed = priv->allocation.y2 != box->y2;
2122 flags_changed = priv->allocation_flags != flags;
2124 priv->allocation = *box;
2125 priv->allocation_flags = flags;
2127 /* allocation is authoritative */
2128 priv->needs_width_request = FALSE;
2129 priv->needs_height_request = FALSE;
2130 priv->needs_allocation = FALSE;
2132 if (x1_changed || y1_changed || x2_changed || y2_changed || flags_changed)
2134 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2135 _clutter_actor_get_debug_name (self));
2137 priv->transform_valid = FALSE;
2139 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2141 /* if the allocation changes, so does the content box */
2142 if (priv->content != NULL)
2143 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2150 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2152 g_object_thaw_notify (obj);
2157 static void clutter_actor_real_allocate (ClutterActor *self,
2158 const ClutterActorBox *box,
2159 ClutterAllocationFlags flags);
2162 clutter_actor_maybe_layout_children (ClutterActor *self,
2163 const ClutterActorBox *allocation,
2164 ClutterAllocationFlags flags)
2166 ClutterActorPrivate *priv = self->priv;
2168 /* this is going to be a bit hard to follow, so let's put an explanation
2171 * we want ClutterActor to have a default layout manager if the actor was
2172 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2174 * we also want any subclass of ClutterActor that does not override the
2175 * ::allocate() virtual function to delegate to a layout manager.
2177 * finally, we want to allow people subclassing ClutterActor and overriding
2178 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2180 * on the other hand, we want existing actor subclasses overriding the
2181 * ::allocate() virtual function and chaining up to the parent's
2182 * implementation to continue working without allocating their children
2183 * twice, or without entering an allocation loop.
2185 * for the first two points, we check if the class of the actor is
2186 * overridding the ::allocate() virtual function; if it isn't, then we
2187 * follow through with checking whether we have children and a layout
2188 * manager, and eventually calling clutter_layout_manager_allocate().
2190 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2191 * allocation flags that we got passed, and if it is present, we continue
2192 * with the check above.
2194 * if neither of these two checks yields a positive result, we just
2195 * assume that the ::allocate() virtual function that resulted in this
2196 * function being called will also allocate the children of the actor.
2199 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2202 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2208 if (priv->n_children != 0 &&
2209 priv->layout_manager != NULL)
2211 ClutterContainer *container = CLUTTER_CONTAINER (self);
2212 ClutterAllocationFlags children_flags;
2213 ClutterActorBox children_box;
2215 /* normalize the box passed to the layout manager */
2216 children_box.x1 = children_box.y1 = 0.f;
2217 children_box.x2 = (allocation->x2 - allocation->x1);
2218 children_box.y2 = (allocation->y2 - allocation->y1);
2220 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2221 * the actor's children, since it refers only to the current
2222 * actor's allocation.
2224 children_flags = flags;
2225 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2227 CLUTTER_NOTE (LAYOUT,
2228 "Allocating %d children of %s "
2229 "at { %.2f, %.2f - %.2f x %.2f } "
2232 _clutter_actor_get_debug_name (self),
2235 (allocation->x2 - allocation->x1),
2236 (allocation->y2 - allocation->y1),
2237 G_OBJECT_TYPE_NAME (priv->layout_manager));
2239 clutter_layout_manager_allocate (priv->layout_manager,
2247 clutter_actor_real_allocate (ClutterActor *self,
2248 const ClutterActorBox *box,
2249 ClutterAllocationFlags flags)
2251 ClutterActorPrivate *priv = self->priv;
2254 g_object_freeze_notify (G_OBJECT (self));
2256 changed = clutter_actor_set_allocation_internal (self, box, flags);
2258 /* we allocate our children before we notify changes in our geometry,
2259 * so that people connecting to properties will be able to get valid
2260 * data out of the sub-tree of the scene graph that has this actor at
2263 clutter_actor_maybe_layout_children (self, box, flags);
2267 ClutterActorBox signal_box = priv->allocation;
2268 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2270 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2275 g_object_thaw_notify (G_OBJECT (self));
2279 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2280 ClutterActor *origin)
2282 /* no point in queuing a redraw on a destroyed actor */
2283 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2286 /* NB: We can't bail out early here if the actor is hidden in case
2287 * the actor bas been cloned. In this case the clone will need to
2288 * receive the signal so it can queue its own redraw.
2291 /* calls klass->queue_redraw in default handler */
2292 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2296 clutter_actor_real_queue_redraw (ClutterActor *self,
2297 ClutterActor *origin)
2299 ClutterActor *parent;
2301 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2302 _clutter_actor_get_debug_name (self),
2303 origin != NULL ? _clutter_actor_get_debug_name (origin)
2306 /* no point in queuing a redraw on a destroyed actor */
2307 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2310 /* If the queue redraw is coming from a child then the actor has
2311 become dirty and any queued effect is no longer valid */
2314 self->priv->is_dirty = TRUE;
2315 self->priv->effect_to_redraw = NULL;
2318 /* If the actor isn't visible, we still had to emit the signal
2319 * to allow for a ClutterClone, but the appearance of the parent
2320 * won't change so we don't have to propagate up the hierarchy.
2322 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2325 /* Although we could determine here that a full stage redraw
2326 * has already been queued and immediately bail out, we actually
2327 * guarantee that we will propagate a queue-redraw signal to our
2328 * parent at least once so that it's possible to implement a
2329 * container that tracks which of its children have queued a
2332 if (self->priv->propagated_one_redraw)
2334 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2335 if (stage != NULL &&
2336 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2340 self->priv->propagated_one_redraw = TRUE;
2342 /* notify parents, if they are all visible eventually we'll
2343 * queue redraw on the stage, which queues the redraw idle.
2345 parent = clutter_actor_get_parent (self);
2348 /* this will go up recursively */
2349 _clutter_actor_signal_queue_redraw (parent, origin);
2354 clutter_actor_real_queue_relayout (ClutterActor *self)
2356 ClutterActorPrivate *priv = self->priv;
2358 /* no point in queueing a redraw on a destroyed actor */
2359 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2362 priv->needs_width_request = TRUE;
2363 priv->needs_height_request = TRUE;
2364 priv->needs_allocation = TRUE;
2366 /* reset the cached size requests */
2367 memset (priv->width_requests, 0,
2368 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2369 memset (priv->height_requests, 0,
2370 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2372 /* We need to go all the way up the hierarchy */
2373 if (priv->parent != NULL)
2374 _clutter_actor_queue_only_relayout (priv->parent);
2378 * clutter_actor_apply_relative_transform_to_point:
2379 * @self: A #ClutterActor
2380 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2381 * default #ClutterStage
2382 * @point: A point as #ClutterVertex
2383 * @vertex: (out caller-allocates): The translated #ClutterVertex
2385 * Transforms @point in coordinates relative to the actor into
2386 * ancestor-relative coordinates using the relevant transform
2387 * stack (i.e. scale, rotation, etc).
2389 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2390 * this case, the coordinates returned will be the coordinates on
2391 * the stage before the projection is applied. This is different from
2392 * the behaviour of clutter_actor_apply_transform_to_point().
2397 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2398 ClutterActor *ancestor,
2399 const ClutterVertex *point,
2400 ClutterVertex *vertex)
2405 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2406 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2407 g_return_if_fail (point != NULL);
2408 g_return_if_fail (vertex != NULL);
2413 if (ancestor == NULL)
2414 ancestor = _clutter_actor_get_stage_internal (self);
2416 if (ancestor == NULL)
2422 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2423 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2427 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2428 const ClutterVertex *vertices_in,
2429 ClutterVertex *vertices_out,
2432 ClutterActor *stage;
2433 CoglMatrix modelview;
2434 CoglMatrix projection;
2437 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2439 stage = _clutter_actor_get_stage_internal (self);
2441 /* We really can't do anything meaningful in this case so don't try
2442 * to do any transform */
2446 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2447 * that gets us to stage coordinates, we want to go all the way to eye
2449 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2451 /* Fetch the projection and viewport */
2452 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2453 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2459 _clutter_util_fully_transform_vertices (&modelview,
2470 * clutter_actor_apply_transform_to_point:
2471 * @self: A #ClutterActor
2472 * @point: A point as #ClutterVertex
2473 * @vertex: (out caller-allocates): The translated #ClutterVertex
2475 * Transforms @point in coordinates relative to the actor
2476 * into screen-relative coordinates with the current actor
2477 * transformation (i.e. scale, rotation, etc)
2482 clutter_actor_apply_transform_to_point (ClutterActor *self,
2483 const ClutterVertex *point,
2484 ClutterVertex *vertex)
2486 g_return_if_fail (point != NULL);
2487 g_return_if_fail (vertex != NULL);
2488 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2492 * _clutter_actor_get_relative_transformation_matrix:
2493 * @self: The actor whose coordinate space you want to transform from.
2494 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2495 * or %NULL if you want to transform all the way to eye coordinates.
2496 * @matrix: A #CoglMatrix to store the transformation
2498 * This gets a transformation @matrix that will transform coordinates from the
2499 * coordinate space of @self into the coordinate space of @ancestor.
2501 * For example if you need a matrix that can transform the local actor
2502 * coordinates of @self into stage coordinates you would pass the actor's stage
2503 * pointer as the @ancestor.
2505 * If you pass %NULL then the transformation will take you all the way through
2506 * to eye coordinates. This can be useful if you want to extract the entire
2507 * modelview transform that Clutter applies before applying the projection
2508 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2509 * using cogl_set_modelview_matrix() for example then you would want a matrix
2510 * that transforms into eye coordinates.
2512 * <note><para>This function explicitly initializes the given @matrix. If you just
2513 * want clutter to multiply a relative transformation with an existing matrix
2514 * you can use clutter_actor_apply_relative_transformation_matrix()
2515 * instead.</para></note>
2518 /* XXX: We should consider caching the stage relative modelview along with
2519 * the actor itself */
2521 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2522 ClutterActor *ancestor,
2525 cogl_matrix_init_identity (matrix);
2527 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2530 /* Project the given @box into stage window coordinates, writing the
2531 * transformed vertices to @verts[]. */
2533 _clutter_actor_transform_and_project_box (ClutterActor *self,
2534 const ClutterActorBox *box,
2535 ClutterVertex verts[])
2537 ClutterVertex box_vertices[4];
2539 box_vertices[0].x = box->x1;
2540 box_vertices[0].y = box->y1;
2541 box_vertices[0].z = 0;
2542 box_vertices[1].x = box->x2;
2543 box_vertices[1].y = box->y1;
2544 box_vertices[1].z = 0;
2545 box_vertices[2].x = box->x1;
2546 box_vertices[2].y = box->y2;
2547 box_vertices[2].z = 0;
2548 box_vertices[3].x = box->x2;
2549 box_vertices[3].y = box->y2;
2550 box_vertices[3].z = 0;
2553 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2557 * clutter_actor_get_allocation_vertices:
2558 * @self: A #ClutterActor
2559 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2560 * against, or %NULL to use the #ClutterStage
2561 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2562 * location for an array of 4 #ClutterVertex in which to store the result
2564 * Calculates the transformed coordinates of the four corners of the
2565 * actor in the plane of @ancestor. The returned vertices relate to
2566 * the #ClutterActorBox coordinates as follows:
2568 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2569 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2570 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2571 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2574 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2575 * this case, the coordinates returned will be the coordinates on
2576 * the stage before the projection is applied. This is different from
2577 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2582 clutter_actor_get_allocation_vertices (ClutterActor *self,
2583 ClutterActor *ancestor,
2584 ClutterVertex verts[])
2586 ClutterActorPrivate *priv;
2587 ClutterActorBox box;
2588 ClutterVertex vertices[4];
2589 CoglMatrix modelview;
2591 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2592 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2594 if (ancestor == NULL)
2595 ancestor = _clutter_actor_get_stage_internal (self);
2597 /* Fallback to a NOP transform if the actor isn't parented under a
2599 if (ancestor == NULL)
2604 /* if the actor needs to be allocated we force a relayout, so that
2605 * we will have valid values to use in the transformations */
2606 if (priv->needs_allocation)
2608 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2610 _clutter_stage_maybe_relayout (stage);
2613 box.x1 = box.y1 = 0;
2614 /* The result isn't really meaningful in this case but at
2615 * least try to do something *vaguely* reasonable... */
2616 clutter_actor_get_size (self, &box.x2, &box.y2);
2620 clutter_actor_get_allocation_box (self, &box);
2622 vertices[0].x = box.x1;
2623 vertices[0].y = box.y1;
2625 vertices[1].x = box.x2;
2626 vertices[1].y = box.y1;
2628 vertices[2].x = box.x1;
2629 vertices[2].y = box.y2;
2631 vertices[3].x = box.x2;
2632 vertices[3].y = box.y2;
2635 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2638 cogl_matrix_transform_points (&modelview,
2640 sizeof (ClutterVertex),
2642 sizeof (ClutterVertex),
2648 * clutter_actor_get_abs_allocation_vertices:
2649 * @self: A #ClutterActor
2650 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2651 * of 4 #ClutterVertex where to store the result.
2653 * Calculates the transformed screen coordinates of the four corners of
2654 * the actor; the returned vertices relate to the #ClutterActorBox
2655 * coordinates as follows:
2657 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2658 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2659 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2660 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2666 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2667 ClutterVertex verts[])
2669 ClutterActorPrivate *priv;
2670 ClutterActorBox actor_space_allocation;
2672 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2676 /* if the actor needs to be allocated we force a relayout, so that
2677 * the actor allocation box will be valid for
2678 * _clutter_actor_transform_and_project_box()
2680 if (priv->needs_allocation)
2682 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2683 /* There's nothing meaningful we can do now */
2687 _clutter_stage_maybe_relayout (stage);
2690 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2691 * own coordinate space... */
2692 actor_space_allocation.x1 = 0;
2693 actor_space_allocation.y1 = 0;
2694 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2695 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2696 _clutter_actor_transform_and_project_box (self,
2697 &actor_space_allocation,
2702 clutter_actor_real_apply_transform (ClutterActor *self,
2705 ClutterActorPrivate *priv = self->priv;
2707 if (!priv->transform_valid)
2709 CoglMatrix *transform = &priv->transform;
2710 const ClutterTransformInfo *info;
2712 info = _clutter_actor_get_transform_info_or_defaults (self);
2714 cogl_matrix_init_identity (transform);
2716 cogl_matrix_translate (transform,
2717 priv->allocation.x1,
2718 priv->allocation.y1,
2722 cogl_matrix_translate (transform, 0, 0, info->depth);
2725 * because the rotation involves translations, we must scale
2726 * before applying the rotations (if we apply the scale after
2727 * the rotations, the translations included in the rotation are
2728 * not scaled and so the entire object will move on the screen
2729 * as a result of rotating it).
2731 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2733 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2734 &info->scale_center,
2735 cogl_matrix_scale (transform,
2742 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2744 cogl_matrix_rotate (transform,
2749 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2751 cogl_matrix_rotate (transform,
2756 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2758 cogl_matrix_rotate (transform,
2762 if (!clutter_anchor_coord_is_zero (&info->anchor))
2766 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2767 cogl_matrix_translate (transform, -x, -y, -z);
2770 priv->transform_valid = TRUE;
2773 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2776 /* Applies the transforms associated with this actor to the given
2779 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2782 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2786 * clutter_actor_apply_relative_transformation_matrix:
2787 * @self: The actor whose coordinate space you want to transform from.
2788 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2789 * or %NULL if you want to transform all the way to eye coordinates.
2790 * @matrix: A #CoglMatrix to apply the transformation too.
2792 * This multiplies a transform with @matrix that will transform coordinates
2793 * from the coordinate space of @self into the coordinate space of @ancestor.
2795 * For example if you need a matrix that can transform the local actor
2796 * coordinates of @self into stage coordinates you would pass the actor's stage
2797 * pointer as the @ancestor.
2799 * If you pass %NULL then the transformation will take you all the way through
2800 * to eye coordinates. This can be useful if you want to extract the entire
2801 * modelview transform that Clutter applies before applying the projection
2802 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2803 * using cogl_set_modelview_matrix() for example then you would want a matrix
2804 * that transforms into eye coordinates.
2806 * <note>This function doesn't initialize the given @matrix, it simply
2807 * multiplies the requested transformation matrix with the existing contents of
2808 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2809 * before calling this function, or you can use
2810 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2813 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2814 ClutterActor *ancestor,
2817 ClutterActor *parent;
2819 /* Note we terminate before ever calling stage->apply_transform()
2820 * since that would conceptually be relative to the underlying
2821 * window OpenGL coordinates so we'd need a special @ancestor
2822 * value to represent the fake parent of the stage. */
2823 if (self == ancestor)
2826 parent = clutter_actor_get_parent (self);
2829 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2832 _clutter_actor_apply_modelview_transform (self, matrix);
2836 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2837 ClutterPaintVolume *pv,
2839 const CoglColor *color)
2841 static CoglPipeline *outline = NULL;
2842 CoglPrimitive *prim;
2843 ClutterVertex line_ends[12 * 2];
2846 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2847 /* XXX: at some point we'll query this from the stage but we can't
2848 * do that until the osx backend uses Cogl natively. */
2849 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2851 if (outline == NULL)
2852 outline = cogl_pipeline_new (ctx);
2854 _clutter_paint_volume_complete (pv);
2856 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2859 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2860 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2861 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2862 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2867 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2868 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2869 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2870 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2872 /* Lines connecting front face to back face */
2873 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2874 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2875 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2876 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2879 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2881 (CoglVertexP3 *)line_ends);
2883 cogl_pipeline_set_color (outline, color);
2884 cogl_framebuffer_draw_primitive (fb, outline, prim);
2885 cogl_object_unref (prim);
2889 PangoLayout *layout;
2890 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2891 pango_layout_set_text (layout, label, -1);
2892 cogl_pango_render_layout (layout,
2897 g_object_unref (layout);
2902 _clutter_actor_draw_paint_volume (ClutterActor *self)
2904 ClutterPaintVolume *pv;
2907 pv = _clutter_actor_get_paint_volume_mutable (self);
2910 gfloat width, height;
2911 ClutterPaintVolume fake_pv;
2913 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2914 _clutter_paint_volume_init_static (&fake_pv, stage);
2916 clutter_actor_get_size (self, &width, &height);
2917 clutter_paint_volume_set_width (&fake_pv, width);
2918 clutter_paint_volume_set_height (&fake_pv, height);
2920 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2921 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2922 _clutter_actor_get_debug_name (self),
2925 clutter_paint_volume_free (&fake_pv);
2929 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2930 _clutter_actor_draw_paint_volume_full (self, pv,
2931 _clutter_actor_get_debug_name (self),
2937 _clutter_actor_paint_cull_result (ClutterActor *self,
2939 ClutterCullResult result)
2941 ClutterPaintVolume *pv;
2946 if (result == CLUTTER_CULL_RESULT_IN)
2947 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2948 else if (result == CLUTTER_CULL_RESULT_OUT)
2949 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2951 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2954 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2956 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2957 _clutter_actor_draw_paint_volume_full (self, pv,
2958 _clutter_actor_get_debug_name (self),
2962 PangoLayout *layout;
2964 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2965 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2966 cogl_set_source_color (&color);
2968 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2969 pango_layout_set_text (layout, label, -1);
2970 cogl_pango_render_layout (layout,
2976 g_object_unref (layout);
2980 static int clone_paint_level = 0;
2983 _clutter_actor_push_clone_paint (void)
2985 clone_paint_level++;
2989 _clutter_actor_pop_clone_paint (void)
2991 clone_paint_level--;
2995 in_clone_paint (void)
2997 return clone_paint_level > 0;
3000 /* Returns TRUE if the actor can be ignored */
3001 /* FIXME: we should return a ClutterCullResult, and
3002 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3003 * means there's no point in trying to cull descendants of the current
3006 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3008 ClutterActorPrivate *priv = self->priv;
3009 ClutterActor *stage;
3010 const ClutterPlane *stage_clip;
3012 if (!priv->last_paint_volume_valid)
3014 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3015 "->last_paint_volume_valid == FALSE",
3016 _clutter_actor_get_debug_name (self));
3020 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3023 stage = _clutter_actor_get_stage_internal (self);
3024 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3025 if (G_UNLIKELY (!stage_clip))
3027 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3028 "No stage clip set",
3029 _clutter_actor_get_debug_name (self));
3033 if (cogl_get_draw_framebuffer () !=
3034 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3036 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3037 "Current framebuffer doesn't correspond to stage",
3038 _clutter_actor_get_debug_name (self));
3043 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3048 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3050 ClutterActorPrivate *priv = self->priv;
3051 const ClutterPaintVolume *pv;
3053 if (priv->last_paint_volume_valid)
3055 clutter_paint_volume_free (&priv->last_paint_volume);
3056 priv->last_paint_volume_valid = FALSE;
3059 pv = clutter_actor_get_paint_volume (self);
3062 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3063 "Actor failed to report a paint volume",
3064 _clutter_actor_get_debug_name (self));
3068 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3070 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3071 NULL); /* eye coordinates */
3073 priv->last_paint_volume_valid = TRUE;
3076 static inline gboolean
3077 actor_has_shader_data (ClutterActor *self)
3079 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3083 _clutter_actor_get_pick_id (ClutterActor *self)
3085 if (self->priv->pick_id < 0)
3088 return self->priv->pick_id;
3091 /* This is the same as clutter_actor_add_effect except that it doesn't
3092 queue a redraw and it doesn't notify on the effect property */
3094 _clutter_actor_add_effect_internal (ClutterActor *self,
3095 ClutterEffect *effect)
3097 ClutterActorPrivate *priv = self->priv;
3099 if (priv->effects == NULL)
3101 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3102 priv->effects->actor = self;
3105 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3108 /* This is the same as clutter_actor_remove_effect except that it doesn't
3109 queue a redraw and it doesn't notify on the effect property */
3111 _clutter_actor_remove_effect_internal (ClutterActor *self,
3112 ClutterEffect *effect)
3114 ClutterActorPrivate *priv = self->priv;
3116 if (priv->effects == NULL)
3119 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3123 needs_flatten_effect (ClutterActor *self)
3125 ClutterActorPrivate *priv = self->priv;
3127 if (G_UNLIKELY (clutter_paint_debug_flags &
3128 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3131 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3133 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3135 if (clutter_actor_get_paint_opacity (self) < 255 &&
3136 clutter_actor_has_overlaps (self))
3144 add_or_remove_flatten_effect (ClutterActor *self)
3146 ClutterActorPrivate *priv = self->priv;
3148 /* Add or remove the flatten effect depending on the
3149 offscreen-redirect property. */
3150 if (needs_flatten_effect (self))
3152 if (priv->flatten_effect == NULL)
3154 ClutterActorMeta *actor_meta;
3157 priv->flatten_effect = _clutter_flatten_effect_new ();
3158 /* Keep a reference to the effect so that we can queue
3160 g_object_ref_sink (priv->flatten_effect);
3162 /* Set the priority of the effect to high so that it will
3163 always be applied to the actor first. It uses an internal
3164 priority so that it won't be visible to applications */
3165 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3166 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3167 _clutter_actor_meta_set_priority (actor_meta, priority);
3169 /* This will add the effect without queueing a redraw */
3170 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3175 if (priv->flatten_effect != NULL)
3177 /* Destroy the effect so that it will lose its fbo cache of
3179 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3180 g_object_unref (priv->flatten_effect);
3181 priv->flatten_effect = NULL;
3187 clutter_actor_real_paint (ClutterActor *actor)
3189 ClutterActorPrivate *priv = actor->priv;
3192 for (iter = priv->first_child;
3194 iter = iter->priv->next_sibling)
3196 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3197 _clutter_actor_get_debug_name (iter),
3198 _clutter_actor_get_debug_name (actor),
3199 iter->priv->allocation.x1,
3200 iter->priv->allocation.y1,
3201 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3202 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3204 clutter_actor_paint (iter);
3209 clutter_actor_paint_node (ClutterActor *actor,
3210 ClutterPaintNode *root)
3212 ClutterActorPrivate *priv = actor->priv;
3217 if (priv->bg_color_set &&
3218 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3220 ClutterPaintNode *node;
3221 ClutterColor bg_color;
3222 ClutterActorBox box;
3226 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3227 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3229 bg_color = priv->bg_color;
3230 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3231 * priv->bg_color.alpha
3234 node = clutter_color_node_new (&bg_color);
3235 clutter_paint_node_set_name (node, "backgroundColor");
3236 clutter_paint_node_add_rectangle (node, &box);
3237 clutter_paint_node_add_child (root, node);
3238 clutter_paint_node_unref (node);
3241 if (priv->content != NULL)
3242 _clutter_content_paint_content (priv->content, actor, root);
3244 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3245 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3247 if (clutter_paint_node_get_n_children (root) == 0)
3250 #ifdef CLUTTER_ENABLE_DEBUG
3251 if (CLUTTER_HAS_DEBUG (PAINT))
3253 /* dump the tree only if we have one */
3254 _clutter_paint_node_dump_tree (root);
3256 #endif /* CLUTTER_ENABLE_DEBUG */
3258 _clutter_paint_node_paint (root);
3261 /* XXX: Uncomment this when we disable emitting the paint signal */
3262 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3269 * clutter_actor_paint:
3270 * @self: A #ClutterActor
3272 * Renders the actor to display.
3274 * This function should not be called directly by applications.
3275 * Call clutter_actor_queue_redraw() to queue paints, instead.
3277 * This function is context-aware, and will either cause a
3278 * regular paint or a pick paint.
3280 * This function will emit the #ClutterActor::paint signal or
3281 * the #ClutterActor::pick signal, depending on the context.
3283 * This function does not paint the actor if the actor is set to 0,
3284 * unless it is performing a pick paint.
3287 clutter_actor_paint (ClutterActor *self)
3289 ClutterActorPrivate *priv;
3290 ClutterPickMode pick_mode;
3291 gboolean clip_set = FALSE;
3292 gboolean shader_applied = FALSE;
3294 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3295 "Actor real-paint counter",
3296 "Increments each time any actor is painted",
3297 0 /* no application private data */);
3298 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3299 "Actor pick-paint counter",
3300 "Increments each time any actor is painted "
3302 0 /* no application private data */);
3304 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3306 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3311 pick_mode = _clutter_context_get_pick_mode ();
3313 if (pick_mode == CLUTTER_PICK_NONE)
3314 priv->propagated_one_redraw = FALSE;
3316 /* It's an important optimization that we consider painting of
3317 * actors with 0 opacity to be a NOP... */
3318 if (pick_mode == CLUTTER_PICK_NONE &&
3319 /* ignore top-levels, since they might be transparent */
3320 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3321 /* Use the override opacity if its been set */
3322 ((priv->opacity_override >= 0) ?
3323 priv->opacity_override : priv->opacity) == 0)
3326 /* if we aren't paintable (not in a toplevel with all
3327 * parents paintable) then do nothing.
3329 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3332 /* mark that we are in the paint process */
3333 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3337 if (priv->enable_model_view_transform)
3341 /* XXX: It could be better to cache the modelview with the actor
3342 * instead of progressively building up the transformations on
3343 * the matrix stack every time we paint. */
3344 cogl_get_modelview_matrix (&matrix);
3345 _clutter_actor_apply_modelview_transform (self, &matrix);
3347 #ifdef CLUTTER_ENABLE_DEBUG
3348 /* Catch when out-of-band transforms have been made by actors not as part
3349 * of an apply_transform vfunc... */
3350 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3352 CoglMatrix expected_matrix;
3354 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3357 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3359 GString *buf = g_string_sized_new (1024);
3360 ClutterActor *parent;
3363 while (parent != NULL)
3365 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3367 if (parent->priv->parent != NULL)
3368 g_string_append (buf, "->");
3370 parent = parent->priv->parent;
3373 g_warning ("Unexpected transform found when painting actor "
3374 "\"%s\". This will be caused by one of the actor's "
3375 "ancestors (%s) using the Cogl API directly to transform "
3376 "children instead of using ::apply_transform().",
3377 _clutter_actor_get_debug_name (self),
3380 g_string_free (buf, TRUE);
3383 #endif /* CLUTTER_ENABLE_DEBUG */
3385 cogl_set_modelview_matrix (&matrix);
3390 cogl_clip_push_rectangle (priv->clip.x,
3392 priv->clip.x + priv->clip.width,
3393 priv->clip.y + priv->clip.height);
3396 else if (priv->clip_to_allocation)
3398 gfloat width, height;
3400 width = priv->allocation.x2 - priv->allocation.x1;
3401 height = priv->allocation.y2 - priv->allocation.y1;
3403 cogl_clip_push_rectangle (0, 0, width, height);
3407 if (pick_mode == CLUTTER_PICK_NONE)
3409 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3411 /* We check whether we need to add the flatten effect before
3412 each paint so that we can avoid having a mechanism for
3413 applications to notify when the value of the
3414 has_overlaps virtual changes. */
3415 add_or_remove_flatten_effect (self);
3418 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3420 /* We save the current paint volume so that the next time the
3421 * actor queues a redraw we can constrain the redraw to just
3422 * cover the union of the new bounding box and the old.
3424 * We also fetch the current paint volume to perform culling so
3425 * we can avoid painting actors outside the current clip region.
3427 * If we are painting inside a clone, we should neither update
3428 * the paint volume or use it to cull painting, since the paint
3429 * box represents the location of the source actor on the
3432 * XXX: We are starting to do a lot of vertex transforms on
3433 * the CPU in a typical paint, so at some point we should
3434 * audit these and consider caching some things.
3436 * NB: We don't perform culling while picking at this point because
3437 * clutter-stage.c doesn't setup the clipping planes appropriately.
3439 * NB: We don't want to update the last-paint-volume during picking
3440 * because the last-paint-volume is used to determine the old screen
3441 * space location of an actor that has moved so we can know the
3442 * minimal region to redraw to clear an old view of the actor. If we
3443 * update this during picking then by the time we come around to
3444 * paint then the last-paint-volume would likely represent the new
3445 * actor position not the old.
3447 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3450 /* annoyingly gcc warns if uninitialized even though
3451 * the initialization is redundant :-( */
3452 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3454 if (G_LIKELY ((clutter_paint_debug_flags &
3455 (CLUTTER_DEBUG_DISABLE_CULLING |
3456 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3457 (CLUTTER_DEBUG_DISABLE_CULLING |
3458 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3459 _clutter_actor_update_last_paint_volume (self);
3461 success = cull_actor (self, &result);
3463 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3464 _clutter_actor_paint_cull_result (self, success, result);
3465 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3469 if (priv->effects == NULL)
3471 if (pick_mode == CLUTTER_PICK_NONE &&
3472 actor_has_shader_data (self))
3474 _clutter_actor_shader_pre_paint (self, FALSE);
3475 shader_applied = TRUE;
3478 priv->next_effect_to_paint = NULL;
3481 priv->next_effect_to_paint =
3482 _clutter_meta_group_peek_metas (priv->effects);
3484 clutter_actor_continue_paint (self);
3487 _clutter_actor_shader_post_paint (self);
3489 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3490 pick_mode == CLUTTER_PICK_NONE))
3491 _clutter_actor_draw_paint_volume (self);
3494 /* If we make it here then the actor has run through a complete
3495 paint run including all the effects so it's no longer dirty */
3496 if (pick_mode == CLUTTER_PICK_NONE)
3497 priv->is_dirty = FALSE;
3504 /* paint sequence complete */
3505 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3509 * clutter_actor_continue_paint:
3510 * @self: A #ClutterActor
3512 * Run the next stage of the paint sequence. This function should only
3513 * be called within the implementation of the ‘run’ virtual of a
3514 * #ClutterEffect. It will cause the run method of the next effect to
3515 * be applied, or it will paint the actual actor if the current effect
3516 * is the last effect in the chain.
3521 clutter_actor_continue_paint (ClutterActor *self)
3523 ClutterActorPrivate *priv;
3525 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3526 /* This should only be called from with in the ‘run’ implementation
3527 of a ClutterEffect */
3528 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3532 /* Skip any effects that are disabled */
3533 while (priv->next_effect_to_paint &&
3534 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3535 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3537 /* If this has come from the last effect then we'll just paint the
3539 if (priv->next_effect_to_paint == NULL)
3541 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3543 ClutterPaintNode *dummy;
3544 gboolean emit_paint = TRUE;
3546 /* XXX - this will go away in 2.0, when we can get rid of this
3547 * stuff and switch to a pure retained render tree of PaintNodes
3548 * for the entire frame, starting from the Stage; the paint()
3549 * virtual function can then be called directly.
3551 dummy = _clutter_dummy_node_new ();
3552 clutter_paint_node_set_name (dummy, "Root");
3554 /* XXX - for 1.12, we use the return value of paint_node() to
3555 * set the emit_paint variable.
3557 clutter_actor_paint_node (self, dummy);
3558 clutter_paint_node_unref (dummy);
3560 if (emit_paint || CLUTTER_ACTOR_IS_TOPLEVEL (self))
3561 g_signal_emit (self, actor_signals[PAINT], 0);
3564 CLUTTER_NOTE (PAINT, "The actor '%s' painted using PaintNodes, "
3565 "skipping the emission of the paint signal.",
3566 _clutter_actor_get_debug_name (self));
3571 ClutterColor col = { 0, };
3573 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3575 /* Actor will then paint silhouette of itself in supplied
3576 * color. See clutter_stage_get_actor_at_pos() for where
3577 * picking is enabled.
3579 g_signal_emit (self, actor_signals[PICK], 0, &col);
3584 ClutterEffect *old_current_effect;
3585 ClutterEffectPaintFlags run_flags = 0;
3587 /* Cache the current effect so that we can put it back before
3589 old_current_effect = priv->current_effect;
3591 priv->current_effect = priv->next_effect_to_paint->data;
3592 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3594 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3598 /* If there's an effect queued with this redraw then all
3599 effects up to that one will be considered dirty. It
3600 is expected the queued effect will paint the cached
3601 image and not call clutter_actor_continue_paint again
3602 (although it should work ok if it does) */
3603 if (priv->effect_to_redraw == NULL ||
3604 priv->current_effect != priv->effect_to_redraw)
3605 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3608 _clutter_effect_paint (priv->current_effect, run_flags);
3612 /* We can't determine when an actor has been modified since
3613 its last pick so lets just assume it has always been
3615 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3617 _clutter_effect_pick (priv->current_effect, run_flags);
3620 priv->current_effect = old_current_effect;
3624 static ClutterActorTraverseVisitFlags
3625 invalidate_queue_redraw_entry (ClutterActor *self,
3629 ClutterActorPrivate *priv = self->priv;
3631 if (priv->queue_redraw_entry != NULL)
3633 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3634 priv->queue_redraw_entry = NULL;
3637 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3641 remove_child (ClutterActor *self,
3642 ClutterActor *child)
3644 ClutterActor *prev_sibling, *next_sibling;
3646 prev_sibling = child->priv->prev_sibling;
3647 next_sibling = child->priv->next_sibling;
3649 if (prev_sibling != NULL)
3650 prev_sibling->priv->next_sibling = next_sibling;
3652 if (next_sibling != NULL)
3653 next_sibling->priv->prev_sibling = prev_sibling;
3655 if (self->priv->first_child == child)
3656 self->priv->first_child = next_sibling;
3658 if (self->priv->last_child == child)
3659 self->priv->last_child = prev_sibling;
3661 child->priv->parent = NULL;
3662 child->priv->prev_sibling = NULL;
3663 child->priv->next_sibling = NULL;
3667 REMOVE_CHILD_DESTROY_META = 1 << 0,
3668 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3669 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3670 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3671 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3672 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3674 /* default flags for public API */
3675 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3676 REMOVE_CHILD_EMIT_PARENT_SET |
3677 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3678 REMOVE_CHILD_CHECK_STATE |
3679 REMOVE_CHILD_FLUSH_QUEUE |
3680 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3682 /* flags for legacy/deprecated API */
3683 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3684 REMOVE_CHILD_FLUSH_QUEUE |
3685 REMOVE_CHILD_EMIT_PARENT_SET |
3686 REMOVE_CHILD_NOTIFY_FIRST_LAST
3687 } ClutterActorRemoveChildFlags;
3690 * clutter_actor_remove_child_internal:
3691 * @self: a #ClutterActor
3692 * @child: the child of @self that has to be removed
3693 * @flags: control the removal operations
3695 * Removes @child from the list of children of @self.
3698 clutter_actor_remove_child_internal (ClutterActor *self,
3699 ClutterActor *child,
3700 ClutterActorRemoveChildFlags flags)
3702 ClutterActor *old_first, *old_last;
3703 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3704 gboolean flush_queue;
3705 gboolean notify_first_last;
3706 gboolean was_mapped;
3708 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3709 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3710 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3711 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3712 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3713 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3715 g_object_freeze_notify (G_OBJECT (self));
3718 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3722 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3724 /* we need to unrealize *before* we set parent_actor to NULL,
3725 * because in an unrealize method actors are dissociating from the
3726 * stage, which means they need to be able to
3727 * clutter_actor_get_stage().
3729 * yhis should unmap and unrealize, unless we're reparenting.
3731 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3738 /* We take this opportunity to invalidate any queue redraw entry
3739 * associated with the actor and descendants since we won't be able to
3740 * determine the appropriate stage after this.
3742 * we do this after we updated the mapped state because actors might
3743 * end up queueing redraws inside their mapped/unmapped virtual
3744 * functions, and if we invalidate the redraw entry we could end up
3745 * with an inconsistent state and weird memory corruption. see
3748 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3749 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3751 _clutter_actor_traverse (child,
3753 invalidate_queue_redraw_entry,
3758 old_first = self->priv->first_child;
3759 old_last = self->priv->last_child;
3761 remove_child (self, child);
3763 self->priv->n_children -= 1;
3765 self->priv->age += 1;
3767 /* clutter_actor_reparent() will emit ::parent-set for us */
3768 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3769 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3771 /* if the child was mapped then we need to relayout ourselves to account
3772 * for the removed child
3775 clutter_actor_queue_relayout (self);
3777 /* we need to emit the signal before dropping the reference */
3778 if (emit_actor_removed)
3779 g_signal_emit_by_name (self, "actor-removed", child);
3781 if (notify_first_last)
3783 if (old_first != self->priv->first_child)
3784 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3786 if (old_last != self->priv->last_child)
3787 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3790 g_object_thaw_notify (G_OBJECT (self));
3792 /* remove the reference we acquired in clutter_actor_add_child() */
3793 g_object_unref (child);
3796 static const ClutterTransformInfo default_transform_info = {
3797 0.0, { 0, }, /* rotation-x */
3798 0.0, { 0, }, /* rotation-y */
3799 0.0, { 0, }, /* rotation-z */
3801 1.0, 1.0, { 0, }, /* scale */
3803 { 0, }, /* anchor */
3809 * _clutter_actor_get_transform_info_or_defaults:
3810 * @self: a #ClutterActor
3812 * Retrieves the ClutterTransformInfo structure associated to an actor.
3814 * If the actor does not have a ClutterTransformInfo structure associated
3815 * to it, then the default structure will be returned.
3817 * This function should only be used for getters.
3819 * Return value: a const pointer to the ClutterTransformInfo structure
3821 const ClutterTransformInfo *
3822 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3824 ClutterTransformInfo *info;
3826 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3830 return &default_transform_info;
3834 clutter_transform_info_free (gpointer data)
3837 g_slice_free (ClutterTransformInfo, data);
3841 * _clutter_actor_get_transform_info:
3842 * @self: a #ClutterActor
3844 * Retrieves a pointer to the ClutterTransformInfo structure.
3846 * If the actor does not have a ClutterTransformInfo associated to it, one
3847 * will be created and initialized to the default values.
3849 * This function should be used for setters.
3851 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3854 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3857 ClutterTransformInfo *
3858 _clutter_actor_get_transform_info (ClutterActor *self)
3860 ClutterTransformInfo *info;
3862 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3865 info = g_slice_new (ClutterTransformInfo);
3867 *info = default_transform_info;
3869 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3871 clutter_transform_info_free);
3878 * clutter_actor_set_rotation_angle_internal:
3879 * @self: a #ClutterActor
3880 * @axis: the axis of the angle to change
3881 * @angle: the angle of rotation
3883 * Sets the rotation angle on the given axis without affecting the
3884 * rotation center point.
3887 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3888 ClutterRotateAxis axis,
3891 GObject *obj = G_OBJECT (self);
3892 ClutterTransformInfo *info;
3894 info = _clutter_actor_get_transform_info (self);
3896 g_object_freeze_notify (obj);
3900 case CLUTTER_X_AXIS:
3901 info->rx_angle = angle;
3902 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3905 case CLUTTER_Y_AXIS:
3906 info->ry_angle = angle;
3907 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3910 case CLUTTER_Z_AXIS:
3911 info->rz_angle = angle;
3912 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3916 self->priv->transform_valid = FALSE;
3918 g_object_thaw_notify (obj);
3920 clutter_actor_queue_redraw (self);
3924 clutter_actor_set_rotation_angle (ClutterActor *self,
3925 ClutterRotateAxis axis,
3928 ClutterTransformInfo *info;
3930 info = _clutter_actor_get_transform_info (self);
3932 if (clutter_actor_get_easing_duration (self) != 0)
3934 ClutterTransition *transition;
3935 GParamSpec *pspec = NULL;
3936 double *cur_angle_p = NULL;
3940 case CLUTTER_X_AXIS:
3941 cur_angle_p = &info->rx_angle;
3942 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3945 case CLUTTER_Y_AXIS:
3946 cur_angle_p = &info->ry_angle;
3947 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3950 case CLUTTER_Z_AXIS:
3951 cur_angle_p = &info->rz_angle;
3952 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3956 g_assert (pspec != NULL);
3957 g_assert (cur_angle_p != NULL);
3959 transition = _clutter_actor_get_transition (self, pspec);
3960 if (transition == NULL)
3962 transition = _clutter_actor_create_transition (self, pspec,
3965 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3968 _clutter_actor_update_transition (self, pspec, angle);
3970 self->priv->transform_valid = FALSE;
3971 clutter_actor_queue_redraw (self);
3974 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3978 * clutter_actor_set_rotation_center_internal:
3979 * @self: a #ClutterActor
3980 * @axis: the axis of the center to change
3981 * @center: the coordinates of the rotation center
3983 * Sets the rotation center on the given axis without affecting the
3987 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3988 ClutterRotateAxis axis,
3989 const ClutterVertex *center)
3991 GObject *obj = G_OBJECT (self);
3992 ClutterTransformInfo *info;
3993 ClutterVertex v = { 0, 0, 0 };
3995 info = _clutter_actor_get_transform_info (self);
4000 g_object_freeze_notify (obj);
4004 case CLUTTER_X_AXIS:
4005 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4006 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4009 case CLUTTER_Y_AXIS:
4010 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4011 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4014 case CLUTTER_Z_AXIS:
4015 /* if the previously set rotation center was fractional, then
4016 * setting explicit coordinates will have to notify the
4017 * :rotation-center-z-gravity property as well
4019 if (info->rz_center.is_fractional)
4020 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4022 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4023 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4027 self->priv->transform_valid = FALSE;
4029 g_object_thaw_notify (obj);
4031 clutter_actor_queue_redraw (self);
4035 clutter_actor_animate_scale_factor (ClutterActor *self,
4040 ClutterTransition *transition;
4042 transition = _clutter_actor_get_transition (self, pspec);
4043 if (transition == NULL)
4045 transition = _clutter_actor_create_transition (self, pspec,
4048 clutter_timeline_start (CLUTTER_TIMELINE (transition));
4051 _clutter_actor_update_transition (self, pspec, new_factor);
4054 self->priv->transform_valid = FALSE;
4055 clutter_actor_queue_redraw (self);
4059 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4063 GObject *obj = G_OBJECT (self);
4064 ClutterTransformInfo *info;
4066 info = _clutter_actor_get_transform_info (self);
4068 if (pspec == obj_props[PROP_SCALE_X])
4069 info->scale_x = factor;
4071 info->scale_y = factor;
4073 self->priv->transform_valid = FALSE;
4074 clutter_actor_queue_redraw (self);
4075 g_object_notify_by_pspec (obj, pspec);
4079 clutter_actor_set_scale_factor (ClutterActor *self,
4080 ClutterRotateAxis axis,
4083 GObject *obj = G_OBJECT (self);
4084 ClutterTransformInfo *info;
4087 info = _clutter_actor_get_transform_info (self);
4089 g_object_freeze_notify (obj);
4093 case CLUTTER_X_AXIS:
4094 pspec = obj_props[PROP_SCALE_X];
4096 if (clutter_actor_get_easing_duration (self) != 0)
4097 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4099 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4102 case CLUTTER_Y_AXIS:
4103 pspec = obj_props[PROP_SCALE_Y];
4105 if (clutter_actor_get_easing_duration (self) != 0)
4106 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4108 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4112 g_assert_not_reached ();
4115 g_object_thaw_notify (obj);
4119 clutter_actor_set_scale_center (ClutterActor *self,
4120 ClutterRotateAxis axis,
4123 GObject *obj = G_OBJECT (self);
4124 ClutterTransformInfo *info;
4125 gfloat center_x, center_y;
4127 info = _clutter_actor_get_transform_info (self);
4129 g_object_freeze_notify (obj);
4131 /* get the current scale center coordinates */
4132 clutter_anchor_coord_get_units (self, &info->scale_center,
4137 /* we need to notify this too, because setting explicit coordinates will
4138 * change the gravity as a side effect
4140 if (info->scale_center.is_fractional)
4141 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4145 case CLUTTER_X_AXIS:
4146 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4147 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4150 case CLUTTER_Y_AXIS:
4151 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4152 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4156 g_assert_not_reached ();
4159 self->priv->transform_valid = FALSE;
4161 clutter_actor_queue_redraw (self);
4163 g_object_thaw_notify (obj);
4167 clutter_actor_set_anchor_coord (ClutterActor *self,
4168 ClutterRotateAxis axis,
4171 GObject *obj = G_OBJECT (self);
4172 ClutterTransformInfo *info;
4173 gfloat anchor_x, anchor_y;
4175 info = _clutter_actor_get_transform_info (self);
4177 g_object_freeze_notify (obj);
4179 clutter_anchor_coord_get_units (self, &info->anchor,
4184 if (info->anchor.is_fractional)
4185 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4189 case CLUTTER_X_AXIS:
4190 clutter_anchor_coord_set_units (&info->anchor,
4194 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4197 case CLUTTER_Y_AXIS:
4198 clutter_anchor_coord_set_units (&info->anchor,
4202 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4206 g_assert_not_reached ();
4209 self->priv->transform_valid = FALSE;
4211 clutter_actor_queue_redraw (self);
4213 g_object_thaw_notify (obj);
4217 clutter_actor_set_property (GObject *object,
4219 const GValue *value,
4222 ClutterActor *actor = CLUTTER_ACTOR (object);
4223 ClutterActorPrivate *priv = actor->priv;
4228 clutter_actor_set_x (actor, g_value_get_float (value));
4232 clutter_actor_set_y (actor, g_value_get_float (value));
4236 clutter_actor_set_width (actor, g_value_get_float (value));
4240 clutter_actor_set_height (actor, g_value_get_float (value));
4244 clutter_actor_set_x (actor, g_value_get_float (value));
4248 clutter_actor_set_y (actor, g_value_get_float (value));
4251 case PROP_FIXED_POSITION_SET:
4252 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4255 case PROP_MIN_WIDTH:
4256 clutter_actor_set_min_width (actor, g_value_get_float (value));
4259 case PROP_MIN_HEIGHT:
4260 clutter_actor_set_min_height (actor, g_value_get_float (value));
4263 case PROP_NATURAL_WIDTH:
4264 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4267 case PROP_NATURAL_HEIGHT:
4268 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4271 case PROP_MIN_WIDTH_SET:
4272 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4275 case PROP_MIN_HEIGHT_SET:
4276 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4279 case PROP_NATURAL_WIDTH_SET:
4280 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4283 case PROP_NATURAL_HEIGHT_SET:
4284 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4287 case PROP_REQUEST_MODE:
4288 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4292 clutter_actor_set_depth (actor, g_value_get_float (value));
4296 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4299 case PROP_OFFSCREEN_REDIRECT:
4300 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4304 clutter_actor_set_name (actor, g_value_get_string (value));
4308 if (g_value_get_boolean (value) == TRUE)
4309 clutter_actor_show (actor);
4311 clutter_actor_hide (actor);
4315 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4316 g_value_get_double (value));
4320 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4321 g_value_get_double (value));
4324 case PROP_SCALE_CENTER_X:
4325 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4326 g_value_get_float (value));
4329 case PROP_SCALE_CENTER_Y:
4330 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4331 g_value_get_float (value));
4334 case PROP_SCALE_GRAVITY:
4336 const ClutterTransformInfo *info;
4337 ClutterGravity gravity;
4339 info = _clutter_actor_get_transform_info_or_defaults (actor);
4340 gravity = g_value_get_enum (value);
4342 clutter_actor_set_scale_with_gravity (actor,
4351 const ClutterGeometry *geom = g_value_get_boxed (value);
4353 clutter_actor_set_clip (actor,
4355 geom->width, geom->height);
4359 case PROP_CLIP_TO_ALLOCATION:
4360 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4364 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4367 case PROP_ROTATION_ANGLE_X:
4368 clutter_actor_set_rotation_angle (actor,
4370 g_value_get_double (value));
4373 case PROP_ROTATION_ANGLE_Y:
4374 clutter_actor_set_rotation_angle (actor,
4376 g_value_get_double (value));
4379 case PROP_ROTATION_ANGLE_Z:
4380 clutter_actor_set_rotation_angle (actor,
4382 g_value_get_double (value));
4385 case PROP_ROTATION_CENTER_X:
4386 clutter_actor_set_rotation_center_internal (actor,
4388 g_value_get_boxed (value));
4391 case PROP_ROTATION_CENTER_Y:
4392 clutter_actor_set_rotation_center_internal (actor,
4394 g_value_get_boxed (value));
4397 case PROP_ROTATION_CENTER_Z:
4398 clutter_actor_set_rotation_center_internal (actor,
4400 g_value_get_boxed (value));
4403 case PROP_ROTATION_CENTER_Z_GRAVITY:
4405 const ClutterTransformInfo *info;
4407 info = _clutter_actor_get_transform_info_or_defaults (actor);
4408 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4409 g_value_get_enum (value));
4414 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4415 g_value_get_float (value));
4419 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4420 g_value_get_float (value));
4423 case PROP_ANCHOR_GRAVITY:
4424 clutter_actor_set_anchor_point_from_gravity (actor,
4425 g_value_get_enum (value));
4428 case PROP_SHOW_ON_SET_PARENT:
4429 priv->show_on_set_parent = g_value_get_boolean (value);
4432 case PROP_TEXT_DIRECTION:
4433 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4437 clutter_actor_add_action (actor, g_value_get_object (value));
4440 case PROP_CONSTRAINTS:
4441 clutter_actor_add_constraint (actor, g_value_get_object (value));
4445 clutter_actor_add_effect (actor, g_value_get_object (value));
4448 case PROP_LAYOUT_MANAGER:
4449 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4453 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4457 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4460 case PROP_MARGIN_TOP:
4461 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4464 case PROP_MARGIN_BOTTOM:
4465 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4468 case PROP_MARGIN_LEFT:
4469 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4472 case PROP_MARGIN_RIGHT:
4473 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4476 case PROP_BACKGROUND_COLOR:
4477 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4481 clutter_actor_set_content (actor, g_value_get_object (value));
4484 case PROP_CONTENT_GRAVITY:
4485 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4488 case PROP_MINIFICATION_FILTER:
4489 clutter_actor_set_content_scaling_filters (actor,
4490 g_value_get_enum (value),
4491 actor->priv->mag_filter);
4494 case PROP_MAGNIFICATION_FILTER:
4495 clutter_actor_set_content_scaling_filters (actor,
4496 actor->priv->min_filter,
4497 g_value_get_enum (value));
4501 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4507 clutter_actor_get_property (GObject *object,
4512 ClutterActor *actor = CLUTTER_ACTOR (object);
4513 ClutterActorPrivate *priv = actor->priv;
4518 g_value_set_float (value, clutter_actor_get_x (actor));
4522 g_value_set_float (value, clutter_actor_get_y (actor));
4526 g_value_set_float (value, clutter_actor_get_width (actor));
4530 g_value_set_float (value, clutter_actor_get_height (actor));
4535 const ClutterLayoutInfo *info;
4537 info = _clutter_actor_get_layout_info_or_defaults (actor);
4538 g_value_set_float (value, info->fixed_x);
4544 const ClutterLayoutInfo *info;
4546 info = _clutter_actor_get_layout_info_or_defaults (actor);
4547 g_value_set_float (value, info->fixed_y);
4551 case PROP_FIXED_POSITION_SET:
4552 g_value_set_boolean (value, priv->position_set);
4555 case PROP_MIN_WIDTH:
4557 const ClutterLayoutInfo *info;
4559 info = _clutter_actor_get_layout_info_or_defaults (actor);
4560 g_value_set_float (value, info->min_width);
4564 case PROP_MIN_HEIGHT:
4566 const ClutterLayoutInfo *info;
4568 info = _clutter_actor_get_layout_info_or_defaults (actor);
4569 g_value_set_float (value, info->min_height);
4573 case PROP_NATURAL_WIDTH:
4575 const ClutterLayoutInfo *info;
4577 info = _clutter_actor_get_layout_info_or_defaults (actor);
4578 g_value_set_float (value, info->natural_width);
4582 case PROP_NATURAL_HEIGHT:
4584 const ClutterLayoutInfo *info;
4586 info = _clutter_actor_get_layout_info_or_defaults (actor);
4587 g_value_set_float (value, info->natural_height);
4591 case PROP_MIN_WIDTH_SET:
4592 g_value_set_boolean (value, priv->min_width_set);
4595 case PROP_MIN_HEIGHT_SET:
4596 g_value_set_boolean (value, priv->min_height_set);
4599 case PROP_NATURAL_WIDTH_SET:
4600 g_value_set_boolean (value, priv->natural_width_set);
4603 case PROP_NATURAL_HEIGHT_SET:
4604 g_value_set_boolean (value, priv->natural_height_set);
4607 case PROP_REQUEST_MODE:
4608 g_value_set_enum (value, priv->request_mode);
4611 case PROP_ALLOCATION:
4612 g_value_set_boxed (value, &priv->allocation);
4616 g_value_set_float (value, clutter_actor_get_depth (actor));
4620 g_value_set_uint (value, priv->opacity);
4623 case PROP_OFFSCREEN_REDIRECT:
4624 g_value_set_enum (value, priv->offscreen_redirect);
4628 g_value_set_string (value, priv->name);
4632 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4636 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4640 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4644 g_value_set_boolean (value, priv->has_clip);
4649 ClutterGeometry clip;
4651 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4652 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4653 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4654 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4656 g_value_set_boxed (value, &clip);
4660 case PROP_CLIP_TO_ALLOCATION:
4661 g_value_set_boolean (value, priv->clip_to_allocation);
4666 const ClutterTransformInfo *info;
4668 info = _clutter_actor_get_transform_info_or_defaults (actor);
4669 g_value_set_double (value, info->scale_x);
4675 const ClutterTransformInfo *info;
4677 info = _clutter_actor_get_transform_info_or_defaults (actor);
4678 g_value_set_double (value, info->scale_y);
4682 case PROP_SCALE_CENTER_X:
4686 clutter_actor_get_scale_center (actor, ¢er, NULL);
4688 g_value_set_float (value, center);
4692 case PROP_SCALE_CENTER_Y:
4696 clutter_actor_get_scale_center (actor, NULL, ¢er);
4698 g_value_set_float (value, center);
4702 case PROP_SCALE_GRAVITY:
4703 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4707 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4710 case PROP_ROTATION_ANGLE_X:
4712 const ClutterTransformInfo *info;
4714 info = _clutter_actor_get_transform_info_or_defaults (actor);
4715 g_value_set_double (value, info->rx_angle);
4719 case PROP_ROTATION_ANGLE_Y:
4721 const ClutterTransformInfo *info;
4723 info = _clutter_actor_get_transform_info_or_defaults (actor);
4724 g_value_set_double (value, info->ry_angle);
4728 case PROP_ROTATION_ANGLE_Z:
4730 const ClutterTransformInfo *info;
4732 info = _clutter_actor_get_transform_info_or_defaults (actor);
4733 g_value_set_double (value, info->rz_angle);
4737 case PROP_ROTATION_CENTER_X:
4739 ClutterVertex center;
4741 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4746 g_value_set_boxed (value, ¢er);
4750 case PROP_ROTATION_CENTER_Y:
4752 ClutterVertex center;
4754 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4759 g_value_set_boxed (value, ¢er);
4763 case PROP_ROTATION_CENTER_Z:
4765 ClutterVertex center;
4767 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4772 g_value_set_boxed (value, ¢er);
4776 case PROP_ROTATION_CENTER_Z_GRAVITY:
4777 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4782 const ClutterTransformInfo *info;
4785 info = _clutter_actor_get_transform_info_or_defaults (actor);
4786 clutter_anchor_coord_get_units (actor, &info->anchor,
4790 g_value_set_float (value, anchor_x);
4796 const ClutterTransformInfo *info;
4799 info = _clutter_actor_get_transform_info_or_defaults (actor);
4800 clutter_anchor_coord_get_units (actor, &info->anchor,
4804 g_value_set_float (value, anchor_y);
4808 case PROP_ANCHOR_GRAVITY:
4809 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4812 case PROP_SHOW_ON_SET_PARENT:
4813 g_value_set_boolean (value, priv->show_on_set_parent);
4816 case PROP_TEXT_DIRECTION:
4817 g_value_set_enum (value, priv->text_direction);
4820 case PROP_HAS_POINTER:
4821 g_value_set_boolean (value, priv->has_pointer);
4824 case PROP_LAYOUT_MANAGER:
4825 g_value_set_object (value, priv->layout_manager);
4830 const ClutterLayoutInfo *info;
4832 info = _clutter_actor_get_layout_info_or_defaults (actor);
4833 g_value_set_enum (value, info->x_align);
4839 const ClutterLayoutInfo *info;
4841 info = _clutter_actor_get_layout_info_or_defaults (actor);
4842 g_value_set_enum (value, info->y_align);
4846 case PROP_MARGIN_TOP:
4848 const ClutterLayoutInfo *info;
4850 info = _clutter_actor_get_layout_info_or_defaults (actor);
4851 g_value_set_float (value, info->margin.top);
4855 case PROP_MARGIN_BOTTOM:
4857 const ClutterLayoutInfo *info;
4859 info = _clutter_actor_get_layout_info_or_defaults (actor);
4860 g_value_set_float (value, info->margin.bottom);
4864 case PROP_MARGIN_LEFT:
4866 const ClutterLayoutInfo *info;
4868 info = _clutter_actor_get_layout_info_or_defaults (actor);
4869 g_value_set_float (value, info->margin.left);
4873 case PROP_MARGIN_RIGHT:
4875 const ClutterLayoutInfo *info;
4877 info = _clutter_actor_get_layout_info_or_defaults (actor);
4878 g_value_set_float (value, info->margin.right);
4882 case PROP_BACKGROUND_COLOR_SET:
4883 g_value_set_boolean (value, priv->bg_color_set);
4886 case PROP_BACKGROUND_COLOR:
4887 g_value_set_boxed (value, &priv->bg_color);
4890 case PROP_FIRST_CHILD:
4891 g_value_set_object (value, priv->first_child);
4894 case PROP_LAST_CHILD:
4895 g_value_set_object (value, priv->last_child);
4899 g_value_set_object (value, priv->content);
4902 case PROP_CONTENT_GRAVITY:
4903 g_value_set_enum (value, priv->content_gravity);
4906 case PROP_CONTENT_BOX:
4908 ClutterActorBox box = { 0, };
4910 clutter_actor_get_content_box (actor, &box);
4911 g_value_set_boxed (value, &box);
4915 case PROP_MINIFICATION_FILTER:
4916 g_value_set_enum (value, priv->min_filter);
4919 case PROP_MAGNIFICATION_FILTER:
4920 g_value_set_enum (value, priv->mag_filter);
4924 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4930 clutter_actor_dispose (GObject *object)
4932 ClutterActor *self = CLUTTER_ACTOR (object);
4933 ClutterActorPrivate *priv = self->priv;
4935 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4937 g_type_name (G_OBJECT_TYPE (self)),
4940 g_signal_emit (self, actor_signals[DESTROY], 0);
4942 /* avoid recursing when called from clutter_actor_destroy() */
4943 if (priv->parent != NULL)
4945 ClutterActor *parent = priv->parent;
4947 /* go through the Container implementation unless this
4948 * is an internal child and has been marked as such.
4950 * removing the actor from its parent will reset the
4951 * realized and mapped states.
4953 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4954 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4956 clutter_actor_remove_child_internal (parent, self,
4957 REMOVE_CHILD_LEGACY_FLAGS);
4960 /* parent must be gone at this point */
4961 g_assert (priv->parent == NULL);
4963 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4965 /* can't be mapped or realized with no parent */
4966 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4967 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4970 g_clear_object (&priv->pango_context);
4971 g_clear_object (&priv->actions);
4972 g_clear_object (&priv->constraints);
4973 g_clear_object (&priv->effects);
4974 g_clear_object (&priv->flatten_effect);
4976 if (priv->layout_manager != NULL)
4978 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4979 g_clear_object (&priv->layout_manager);
4982 if (priv->content != NULL)
4984 _clutter_content_detached (priv->content, self);
4985 g_clear_object (&priv->content);
4988 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4992 clutter_actor_finalize (GObject *object)
4994 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4996 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4997 priv->name != NULL ? priv->name : "<none>",
4999 g_type_name (G_OBJECT_TYPE (object)));
5001 _clutter_context_release_id (priv->id);
5003 g_free (priv->name);
5005 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5010 * clutter_actor_get_accessible:
5011 * @self: a #ClutterActor
5013 * Returns the accessible object that describes the actor to an
5014 * assistive technology.
5016 * If no class-specific #AtkObject implementation is available for the
5017 * actor instance in question, it will inherit an #AtkObject
5018 * implementation from the first ancestor class for which such an
5019 * implementation is defined.
5021 * The documentation of the <ulink
5022 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5023 * library contains more information about accessible objects and
5026 * Returns: (transfer none): the #AtkObject associated with @actor
5029 clutter_actor_get_accessible (ClutterActor *self)
5031 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5033 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5037 clutter_actor_real_get_accessible (ClutterActor *actor)
5039 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5043 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5045 AtkObject *accessible;
5047 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5048 if (accessible != NULL)
5049 g_object_ref (accessible);
5055 atk_implementor_iface_init (AtkImplementorIface *iface)
5057 iface->ref_accessible = _clutter_actor_ref_accessible;
5061 clutter_actor_update_default_paint_volume (ClutterActor *self,
5062 ClutterPaintVolume *volume)
5064 ClutterActorPrivate *priv = self->priv;
5065 gboolean res = FALSE;
5067 /* we start from the allocation */
5068 clutter_paint_volume_set_width (volume,
5069 priv->allocation.x2 - priv->allocation.x1);
5070 clutter_paint_volume_set_height (volume,
5071 priv->allocation.y2 - priv->allocation.y1);
5073 /* if the actor has a clip set then we have a pretty definite
5074 * size for the paint volume: the actor cannot possibly paint
5075 * outside the clip region.
5077 if (priv->clip_to_allocation)
5079 /* the allocation has already been set, so we just flip the
5086 ClutterActor *child;
5088 if (priv->has_clip &&
5089 priv->clip.width >= 0 &&
5090 priv->clip.height >= 0)
5092 ClutterVertex origin;
5094 origin.x = priv->clip.x;
5095 origin.y = priv->clip.y;
5098 clutter_paint_volume_set_origin (volume, &origin);
5099 clutter_paint_volume_set_width (volume, priv->clip.width);
5100 clutter_paint_volume_set_height (volume, priv->clip.height);
5105 /* if we don't have children we just bail out here... */
5106 if (priv->n_children == 0)
5109 /* ...but if we have children then we ask for their paint volume in
5110 * our coordinates. if any of our children replies that it doesn't
5111 * have a paint volume, we bail out
5113 for (child = priv->first_child;
5115 child = child->priv->next_sibling)
5117 const ClutterPaintVolume *child_volume;
5119 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5120 if (child_volume == NULL)
5126 clutter_paint_volume_union (volume, child_volume);
5136 clutter_actor_real_get_paint_volume (ClutterActor *self,
5137 ClutterPaintVolume *volume)
5139 ClutterActorClass *klass;
5142 klass = CLUTTER_ACTOR_GET_CLASS (self);
5144 /* XXX - this thoroughly sucks, but we don't want to penalize users
5145 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5146 * redraw. This should go away in 2.0.
5148 if (klass->paint == clutter_actor_real_paint &&
5149 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5155 /* this is the default return value: we cannot know if a class
5156 * is going to paint outside its allocation, so we take the
5157 * conservative approach.
5162 if (clutter_actor_update_default_paint_volume (self, volume))
5169 * clutter_actor_get_default_paint_volume:
5170 * @self: a #ClutterActor
5172 * Retrieves the default paint volume for @self.
5174 * This function provides the same #ClutterPaintVolume that would be
5175 * computed by the default implementation inside #ClutterActor of the
5176 * #ClutterActorClass.get_paint_volume() virtual function.
5178 * This function should only be used by #ClutterActor subclasses that
5179 * cannot chain up to the parent implementation when computing their
5182 * Return value: (transfer none): a pointer to the default
5183 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5184 * the actor could not compute a valid paint volume. The returned value
5185 * is not guaranteed to be stable across multiple frames, so if you
5186 * want to retain it, you will need to copy it using
5187 * clutter_paint_volume_copy().
5191 const ClutterPaintVolume *
5192 clutter_actor_get_default_paint_volume (ClutterActor *self)
5194 ClutterPaintVolume volume;
5195 ClutterPaintVolume *res;
5197 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5200 _clutter_paint_volume_init_static (&volume, self);
5201 if (clutter_actor_update_default_paint_volume (self, &volume))
5203 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5207 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5208 _clutter_paint_volume_copy_static (&volume, res);
5212 clutter_paint_volume_free (&volume);
5218 clutter_actor_real_has_overlaps (ClutterActor *self)
5220 /* By default we'll assume that all actors need an offscreen redirect to get
5221 * the correct opacity. Actors such as ClutterTexture that would never need
5222 * an offscreen redirect can override this to return FALSE. */
5227 clutter_actor_real_destroy (ClutterActor *actor)
5229 ClutterActorIter iter;
5231 clutter_actor_iter_init (&iter, actor);
5232 while (clutter_actor_iter_next (&iter, NULL))
5233 clutter_actor_iter_destroy (&iter);
5237 clutter_actor_constructor (GType gtype,
5239 GObjectConstructParam *props)
5241 GObjectClass *gobject_class;
5245 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5246 retval = gobject_class->constructor (gtype, n_props, props);
5247 self = CLUTTER_ACTOR (retval);
5249 if (self->priv->layout_manager == NULL)
5251 ClutterLayoutManager *default_layout;
5253 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5255 default_layout = clutter_fixed_layout_new ();
5256 clutter_actor_set_layout_manager (self, default_layout);
5263 clutter_actor_class_init (ClutterActorClass *klass)
5265 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5267 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5268 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5269 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5270 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5272 object_class->constructor = clutter_actor_constructor;
5273 object_class->set_property = clutter_actor_set_property;
5274 object_class->get_property = clutter_actor_get_property;
5275 object_class->dispose = clutter_actor_dispose;
5276 object_class->finalize = clutter_actor_finalize;
5278 klass->show = clutter_actor_real_show;
5279 klass->show_all = clutter_actor_show;
5280 klass->hide = clutter_actor_real_hide;
5281 klass->hide_all = clutter_actor_hide;
5282 klass->map = clutter_actor_real_map;
5283 klass->unmap = clutter_actor_real_unmap;
5284 klass->unrealize = clutter_actor_real_unrealize;
5285 klass->pick = clutter_actor_real_pick;
5286 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5287 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5288 klass->allocate = clutter_actor_real_allocate;
5289 klass->queue_redraw = clutter_actor_real_queue_redraw;
5290 klass->queue_relayout = clutter_actor_real_queue_relayout;
5291 klass->apply_transform = clutter_actor_real_apply_transform;
5292 klass->get_accessible = clutter_actor_real_get_accessible;
5293 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5294 klass->has_overlaps = clutter_actor_real_has_overlaps;
5295 klass->paint = clutter_actor_real_paint;
5296 klass->destroy = clutter_actor_real_destroy;
5298 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5303 * X coordinate of the actor in pixels. If written, forces a fixed
5304 * position for the actor. If read, returns the fixed position if any,
5305 * otherwise the allocation if available, otherwise 0.
5307 * The #ClutterActor:x property is animatable.
5310 g_param_spec_float ("x",
5312 P_("X coordinate of the actor"),
5313 -G_MAXFLOAT, G_MAXFLOAT,
5316 G_PARAM_STATIC_STRINGS |
5317 CLUTTER_PARAM_ANIMATABLE);
5322 * Y coordinate of the actor in pixels. If written, forces a fixed
5323 * position for the actor. If read, returns the fixed position if
5324 * any, otherwise the allocation if available, otherwise 0.
5326 * The #ClutterActor:y property is animatable.
5329 g_param_spec_float ("y",
5331 P_("Y coordinate of the actor"),
5332 -G_MAXFLOAT, G_MAXFLOAT,
5335 G_PARAM_STATIC_STRINGS |
5336 CLUTTER_PARAM_ANIMATABLE);
5339 * ClutterActor:width:
5341 * Width of the actor (in pixels). If written, forces the minimum and
5342 * natural size request of the actor to the given width. If read, returns
5343 * the allocated width if available, otherwise the width request.
5345 * The #ClutterActor:width property is animatable.
5347 obj_props[PROP_WIDTH] =
5348 g_param_spec_float ("width",
5350 P_("Width of the actor"),
5354 G_PARAM_STATIC_STRINGS |
5355 CLUTTER_PARAM_ANIMATABLE);
5358 * ClutterActor:height:
5360 * Height of the actor (in pixels). If written, forces the minimum and
5361 * natural size request of the actor to the given height. If read, returns
5362 * the allocated height if available, otherwise the height request.
5364 * The #ClutterActor:height property is animatable.
5366 obj_props[PROP_HEIGHT] =
5367 g_param_spec_float ("height",
5369 P_("Height of the actor"),
5373 G_PARAM_STATIC_STRINGS |
5374 CLUTTER_PARAM_ANIMATABLE);
5377 * ClutterActor:fixed-x:
5379 * The fixed X position of the actor in pixels.
5381 * Writing this property sets #ClutterActor:fixed-position-set
5382 * property as well, as a side effect
5386 obj_props[PROP_FIXED_X] =
5387 g_param_spec_float ("fixed-x",
5389 P_("Forced X position of the actor"),
5390 -G_MAXFLOAT, G_MAXFLOAT,
5392 CLUTTER_PARAM_READWRITE);
5395 * ClutterActor:fixed-y:
5397 * The fixed Y position of the actor in pixels.
5399 * Writing this property sets the #ClutterActor:fixed-position-set
5400 * property as well, as a side effect
5404 obj_props[PROP_FIXED_Y] =
5405 g_param_spec_float ("fixed-y",
5407 P_("Forced Y position of the actor"),
5408 -G_MAXFLOAT, G_MAXFLOAT,
5410 CLUTTER_PARAM_READWRITE);
5413 * ClutterActor:fixed-position-set:
5415 * This flag controls whether the #ClutterActor:fixed-x and
5416 * #ClutterActor:fixed-y properties are used
5420 obj_props[PROP_FIXED_POSITION_SET] =
5421 g_param_spec_boolean ("fixed-position-set",
5422 P_("Fixed position set"),
5423 P_("Whether to use fixed positioning for the actor"),
5425 CLUTTER_PARAM_READWRITE);
5428 * ClutterActor:min-width:
5430 * A forced minimum width request for the actor, in pixels
5432 * Writing this property sets the #ClutterActor:min-width-set property
5433 * as well, as a side effect.
5435 *This property overrides the usual width request of the actor.
5439 obj_props[PROP_MIN_WIDTH] =
5440 g_param_spec_float ("min-width",
5442 P_("Forced minimum width request for the actor"),
5445 CLUTTER_PARAM_READWRITE);
5448 * ClutterActor:min-height:
5450 * A forced minimum height request for the actor, in pixels
5452 * Writing this property sets the #ClutterActor:min-height-set property
5453 * as well, as a side effect. This property overrides the usual height
5454 * request of the actor.
5458 obj_props[PROP_MIN_HEIGHT] =
5459 g_param_spec_float ("min-height",
5461 P_("Forced minimum height request for the actor"),
5464 CLUTTER_PARAM_READWRITE);
5467 * ClutterActor:natural-width:
5469 * A forced natural width request for the actor, in pixels
5471 * Writing this property sets the #ClutterActor:natural-width-set
5472 * property as well, as a side effect. This property overrides the
5473 * usual width request of the actor
5477 obj_props[PROP_NATURAL_WIDTH] =
5478 g_param_spec_float ("natural-width",
5479 P_("Natural Width"),
5480 P_("Forced natural width request for the actor"),
5483 CLUTTER_PARAM_READWRITE);
5486 * ClutterActor:natural-height:
5488 * A forced natural height request for the actor, in pixels
5490 * Writing this property sets the #ClutterActor:natural-height-set
5491 * property as well, as a side effect. This property overrides the
5492 * usual height request of the actor
5496 obj_props[PROP_NATURAL_HEIGHT] =
5497 g_param_spec_float ("natural-height",
5498 P_("Natural Height"),
5499 P_("Forced natural height request for the actor"),
5502 CLUTTER_PARAM_READWRITE);
5505 * ClutterActor:min-width-set:
5507 * This flag controls whether the #ClutterActor:min-width property
5512 obj_props[PROP_MIN_WIDTH_SET] =
5513 g_param_spec_boolean ("min-width-set",
5514 P_("Minimum width set"),
5515 P_("Whether to use the min-width property"),
5517 CLUTTER_PARAM_READWRITE);
5520 * ClutterActor:min-height-set:
5522 * This flag controls whether the #ClutterActor:min-height property
5527 obj_props[PROP_MIN_HEIGHT_SET] =
5528 g_param_spec_boolean ("min-height-set",
5529 P_("Minimum height set"),
5530 P_("Whether to use the min-height property"),
5532 CLUTTER_PARAM_READWRITE);
5535 * ClutterActor:natural-width-set:
5537 * This flag controls whether the #ClutterActor:natural-width property
5542 obj_props[PROP_NATURAL_WIDTH_SET] =
5543 g_param_spec_boolean ("natural-width-set",
5544 P_("Natural width set"),
5545 P_("Whether to use the natural-width property"),
5547 CLUTTER_PARAM_READWRITE);
5550 * ClutterActor:natural-height-set:
5552 * This flag controls whether the #ClutterActor:natural-height property
5557 obj_props[PROP_NATURAL_HEIGHT_SET] =
5558 g_param_spec_boolean ("natural-height-set",
5559 P_("Natural height set"),
5560 P_("Whether to use the natural-height property"),
5562 CLUTTER_PARAM_READWRITE);
5565 * ClutterActor:allocation:
5567 * The allocation for the actor, in pixels
5569 * This is property is read-only, but you might monitor it to know when an
5570 * actor moves or resizes
5574 obj_props[PROP_ALLOCATION] =
5575 g_param_spec_boxed ("allocation",
5577 P_("The actor's allocation"),
5578 CLUTTER_TYPE_ACTOR_BOX,
5579 CLUTTER_PARAM_READABLE);
5582 * ClutterActor:request-mode:
5584 * Request mode for the #ClutterActor. The request mode determines the
5585 * type of geometry management used by the actor, either height for width
5586 * (the default) or width for height.
5588 * For actors implementing height for width, the parent container should get
5589 * the preferred width first, and then the preferred height for that width.
5591 * For actors implementing width for height, the parent container should get
5592 * the preferred height first, and then the preferred width for that height.
5597 * ClutterRequestMode mode;
5598 * gfloat natural_width, min_width;
5599 * gfloat natural_height, min_height;
5601 * mode = clutter_actor_get_request_mode (child);
5602 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5604 * clutter_actor_get_preferred_width (child, -1,
5606 * &natural_width);
5607 * clutter_actor_get_preferred_height (child, natural_width,
5609 * &natural_height);
5613 * clutter_actor_get_preferred_height (child, -1,
5615 * &natural_height);
5616 * clutter_actor_get_preferred_width (child, natural_height,
5618 * &natural_width);
5622 * will retrieve the minimum and natural width and height depending on the
5623 * preferred request mode of the #ClutterActor "child".
5625 * The clutter_actor_get_preferred_size() function will implement this
5630 obj_props[PROP_REQUEST_MODE] =
5631 g_param_spec_enum ("request-mode",
5633 P_("The actor's request mode"),
5634 CLUTTER_TYPE_REQUEST_MODE,
5635 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5636 CLUTTER_PARAM_READWRITE);
5639 * ClutterActor:depth:
5641 * The position of the actor on the Z axis.
5643 * The #ClutterActor:depth property is relative to the parent's
5646 * The #ClutterActor:depth property is animatable.
5650 obj_props[PROP_DEPTH] =
5651 g_param_spec_float ("depth",
5653 P_("Position on the Z axis"),
5654 -G_MAXFLOAT, G_MAXFLOAT,
5657 G_PARAM_STATIC_STRINGS |
5658 CLUTTER_PARAM_ANIMATABLE);
5661 * ClutterActor:opacity:
5663 * Opacity of an actor, between 0 (fully transparent) and
5664 * 255 (fully opaque)
5666 * The #ClutterActor:opacity property is animatable.
5668 obj_props[PROP_OPACITY] =
5669 g_param_spec_uint ("opacity",
5671 P_("Opacity of an actor"),
5675 G_PARAM_STATIC_STRINGS |
5676 CLUTTER_PARAM_ANIMATABLE);
5679 * ClutterActor:offscreen-redirect:
5681 * Determines the conditions in which the actor will be redirected
5682 * to an offscreen framebuffer while being painted. For example this
5683 * can be used to cache an actor in a framebuffer or for improved
5684 * handling of transparent actors. See
5685 * clutter_actor_set_offscreen_redirect() for details.
5689 obj_props[PROP_OFFSCREEN_REDIRECT] =
5690 g_param_spec_flags ("offscreen-redirect",
5691 P_("Offscreen redirect"),
5692 P_("Flags controlling when to flatten the actor into a single image"),
5693 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5695 CLUTTER_PARAM_READWRITE);
5698 * ClutterActor:visible:
5700 * Whether the actor is set to be visible or not
5702 * See also #ClutterActor:mapped
5704 obj_props[PROP_VISIBLE] =
5705 g_param_spec_boolean ("visible",
5707 P_("Whether the actor is visible or not"),
5709 CLUTTER_PARAM_READWRITE);
5712 * ClutterActor:mapped:
5714 * Whether the actor is mapped (will be painted when the stage
5715 * to which it belongs is mapped)
5719 obj_props[PROP_MAPPED] =
5720 g_param_spec_boolean ("mapped",
5722 P_("Whether the actor will be painted"),
5724 CLUTTER_PARAM_READABLE);
5727 * ClutterActor:realized:
5729 * Whether the actor has been realized
5733 obj_props[PROP_REALIZED] =
5734 g_param_spec_boolean ("realized",
5736 P_("Whether the actor has been realized"),
5738 CLUTTER_PARAM_READABLE);
5741 * ClutterActor:reactive:
5743 * Whether the actor is reactive to events or not
5745 * Only reactive actors will emit event-related signals
5749 obj_props[PROP_REACTIVE] =
5750 g_param_spec_boolean ("reactive",
5752 P_("Whether the actor is reactive to events"),
5754 CLUTTER_PARAM_READWRITE);
5757 * ClutterActor:has-clip:
5759 * Whether the actor has the #ClutterActor:clip property set or not
5761 obj_props[PROP_HAS_CLIP] =
5762 g_param_spec_boolean ("has-clip",
5764 P_("Whether the actor has a clip set"),
5766 CLUTTER_PARAM_READABLE);
5769 * ClutterActor:clip:
5771 * The clip region for the actor, in actor-relative coordinates
5773 * Every part of the actor outside the clip region will not be
5776 obj_props[PROP_CLIP] =
5777 g_param_spec_boxed ("clip",
5779 P_("The clip region for the actor"),
5780 CLUTTER_TYPE_GEOMETRY,
5781 CLUTTER_PARAM_READWRITE);
5784 * ClutterActor:name:
5786 * The name of the actor
5790 obj_props[PROP_NAME] =
5791 g_param_spec_string ("name",
5793 P_("Name of the actor"),
5795 CLUTTER_PARAM_READWRITE);
5798 * ClutterActor:scale-x:
5800 * The horizontal scale of the actor.
5802 * The #ClutterActor:scale-x property is animatable.
5806 obj_props[PROP_SCALE_X] =
5807 g_param_spec_double ("scale-x",
5809 P_("Scale factor on the X axis"),
5813 G_PARAM_STATIC_STRINGS |
5814 CLUTTER_PARAM_ANIMATABLE);
5817 * ClutterActor:scale-y:
5819 * The vertical scale of the actor.
5821 * The #ClutterActor:scale-y property is animatable.
5825 obj_props[PROP_SCALE_Y] =
5826 g_param_spec_double ("scale-y",
5828 P_("Scale factor on the Y axis"),
5832 G_PARAM_STATIC_STRINGS |
5833 CLUTTER_PARAM_ANIMATABLE);
5836 * ClutterActor:scale-center-x:
5838 * The horizontal center point for scaling
5842 obj_props[PROP_SCALE_CENTER_X] =
5843 g_param_spec_float ("scale-center-x",
5844 P_("Scale Center X"),
5845 P_("Horizontal scale center"),
5846 -G_MAXFLOAT, G_MAXFLOAT,
5848 CLUTTER_PARAM_READWRITE);
5851 * ClutterActor:scale-center-y:
5853 * The vertical center point for scaling
5857 obj_props[PROP_SCALE_CENTER_Y] =
5858 g_param_spec_float ("scale-center-y",
5859 P_("Scale Center Y"),
5860 P_("Vertical scale center"),
5861 -G_MAXFLOAT, G_MAXFLOAT,
5863 CLUTTER_PARAM_READWRITE);
5866 * ClutterActor:scale-gravity:
5868 * The center point for scaling expressed as a #ClutterGravity
5872 obj_props[PROP_SCALE_GRAVITY] =
5873 g_param_spec_enum ("scale-gravity",
5874 P_("Scale Gravity"),
5875 P_("The center of scaling"),
5876 CLUTTER_TYPE_GRAVITY,
5877 CLUTTER_GRAVITY_NONE,
5878 CLUTTER_PARAM_READWRITE);
5881 * ClutterActor:rotation-angle-x:
5883 * The rotation angle on the X axis.
5885 * The #ClutterActor:rotation-angle-x property is animatable.
5889 obj_props[PROP_ROTATION_ANGLE_X] =
5890 g_param_spec_double ("rotation-angle-x",
5891 P_("Rotation Angle X"),
5892 P_("The rotation angle on the X axis"),
5893 -G_MAXDOUBLE, G_MAXDOUBLE,
5896 G_PARAM_STATIC_STRINGS |
5897 CLUTTER_PARAM_ANIMATABLE);
5900 * ClutterActor:rotation-angle-y:
5902 * The rotation angle on the Y axis
5904 * The #ClutterActor:rotation-angle-y property is animatable.
5908 obj_props[PROP_ROTATION_ANGLE_Y] =
5909 g_param_spec_double ("rotation-angle-y",
5910 P_("Rotation Angle Y"),
5911 P_("The rotation angle on the Y axis"),
5912 -G_MAXDOUBLE, G_MAXDOUBLE,
5915 G_PARAM_STATIC_STRINGS |
5916 CLUTTER_PARAM_ANIMATABLE);
5919 * ClutterActor:rotation-angle-z:
5921 * The rotation angle on the Z axis
5923 * The #ClutterActor:rotation-angle-z property is animatable.
5927 obj_props[PROP_ROTATION_ANGLE_Z] =
5928 g_param_spec_double ("rotation-angle-z",
5929 P_("Rotation Angle Z"),
5930 P_("The rotation angle on the Z axis"),
5931 -G_MAXDOUBLE, G_MAXDOUBLE,
5934 G_PARAM_STATIC_STRINGS |
5935 CLUTTER_PARAM_ANIMATABLE);
5938 * ClutterActor:rotation-center-x:
5940 * The rotation center on the X axis.
5944 obj_props[PROP_ROTATION_CENTER_X] =
5945 g_param_spec_boxed ("rotation-center-x",
5946 P_("Rotation Center X"),
5947 P_("The rotation center on the X axis"),
5948 CLUTTER_TYPE_VERTEX,
5949 CLUTTER_PARAM_READWRITE);
5952 * ClutterActor:rotation-center-y:
5954 * The rotation center on the Y axis.
5958 obj_props[PROP_ROTATION_CENTER_Y] =
5959 g_param_spec_boxed ("rotation-center-y",
5960 P_("Rotation Center Y"),
5961 P_("The rotation center on the Y axis"),
5962 CLUTTER_TYPE_VERTEX,
5963 CLUTTER_PARAM_READWRITE);
5966 * ClutterActor:rotation-center-z:
5968 * The rotation center on the Z axis.
5972 obj_props[PROP_ROTATION_CENTER_Z] =
5973 g_param_spec_boxed ("rotation-center-z",
5974 P_("Rotation Center Z"),
5975 P_("The rotation center on the Z axis"),
5976 CLUTTER_TYPE_VERTEX,
5977 CLUTTER_PARAM_READWRITE);
5980 * ClutterActor:rotation-center-z-gravity:
5982 * The rotation center on the Z axis expressed as a #ClutterGravity.
5986 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5987 g_param_spec_enum ("rotation-center-z-gravity",
5988 P_("Rotation Center Z Gravity"),
5989 P_("Center point for rotation around the Z axis"),
5990 CLUTTER_TYPE_GRAVITY,
5991 CLUTTER_GRAVITY_NONE,
5992 CLUTTER_PARAM_READWRITE);
5995 * ClutterActor:anchor-x:
5997 * The X coordinate of an actor's anchor point, relative to
5998 * the actor coordinate space, in pixels
6002 obj_props[PROP_ANCHOR_X] =
6003 g_param_spec_float ("anchor-x",
6005 P_("X coordinate of the anchor point"),
6006 -G_MAXFLOAT, G_MAXFLOAT,
6008 CLUTTER_PARAM_READWRITE);
6011 * ClutterActor:anchor-y:
6013 * The Y coordinate of an actor's anchor point, relative to
6014 * the actor coordinate space, in pixels
6018 obj_props[PROP_ANCHOR_Y] =
6019 g_param_spec_float ("anchor-y",
6021 P_("Y coordinate of the anchor point"),
6022 -G_MAXFLOAT, G_MAXFLOAT,
6024 CLUTTER_PARAM_READWRITE);
6027 * ClutterActor:anchor-gravity:
6029 * The anchor point expressed as a #ClutterGravity
6033 obj_props[PROP_ANCHOR_GRAVITY] =
6034 g_param_spec_enum ("anchor-gravity",
6035 P_("Anchor Gravity"),
6036 P_("The anchor point as a ClutterGravity"),
6037 CLUTTER_TYPE_GRAVITY,
6038 CLUTTER_GRAVITY_NONE,
6039 CLUTTER_PARAM_READWRITE);
6042 * ClutterActor:show-on-set-parent:
6044 * If %TRUE, the actor is automatically shown when parented.
6046 * Calling clutter_actor_hide() on an actor which has not been
6047 * parented will set this property to %FALSE as a side effect.
6051 obj_props[PROP_SHOW_ON_SET_PARENT] =
6052 g_param_spec_boolean ("show-on-set-parent",
6053 P_("Show on set parent"),
6054 P_("Whether the actor is shown when parented"),
6056 CLUTTER_PARAM_READWRITE);
6059 * ClutterActor:clip-to-allocation:
6061 * Whether the clip region should track the allocated area
6064 * This property is ignored if a clip area has been explicitly
6065 * set using clutter_actor_set_clip().
6069 obj_props[PROP_CLIP_TO_ALLOCATION] =
6070 g_param_spec_boolean ("clip-to-allocation",
6071 P_("Clip to Allocation"),
6072 P_("Sets the clip region to track the actor's allocation"),
6074 CLUTTER_PARAM_READWRITE);
6077 * ClutterActor:text-direction:
6079 * The direction of the text inside a #ClutterActor.
6083 obj_props[PROP_TEXT_DIRECTION] =
6084 g_param_spec_enum ("text-direction",
6085 P_("Text Direction"),
6086 P_("Direction of the text"),
6087 CLUTTER_TYPE_TEXT_DIRECTION,
6088 CLUTTER_TEXT_DIRECTION_LTR,
6089 CLUTTER_PARAM_READWRITE);
6092 * ClutterActor:has-pointer:
6094 * Whether the actor contains the pointer of a #ClutterInputDevice
6099 obj_props[PROP_HAS_POINTER] =
6100 g_param_spec_boolean ("has-pointer",
6102 P_("Whether the actor contains the pointer of an input device"),
6104 CLUTTER_PARAM_READABLE);
6107 * ClutterActor:actions:
6109 * Adds a #ClutterAction to the actor
6113 obj_props[PROP_ACTIONS] =
6114 g_param_spec_object ("actions",
6116 P_("Adds an action to the actor"),
6117 CLUTTER_TYPE_ACTION,
6118 CLUTTER_PARAM_WRITABLE);
6121 * ClutterActor:constraints:
6123 * Adds a #ClutterConstraint to the actor
6127 obj_props[PROP_CONSTRAINTS] =
6128 g_param_spec_object ("constraints",
6130 P_("Adds a constraint to the actor"),
6131 CLUTTER_TYPE_CONSTRAINT,
6132 CLUTTER_PARAM_WRITABLE);
6135 * ClutterActor:effect:
6137 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6141 obj_props[PROP_EFFECT] =
6142 g_param_spec_object ("effect",
6144 P_("Add an effect to be applied on the actor"),
6145 CLUTTER_TYPE_EFFECT,
6146 CLUTTER_PARAM_WRITABLE);
6149 * ClutterActor:layout-manager:
6151 * A delegate object for controlling the layout of the children of
6156 obj_props[PROP_LAYOUT_MANAGER] =
6157 g_param_spec_object ("layout-manager",
6158 P_("Layout Manager"),
6159 P_("The object controlling the layout of an actor's children"),
6160 CLUTTER_TYPE_LAYOUT_MANAGER,
6161 CLUTTER_PARAM_READWRITE);
6165 * ClutterActor:x-align:
6167 * The alignment of an actor on the X axis, if the actor has been given
6168 * extra space for its allocation.
6172 obj_props[PROP_X_ALIGN] =
6173 g_param_spec_enum ("x-align",
6175 P_("The alignment of the actor on the X axis within its allocation"),
6176 CLUTTER_TYPE_ACTOR_ALIGN,
6177 CLUTTER_ACTOR_ALIGN_FILL,
6178 CLUTTER_PARAM_READWRITE);
6181 * ClutterActor:y-align:
6183 * The alignment of an actor on the Y axis, if the actor has been given
6184 * extra space for its allocation.
6188 obj_props[PROP_Y_ALIGN] =
6189 g_param_spec_enum ("y-align",
6191 P_("The alignment of the actor on the Y axis within its allocation"),
6192 CLUTTER_TYPE_ACTOR_ALIGN,
6193 CLUTTER_ACTOR_ALIGN_FILL,
6194 CLUTTER_PARAM_READWRITE);
6197 * ClutterActor:margin-top:
6199 * The margin (in pixels) from the top of the actor.
6201 * This property adds a margin to the actor's preferred size; the margin
6202 * will be automatically taken into account when allocating the actor.
6206 obj_props[PROP_MARGIN_TOP] =
6207 g_param_spec_float ("margin-top",
6209 P_("Extra space at the top"),
6212 CLUTTER_PARAM_READWRITE);
6215 * ClutterActor:margin-bottom:
6217 * The margin (in pixels) from the bottom of the actor.
6219 * This property adds a margin to the actor's preferred size; the margin
6220 * will be automatically taken into account when allocating the actor.
6224 obj_props[PROP_MARGIN_BOTTOM] =
6225 g_param_spec_float ("margin-bottom",
6226 P_("Margin Bottom"),
6227 P_("Extra space at the bottom"),
6230 CLUTTER_PARAM_READWRITE);
6233 * ClutterActor:margin-left:
6235 * The margin (in pixels) from the left of the actor.
6237 * This property adds a margin to the actor's preferred size; the margin
6238 * will be automatically taken into account when allocating the actor.
6242 obj_props[PROP_MARGIN_LEFT] =
6243 g_param_spec_float ("margin-left",
6245 P_("Extra space at the left"),
6248 CLUTTER_PARAM_READWRITE);
6251 * ClutterActor:margin-right:
6253 * The margin (in pixels) from the right of the actor.
6255 * This property adds a margin to the actor's preferred size; the margin
6256 * will be automatically taken into account when allocating the actor.
6260 obj_props[PROP_MARGIN_RIGHT] =
6261 g_param_spec_float ("margin-right",
6263 P_("Extra space at the right"),
6266 CLUTTER_PARAM_READWRITE);
6269 * ClutterActor:background-color-set:
6271 * Whether the #ClutterActor:background-color property has been set.
6275 obj_props[PROP_BACKGROUND_COLOR_SET] =
6276 g_param_spec_boolean ("background-color-set",
6277 P_("Background Color Set"),
6278 P_("Whether the background color is set"),
6280 CLUTTER_PARAM_READABLE);
6283 * ClutterActor:background-color:
6285 * Paints a solid fill of the actor's allocation using the specified
6288 * The #ClutterActor:background-color property is animatable.
6292 obj_props[PROP_BACKGROUND_COLOR] =
6293 clutter_param_spec_color ("background-color",
6294 P_("Background color"),
6295 P_("The actor's background color"),
6296 CLUTTER_COLOR_Transparent,
6298 G_PARAM_STATIC_STRINGS |
6299 CLUTTER_PARAM_ANIMATABLE);
6302 * ClutterActor:first-child:
6304 * The actor's first child.
6308 obj_props[PROP_FIRST_CHILD] =
6309 g_param_spec_object ("first-child",
6311 P_("The actor's first child"),
6313 CLUTTER_PARAM_READABLE);
6316 * ClutterActor:last-child:
6318 * The actor's last child.
6322 obj_props[PROP_LAST_CHILD] =
6323 g_param_spec_object ("last-child",
6325 P_("The actor's last child"),
6327 CLUTTER_PARAM_READABLE);
6330 * ClutterActor:content:
6332 * The #ClutterContent implementation that controls the content
6337 obj_props[PROP_CONTENT] =
6338 g_param_spec_object ("content",
6340 P_("Delegate object for painting the actor's content"),
6341 CLUTTER_TYPE_CONTENT,
6342 CLUTTER_PARAM_READWRITE);
6345 * ClutterActor:content-gravity:
6347 * The alignment that should be honoured by the #ClutterContent
6348 * set with the #ClutterActor:content property.
6350 * Changing the value of this property will change the bounding box of
6351 * the content; you can use the #ClutterActor:content-box property to
6352 * get the position and size of the content within the actor's
6355 * This property is meaningful only for #ClutterContent implementations
6356 * that have a preferred size, and if the preferred size is smaller than
6357 * the actor's allocation.
6361 obj_props[PROP_CONTENT_GRAVITY] =
6362 g_param_spec_enum ("content-gravity",
6363 P_("Content Gravity"),
6364 P_("Alignment of the actor's content"),
6365 CLUTTER_TYPE_CONTENT_GRAVITY,
6366 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6367 CLUTTER_PARAM_READWRITE);
6370 * ClutterActor:content-box:
6372 * The bounding box for the #ClutterContent used by the actor.
6374 * The value of this property is controlled by the #ClutterActor:allocation
6375 * and #ClutterActor:content-gravity properties of #ClutterActor.
6377 * The bounding box for the content is guaranteed to never exceed the
6378 * allocation's of the actor.
6382 obj_props[PROP_CONTENT_BOX] =
6383 g_param_spec_boxed ("content-box",
6385 P_("The bounding box of the actor's content"),
6386 CLUTTER_TYPE_ACTOR_BOX,
6387 CLUTTER_PARAM_READABLE);
6389 obj_props[PROP_MINIFICATION_FILTER] =
6390 g_param_spec_enum ("minification-filter",
6391 P_("Minification Filter"),
6392 P_("The filter used when reducing the size of the content"),
6393 CLUTTER_TYPE_SCALING_FILTER,
6394 CLUTTER_SCALING_FILTER_LINEAR,
6395 CLUTTER_PARAM_READWRITE);
6397 obj_props[PROP_MAGNIFICATION_FILTER] =
6398 g_param_spec_enum ("magnification-filter",
6399 P_("Magnification Filter"),
6400 P_("The filter used when increasing the size of the content"),
6401 CLUTTER_TYPE_SCALING_FILTER,
6402 CLUTTER_SCALING_FILTER_LINEAR,
6403 CLUTTER_PARAM_READWRITE);
6405 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6408 * ClutterActor::destroy:
6409 * @actor: the #ClutterActor which emitted the signal
6411 * The ::destroy signal notifies that all references held on the
6412 * actor which emitted it should be released.
6414 * The ::destroy signal should be used by all holders of a reference
6417 * This signal might result in the finalization of the #ClutterActor
6418 * if all references are released.
6420 * Composite actors and actors implementing the #ClutterContainer
6421 * interface should override the default implementation of the
6422 * class handler of this signal and call clutter_actor_destroy() on
6423 * their children. When overriding the default class handler, it is
6424 * required to chain up to the parent's implementation.
6428 actor_signals[DESTROY] =
6429 g_signal_new (I_("destroy"),
6430 G_TYPE_FROM_CLASS (object_class),
6431 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6432 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6434 _clutter_marshal_VOID__VOID,
6437 * ClutterActor::show:
6438 * @actor: the object which received the signal
6440 * The ::show signal is emitted when an actor is visible and
6441 * rendered on the stage.
6445 actor_signals[SHOW] =
6446 g_signal_new (I_("show"),
6447 G_TYPE_FROM_CLASS (object_class),
6449 G_STRUCT_OFFSET (ClutterActorClass, show),
6451 _clutter_marshal_VOID__VOID,
6454 * ClutterActor::hide:
6455 * @actor: the object which received the signal
6457 * The ::hide signal is emitted when an actor is no longer rendered
6462 actor_signals[HIDE] =
6463 g_signal_new (I_("hide"),
6464 G_TYPE_FROM_CLASS (object_class),
6466 G_STRUCT_OFFSET (ClutterActorClass, hide),
6468 _clutter_marshal_VOID__VOID,
6471 * ClutterActor::parent-set:
6472 * @actor: the object which received the signal
6473 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6475 * This signal is emitted when the parent of the actor changes.
6479 actor_signals[PARENT_SET] =
6480 g_signal_new (I_("parent-set"),
6481 G_TYPE_FROM_CLASS (object_class),
6483 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6485 _clutter_marshal_VOID__OBJECT,
6487 CLUTTER_TYPE_ACTOR);
6490 * ClutterActor::queue-redraw:
6491 * @actor: the actor we're bubbling the redraw request through
6492 * @origin: the actor which initiated the redraw request
6494 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6495 * is called on @origin.
6497 * The default implementation for #ClutterActor chains up to the
6498 * parent actor and queues a redraw on the parent, thus "bubbling"
6499 * the redraw queue up through the actor graph. The default
6500 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6501 * in a main loop idle handler.
6503 * Note that the @origin actor may be the stage, or a container; it
6504 * does not have to be a leaf node in the actor graph.
6506 * Toolkits embedding a #ClutterStage which require a redraw and
6507 * relayout cycle can stop the emission of this signal using the
6508 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6513 * on_redraw_complete (gpointer data)
6515 * ClutterStage *stage = data;
6517 * /* execute the Clutter drawing pipeline */
6518 * clutter_stage_ensure_redraw (stage);
6522 * on_stage_queue_redraw (ClutterStage *stage)
6524 * /* this prevents the default handler to run */
6525 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6527 * /* queue a redraw with the host toolkit and call
6528 * * a function when the redraw has been completed
6530 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6534 * <note><para>This signal is emitted before the Clutter paint
6535 * pipeline is executed. If you want to know when the pipeline has
6536 * been completed you should connect to the ::paint signal on the
6537 * Stage with g_signal_connect_after().</para></note>
6541 actor_signals[QUEUE_REDRAW] =
6542 g_signal_new (I_("queue-redraw"),
6543 G_TYPE_FROM_CLASS (object_class),
6546 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6548 _clutter_marshal_VOID__OBJECT,
6550 CLUTTER_TYPE_ACTOR);
6553 * ClutterActor::queue-relayout
6554 * @actor: the actor being queued for relayout
6556 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6557 * is called on an actor.
6559 * The default implementation for #ClutterActor chains up to the
6560 * parent actor and queues a relayout on the parent, thus "bubbling"
6561 * the relayout queue up through the actor graph.
6563 * The main purpose of this signal is to allow relayout to be propagated
6564 * properly in the procense of #ClutterClone actors. Applications will
6565 * not normally need to connect to this signal.
6569 actor_signals[QUEUE_RELAYOUT] =
6570 g_signal_new (I_("queue-relayout"),
6571 G_TYPE_FROM_CLASS (object_class),
6574 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6576 _clutter_marshal_VOID__VOID,
6580 * ClutterActor::event:
6581 * @actor: the actor which received the event
6582 * @event: a #ClutterEvent
6584 * The ::event signal is emitted each time an event is received
6585 * by the @actor. This signal will be emitted on every actor,
6586 * following the hierarchy chain, until it reaches the top-level
6587 * container (the #ClutterStage).
6589 * Return value: %TRUE if the event has been handled by the actor,
6590 * or %FALSE to continue the emission.
6594 actor_signals[EVENT] =
6595 g_signal_new (I_("event"),
6596 G_TYPE_FROM_CLASS (object_class),
6598 G_STRUCT_OFFSET (ClutterActorClass, event),
6599 _clutter_boolean_handled_accumulator, NULL,
6600 _clutter_marshal_BOOLEAN__BOXED,
6602 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6604 * ClutterActor::button-press-event:
6605 * @actor: the actor which received the event
6606 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6608 * The ::button-press-event signal is emitted each time a mouse button
6609 * is pressed on @actor.
6611 * Return value: %TRUE if the event has been handled by the actor,
6612 * or %FALSE to continue the emission.
6616 actor_signals[BUTTON_PRESS_EVENT] =
6617 g_signal_new (I_("button-press-event"),
6618 G_TYPE_FROM_CLASS (object_class),
6620 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6621 _clutter_boolean_handled_accumulator, NULL,
6622 _clutter_marshal_BOOLEAN__BOXED,
6624 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6626 * ClutterActor::button-release-event:
6627 * @actor: the actor which received the event
6628 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6630 * The ::button-release-event signal is emitted each time a mouse button
6631 * is released on @actor.
6633 * Return value: %TRUE if the event has been handled by the actor,
6634 * or %FALSE to continue the emission.
6638 actor_signals[BUTTON_RELEASE_EVENT] =
6639 g_signal_new (I_("button-release-event"),
6640 G_TYPE_FROM_CLASS (object_class),
6642 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6643 _clutter_boolean_handled_accumulator, NULL,
6644 _clutter_marshal_BOOLEAN__BOXED,
6646 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6648 * ClutterActor::scroll-event:
6649 * @actor: the actor which received the event
6650 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6652 * The ::scroll-event signal is emitted each time the mouse is
6653 * scrolled on @actor
6655 * Return value: %TRUE if the event has been handled by the actor,
6656 * or %FALSE to continue the emission.
6660 actor_signals[SCROLL_EVENT] =
6661 g_signal_new (I_("scroll-event"),
6662 G_TYPE_FROM_CLASS (object_class),
6664 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6665 _clutter_boolean_handled_accumulator, NULL,
6666 _clutter_marshal_BOOLEAN__BOXED,
6668 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6670 * ClutterActor::key-press-event:
6671 * @actor: the actor which received the event
6672 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6674 * The ::key-press-event signal is emitted each time a keyboard button
6675 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6677 * Return value: %TRUE if the event has been handled by the actor,
6678 * or %FALSE to continue the emission.
6682 actor_signals[KEY_PRESS_EVENT] =
6683 g_signal_new (I_("key-press-event"),
6684 G_TYPE_FROM_CLASS (object_class),
6686 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6687 _clutter_boolean_handled_accumulator, NULL,
6688 _clutter_marshal_BOOLEAN__BOXED,
6690 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6692 * ClutterActor::key-release-event:
6693 * @actor: the actor which received the event
6694 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6696 * The ::key-release-event signal is emitted each time a keyboard button
6697 * is released while @actor has key focus (see
6698 * clutter_stage_set_key_focus()).
6700 * Return value: %TRUE if the event has been handled by the actor,
6701 * or %FALSE to continue the emission.
6705 actor_signals[KEY_RELEASE_EVENT] =
6706 g_signal_new (I_("key-release-event"),
6707 G_TYPE_FROM_CLASS (object_class),
6709 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6710 _clutter_boolean_handled_accumulator, NULL,
6711 _clutter_marshal_BOOLEAN__BOXED,
6713 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6715 * ClutterActor::motion-event:
6716 * @actor: the actor which received the event
6717 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6719 * The ::motion-event signal is emitted each time the mouse pointer is
6720 * moved over @actor.
6722 * Return value: %TRUE if the event has been handled by the actor,
6723 * or %FALSE to continue the emission.
6727 actor_signals[MOTION_EVENT] =
6728 g_signal_new (I_("motion-event"),
6729 G_TYPE_FROM_CLASS (object_class),
6731 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6732 _clutter_boolean_handled_accumulator, NULL,
6733 _clutter_marshal_BOOLEAN__BOXED,
6735 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6738 * ClutterActor::key-focus-in:
6739 * @actor: the actor which now has key focus
6741 * The ::key-focus-in signal is emitted when @actor receives key focus.
6745 actor_signals[KEY_FOCUS_IN] =
6746 g_signal_new (I_("key-focus-in"),
6747 G_TYPE_FROM_CLASS (object_class),
6749 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6751 _clutter_marshal_VOID__VOID,
6755 * ClutterActor::key-focus-out:
6756 * @actor: the actor which now has key focus
6758 * The ::key-focus-out signal is emitted when @actor loses key focus.
6762 actor_signals[KEY_FOCUS_OUT] =
6763 g_signal_new (I_("key-focus-out"),
6764 G_TYPE_FROM_CLASS (object_class),
6766 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6768 _clutter_marshal_VOID__VOID,
6772 * ClutterActor::enter-event:
6773 * @actor: the actor which the pointer has entered.
6774 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6776 * The ::enter-event signal is emitted when the pointer enters the @actor
6778 * Return value: %TRUE if the event has been handled by the actor,
6779 * or %FALSE to continue the emission.
6783 actor_signals[ENTER_EVENT] =
6784 g_signal_new (I_("enter-event"),
6785 G_TYPE_FROM_CLASS (object_class),
6787 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6788 _clutter_boolean_handled_accumulator, NULL,
6789 _clutter_marshal_BOOLEAN__BOXED,
6791 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6794 * ClutterActor::leave-event:
6795 * @actor: the actor which the pointer has left
6796 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6798 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6800 * Return value: %TRUE if the event has been handled by the actor,
6801 * or %FALSE to continue the emission.
6805 actor_signals[LEAVE_EVENT] =
6806 g_signal_new (I_("leave-event"),
6807 G_TYPE_FROM_CLASS (object_class),
6809 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6810 _clutter_boolean_handled_accumulator, NULL,
6811 _clutter_marshal_BOOLEAN__BOXED,
6813 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6816 * ClutterActor::captured-event:
6817 * @actor: the actor which received the signal
6818 * @event: a #ClutterEvent
6820 * The ::captured-event signal is emitted when an event is captured
6821 * by Clutter. This signal will be emitted starting from the top-level
6822 * container (the #ClutterStage) to the actor which received the event
6823 * going down the hierarchy. This signal can be used to intercept every
6824 * event before the specialized events (like
6825 * ClutterActor::button-press-event or ::key-released-event) are
6828 * Return value: %TRUE if the event has been handled by the actor,
6829 * or %FALSE to continue the emission.
6833 actor_signals[CAPTURED_EVENT] =
6834 g_signal_new (I_("captured-event"),
6835 G_TYPE_FROM_CLASS (object_class),
6837 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6838 _clutter_boolean_handled_accumulator, NULL,
6839 _clutter_marshal_BOOLEAN__BOXED,
6841 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6844 * ClutterActor::paint:
6845 * @actor: the #ClutterActor that received the signal
6847 * The ::paint signal is emitted each time an actor is being painted.
6849 * Subclasses of #ClutterActor should override the class signal handler
6850 * and paint themselves in that function.
6852 * It is possible to connect a handler to the ::paint signal in order
6853 * to set up some custom aspect of a paint.
6857 actor_signals[PAINT] =
6858 g_signal_new (I_("paint"),
6859 G_TYPE_FROM_CLASS (object_class),
6862 G_STRUCT_OFFSET (ClutterActorClass, paint),
6864 _clutter_marshal_VOID__VOID,
6867 * ClutterActor::realize:
6868 * @actor: the #ClutterActor that received the signal
6870 * The ::realize signal is emitted each time an actor is being
6875 actor_signals[REALIZE] =
6876 g_signal_new (I_("realize"),
6877 G_TYPE_FROM_CLASS (object_class),
6879 G_STRUCT_OFFSET (ClutterActorClass, realize),
6881 _clutter_marshal_VOID__VOID,
6884 * ClutterActor::unrealize:
6885 * @actor: the #ClutterActor that received the signal
6887 * The ::unrealize signal is emitted each time an actor is being
6892 actor_signals[UNREALIZE] =
6893 g_signal_new (I_("unrealize"),
6894 G_TYPE_FROM_CLASS (object_class),
6896 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6898 _clutter_marshal_VOID__VOID,
6902 * ClutterActor::pick:
6903 * @actor: the #ClutterActor that received the signal
6904 * @color: the #ClutterColor to be used when picking
6906 * The ::pick signal is emitted each time an actor is being painted
6907 * in "pick mode". The pick mode is used to identify the actor during
6908 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6909 * The actor should paint its shape using the passed @pick_color.
6911 * Subclasses of #ClutterActor should override the class signal handler
6912 * and paint themselves in that function.
6914 * It is possible to connect a handler to the ::pick signal in order
6915 * to set up some custom aspect of a paint in pick mode.
6919 actor_signals[PICK] =
6920 g_signal_new (I_("pick"),
6921 G_TYPE_FROM_CLASS (object_class),
6923 G_STRUCT_OFFSET (ClutterActorClass, pick),
6925 _clutter_marshal_VOID__BOXED,
6927 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6930 * ClutterActor::allocation-changed:
6931 * @actor: the #ClutterActor that emitted the signal
6932 * @box: a #ClutterActorBox with the new allocation
6933 * @flags: #ClutterAllocationFlags for the allocation
6935 * The ::allocation-changed signal is emitted when the
6936 * #ClutterActor:allocation property changes. Usually, application
6937 * code should just use the notifications for the :allocation property
6938 * but if you want to track the allocation flags as well, for instance
6939 * to know whether the absolute origin of @actor changed, then you might
6940 * want use this signal instead.
6944 actor_signals[ALLOCATION_CHANGED] =
6945 g_signal_new (I_("allocation-changed"),
6946 G_TYPE_FROM_CLASS (object_class),
6950 _clutter_marshal_VOID__BOXED_FLAGS,
6952 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6953 CLUTTER_TYPE_ALLOCATION_FLAGS);
6957 clutter_actor_init (ClutterActor *self)
6959 ClutterActorPrivate *priv;
6961 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6963 priv->id = _clutter_context_acquire_id (self);
6966 priv->opacity = 0xff;
6967 priv->show_on_set_parent = TRUE;
6969 priv->needs_width_request = TRUE;
6970 priv->needs_height_request = TRUE;
6971 priv->needs_allocation = TRUE;
6973 priv->cached_width_age = 1;
6974 priv->cached_height_age = 1;
6976 priv->opacity_override = -1;
6977 priv->enable_model_view_transform = TRUE;
6979 /* Initialize an empty paint volume to start with */
6980 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6981 priv->last_paint_volume_valid = TRUE;
6983 priv->transform_valid = FALSE;
6985 /* the default is to stretch the content, to match the
6986 * current behaviour of basically all actors. also, it's
6987 * the easiest thing to compute.
6989 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6990 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
6991 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
6995 * clutter_actor_new:
6997 * Creates a new #ClutterActor.
6999 * A newly created actor has a floating reference, which will be sunk
7000 * when it is added to another actor.
7002 * Return value: (transfer full): the newly created #ClutterActor
7007 clutter_actor_new (void)
7009 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7013 * clutter_actor_destroy:
7014 * @self: a #ClutterActor
7016 * Destroys an actor. When an actor is destroyed, it will break any
7017 * references it holds to other objects. If the actor is inside a
7018 * container, the actor will be removed.
7020 * When you destroy a container, its children will be destroyed as well.
7022 * Note: you cannot destroy the #ClutterStage returned by
7023 * clutter_stage_get_default().
7026 clutter_actor_destroy (ClutterActor *self)
7028 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7030 g_object_ref (self);
7032 /* avoid recursion while destroying */
7033 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7035 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7037 g_object_run_dispose (G_OBJECT (self));
7039 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7042 g_object_unref (self);
7046 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7047 ClutterPaintVolume *clip)
7049 ClutterActorPrivate *priv = self->priv;
7050 ClutterPaintVolume *pv;
7053 /* Remove queue entry early in the process, otherwise a new
7054 queue_redraw() during signal handling could put back this
7055 object in the stage redraw list (but the entry is freed as
7056 soon as we return from this function, causing a segfault
7059 priv->queue_redraw_entry = NULL;
7061 /* If we've been explicitly passed a clip volume then there's
7062 * nothing more to calculate, but otherwise the only thing we know
7063 * is that the change is constrained to the given actor.
7065 * The idea is that if we know the paint volume for where the actor
7066 * was last drawn (in eye coordinates) and we also have the paint
7067 * volume for where it will be drawn next (in actor coordinates)
7068 * then if we queue a redraw for both these volumes that will cover
7069 * everything that needs to be redrawn to clear the old view and
7070 * show the latest view of the actor.
7072 * Don't clip this redraw if we don't know what position we had for
7073 * the previous redraw since we don't know where to set the clip so
7074 * it will clear the actor as it is currently.
7078 _clutter_actor_set_queue_redraw_clip (self, clip);
7081 else if (G_LIKELY (priv->last_paint_volume_valid))
7083 pv = _clutter_actor_get_paint_volume_mutable (self);
7086 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7088 /* make sure we redraw the actors old position... */
7089 _clutter_actor_set_queue_redraw_clip (stage,
7090 &priv->last_paint_volume);
7091 _clutter_actor_signal_queue_redraw (stage, stage);
7092 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7094 /* XXX: Ideally the redraw signal would take a clip volume
7095 * argument, but that would be an ABI break. Until we can
7096 * break the ABI we pass the argument out-of-band
7099 /* setup the clip for the actors new position... */
7100 _clutter_actor_set_queue_redraw_clip (self, pv);
7109 _clutter_actor_signal_queue_redraw (self, self);
7111 /* Just in case anyone is manually firing redraw signals without
7112 * using the public queue_redraw() API we are careful to ensure that
7113 * our out-of-band clip member is cleared before returning...
7115 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7117 if (G_LIKELY (clipped))
7118 _clutter_actor_set_queue_redraw_clip (self, NULL);
7122 _clutter_actor_get_allocation_clip (ClutterActor *self,
7123 ClutterActorBox *clip)
7125 ClutterActorBox allocation;
7127 /* XXX: we don't care if we get an out of date allocation here
7128 * because clutter_actor_queue_redraw_with_clip knows to ignore
7129 * the clip if the actor's allocation is invalid.
7131 * This is noted because clutter_actor_get_allocation_box does some
7132 * unnecessary work to support buggy code with a comment suggesting
7133 * that it could be changed later which would be good for this use
7136 clutter_actor_get_allocation_box (self, &allocation);
7138 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7139 * actor's own coordinate space but the allocation is in parent
7143 clip->x2 = allocation.x2 - allocation.x1;
7144 clip->y2 = allocation.y2 - allocation.y1;
7148 _clutter_actor_queue_redraw_full (ClutterActor *self,
7149 ClutterRedrawFlags flags,
7150 ClutterPaintVolume *volume,
7151 ClutterEffect *effect)
7153 ClutterActorPrivate *priv = self->priv;
7154 ClutterPaintVolume allocation_pv;
7155 ClutterPaintVolume *pv;
7156 gboolean should_free_pv;
7157 ClutterActor *stage;
7159 /* Here's an outline of the actor queue redraw mechanism:
7161 * The process starts in one of the following two functions which
7162 * are wrappers for this function:
7163 * clutter_actor_queue_redraw
7164 * _clutter_actor_queue_redraw_with_clip
7166 * additionally, an effect can queue a redraw by wrapping this
7167 * function in clutter_effect_queue_rerun
7169 * This functions queues an entry in a list associated with the
7170 * stage which is a list of actors that queued a redraw while
7171 * updating the timelines, performing layouting and processing other
7172 * mainloop sources before the next paint starts.
7174 * We aim to minimize the processing done at this point because
7175 * there is a good chance other events will happen while updating
7176 * the scenegraph that would invalidate any expensive work we might
7177 * otherwise try to do here. For example we don't try and resolve
7178 * the screen space bounding box of an actor at this stage so as to
7179 * minimize how much of the screen redraw because it's possible
7180 * something else will happen which will force a full redraw anyway.
7182 * When all updates are complete and we come to paint the stage then
7183 * we iterate this list and actually emit the "queue-redraw" signals
7184 * for each of the listed actors which will bubble up to the stage
7185 * for each actor and at that point we will transform the actors
7186 * paint volume into screen coordinates to determine the clip region
7187 * for what needs to be redrawn in the next paint.
7189 * Besides minimizing redundant work another reason for this
7190 * deferred design is that it's more likely we will be able to
7191 * determine the paint volume of an actor once we've finished
7192 * updating the scenegraph because its allocation should be up to
7193 * date. NB: If we can't determine an actors paint volume then we
7194 * can't automatically queue a clipped redraw which can make a big
7195 * difference to performance.
7197 * So the control flow goes like this:
7198 * One of clutter_actor_queue_redraw,
7199 * _clutter_actor_queue_redraw_with_clip
7200 * or clutter_effect_queue_rerun
7202 * then control moves to:
7203 * _clutter_stage_queue_actor_redraw
7205 * later during _clutter_stage_do_update, once relayouting is done
7206 * and the scenegraph has been updated we will call:
7207 * _clutter_stage_finish_queue_redraws
7209 * _clutter_stage_finish_queue_redraws will call
7210 * _clutter_actor_finish_queue_redraw for each listed actor.
7211 * Note: actors *are* allowed to queue further redraws during this
7212 * process (considering clone actors or texture_new_from_actor which
7213 * respond to their source queueing a redraw by queuing a redraw
7214 * themselves). We repeat the process until the list is empty.
7216 * This will result in the "queue-redraw" signal being fired for
7217 * each actor which will pass control to the default signal handler:
7218 * clutter_actor_real_queue_redraw
7220 * This will bubble up to the stages handler:
7221 * clutter_stage_real_queue_redraw
7223 * clutter_stage_real_queue_redraw will transform the actors paint
7224 * volume into screen space and add it as a clip region for the next
7228 /* ignore queueing a redraw for actors being destroyed */
7229 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7232 stage = _clutter_actor_get_stage_internal (self);
7234 /* Ignore queueing a redraw for actors not descended from a stage */
7238 /* ignore queueing a redraw on stages that are being destroyed */
7239 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7242 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7244 ClutterActorBox allocation_clip;
7245 ClutterVertex origin;
7247 /* If the actor doesn't have a valid allocation then we will
7248 * queue a full stage redraw. */
7249 if (priv->needs_allocation)
7251 /* NB: NULL denotes an undefined clip which will result in a
7253 _clutter_actor_set_queue_redraw_clip (self, NULL);
7254 _clutter_actor_signal_queue_redraw (self, self);
7258 _clutter_paint_volume_init_static (&allocation_pv, self);
7259 pv = &allocation_pv;
7261 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7263 origin.x = allocation_clip.x1;
7264 origin.y = allocation_clip.y1;
7266 clutter_paint_volume_set_origin (pv, &origin);
7267 clutter_paint_volume_set_width (pv,
7268 allocation_clip.x2 - allocation_clip.x1);
7269 clutter_paint_volume_set_height (pv,
7270 allocation_clip.y2 -
7271 allocation_clip.y1);
7272 should_free_pv = TRUE;
7277 should_free_pv = FALSE;
7280 self->priv->queue_redraw_entry =
7281 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7282 priv->queue_redraw_entry,
7287 clutter_paint_volume_free (pv);
7289 /* If this is the first redraw queued then we can directly use the
7291 if (!priv->is_dirty)
7292 priv->effect_to_redraw = effect;
7293 /* Otherwise we need to merge it with the existing effect parameter */
7294 else if (effect != NULL)
7296 /* If there's already an effect then we need to use whichever is
7297 later in the chain of actors. Otherwise a full redraw has
7298 already been queued on the actor so we need to ignore the
7300 if (priv->effect_to_redraw != NULL)
7302 if (priv->effects == NULL)
7303 g_warning ("Redraw queued with an effect that is "
7304 "not applied to the actor");
7309 for (l = _clutter_meta_group_peek_metas (priv->effects);
7313 if (l->data == priv->effect_to_redraw ||
7315 priv->effect_to_redraw = l->data;
7322 /* If no effect is specified then we need to redraw the whole
7324 priv->effect_to_redraw = NULL;
7327 priv->is_dirty = TRUE;
7331 * clutter_actor_queue_redraw:
7332 * @self: A #ClutterActor
7334 * Queues up a redraw of an actor and any children. The redraw occurs
7335 * once the main loop becomes idle (after the current batch of events
7336 * has been processed, roughly).
7338 * Applications rarely need to call this, as redraws are handled
7339 * automatically by modification functions.
7341 * This function will not do anything if @self is not visible, or
7342 * if the actor is inside an invisible part of the scenegraph.
7344 * Also be aware that painting is a NOP for actors with an opacity of
7347 * When you are implementing a custom actor you must queue a redraw
7348 * whenever some private state changes that will affect painting or
7349 * picking of your actor.
7352 clutter_actor_queue_redraw (ClutterActor *self)
7354 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7356 _clutter_actor_queue_redraw_full (self,
7358 NULL, /* clip volume */
7363 * _clutter_actor_queue_redraw_with_clip:
7364 * @self: A #ClutterActor
7365 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7366 * this queue redraw.
7367 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7368 * redrawn or %NULL if you are just using a @flag to state your
7371 * Queues up a clipped redraw of an actor and any children. The redraw
7372 * occurs once the main loop becomes idle (after the current batch of
7373 * events has been processed, roughly).
7375 * If no flags are given the clip volume is defined by @volume
7376 * specified in actor coordinates and tells Clutter that only content
7377 * within this volume has been changed so Clutter can optionally
7378 * optimize the redraw.
7380 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7381 * should be %NULL and this tells Clutter to use the actor's current
7382 * allocation as a clip box. This flag can only be used for 2D actors,
7383 * because any actor with depth may be projected outside its
7386 * Applications rarely need to call this, as redraws are handled
7387 * automatically by modification functions.
7389 * This function will not do anything if @self is not visible, or if
7390 * the actor is inside an invisible part of the scenegraph.
7392 * Also be aware that painting is a NOP for actors with an opacity of
7395 * When you are implementing a custom actor you must queue a redraw
7396 * whenever some private state changes that will affect painting or
7397 * picking of your actor.
7400 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7401 ClutterRedrawFlags flags,
7402 ClutterPaintVolume *volume)
7404 _clutter_actor_queue_redraw_full (self,
7406 volume, /* clip volume */
7411 _clutter_actor_queue_only_relayout (ClutterActor *self)
7413 ClutterActorPrivate *priv = self->priv;
7415 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7418 if (priv->needs_width_request &&
7419 priv->needs_height_request &&
7420 priv->needs_allocation)
7421 return; /* save some cpu cycles */
7423 #if CLUTTER_ENABLE_DEBUG
7424 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7426 g_warning ("The actor '%s' is currently inside an allocation "
7427 "cycle; calling clutter_actor_queue_relayout() is "
7429 _clutter_actor_get_debug_name (self));
7431 #endif /* CLUTTER_ENABLE_DEBUG */
7433 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7437 * clutter_actor_queue_redraw_with_clip:
7438 * @self: a #ClutterActor
7439 * @clip: (allow-none): a rectangular clip region, or %NULL
7441 * Queues a redraw on @self limited to a specific, actor-relative
7444 * If @clip is %NULL this function is equivalent to
7445 * clutter_actor_queue_redraw().
7450 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7451 const cairo_rectangle_int_t *clip)
7453 ClutterPaintVolume volume;
7454 ClutterVertex origin;
7456 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7460 clutter_actor_queue_redraw (self);
7464 _clutter_paint_volume_init_static (&volume, self);
7470 clutter_paint_volume_set_origin (&volume, &origin);
7471 clutter_paint_volume_set_width (&volume, clip->width);
7472 clutter_paint_volume_set_height (&volume, clip->height);
7474 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7476 clutter_paint_volume_free (&volume);
7480 * clutter_actor_queue_relayout:
7481 * @self: A #ClutterActor
7483 * Indicates that the actor's size request or other layout-affecting
7484 * properties may have changed. This function is used inside #ClutterActor
7485 * subclass implementations, not by applications directly.
7487 * Queueing a new layout automatically queues a redraw as well.
7492 clutter_actor_queue_relayout (ClutterActor *self)
7494 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7496 _clutter_actor_queue_only_relayout (self);
7497 clutter_actor_queue_redraw (self);
7501 * clutter_actor_get_preferred_size:
7502 * @self: a #ClutterActor
7503 * @min_width_p: (out) (allow-none): return location for the minimum
7505 * @min_height_p: (out) (allow-none): return location for the minimum
7507 * @natural_width_p: (out) (allow-none): return location for the natural
7509 * @natural_height_p: (out) (allow-none): return location for the natural
7512 * Computes the preferred minimum and natural size of an actor, taking into
7513 * account the actor's geometry management (either height-for-width
7514 * or width-for-height).
7516 * The width and height used to compute the preferred height and preferred
7517 * width are the actor's natural ones.
7519 * If you need to control the height for the preferred width, or the width for
7520 * the preferred height, you should use clutter_actor_get_preferred_width()
7521 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7522 * geometry management using the #ClutterActor:request-mode property.
7527 clutter_actor_get_preferred_size (ClutterActor *self,
7528 gfloat *min_width_p,
7529 gfloat *min_height_p,
7530 gfloat *natural_width_p,
7531 gfloat *natural_height_p)
7533 ClutterActorPrivate *priv;
7534 gfloat min_width, min_height;
7535 gfloat natural_width, natural_height;
7537 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7541 min_width = min_height = 0;
7542 natural_width = natural_height = 0;
7544 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7546 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7547 clutter_actor_get_preferred_width (self, -1,
7550 clutter_actor_get_preferred_height (self, natural_width,
7556 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7557 clutter_actor_get_preferred_height (self, -1,
7560 clutter_actor_get_preferred_width (self, natural_height,
7566 *min_width_p = min_width;
7569 *min_height_p = min_height;
7571 if (natural_width_p)
7572 *natural_width_p = natural_width;
7574 if (natural_height_p)
7575 *natural_height_p = natural_height;
7580 * @align: a #ClutterActorAlign
7581 * @direction: a #ClutterTextDirection
7583 * Retrieves the correct alignment depending on the text direction
7585 * Return value: the effective alignment
7587 static ClutterActorAlign
7588 effective_align (ClutterActorAlign align,
7589 ClutterTextDirection direction)
7591 ClutterActorAlign res;
7595 case CLUTTER_ACTOR_ALIGN_START:
7596 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7597 ? CLUTTER_ACTOR_ALIGN_END
7598 : CLUTTER_ACTOR_ALIGN_START;
7601 case CLUTTER_ACTOR_ALIGN_END:
7602 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7603 ? CLUTTER_ACTOR_ALIGN_START
7604 : CLUTTER_ACTOR_ALIGN_END;
7616 adjust_for_margin (float margin_start,
7618 float *minimum_size,
7619 float *natural_size,
7620 float *allocated_start,
7621 float *allocated_end)
7623 *minimum_size -= (margin_start + margin_end);
7624 *natural_size -= (margin_start + margin_end);
7625 *allocated_start += margin_start;
7626 *allocated_end -= margin_end;
7630 adjust_for_alignment (ClutterActorAlign alignment,
7632 float *allocated_start,
7633 float *allocated_end)
7635 float allocated_size = *allocated_end - *allocated_start;
7639 case CLUTTER_ACTOR_ALIGN_FILL:
7643 case CLUTTER_ACTOR_ALIGN_START:
7645 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7648 case CLUTTER_ACTOR_ALIGN_END:
7649 if (allocated_size > natural_size)
7651 *allocated_start += (allocated_size - natural_size);
7652 *allocated_end = *allocated_start + natural_size;
7656 case CLUTTER_ACTOR_ALIGN_CENTER:
7657 if (allocated_size > natural_size)
7659 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7660 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7667 * clutter_actor_adjust_width:
7668 * @self: a #ClutterActor
7669 * @minimum_width: (inout): the actor's preferred minimum width, which
7670 * will be adjusted depending on the margin
7671 * @natural_width: (inout): the actor's preferred natural width, which
7672 * will be adjusted depending on the margin
7673 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7674 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7676 * Adjusts the preferred and allocated position and size of an actor,
7677 * depending on the margin and alignment properties.
7680 clutter_actor_adjust_width (ClutterActor *self,
7681 gfloat *minimum_width,
7682 gfloat *natural_width,
7683 gfloat *adjusted_x1,
7684 gfloat *adjusted_x2)
7686 ClutterTextDirection text_dir;
7687 const ClutterLayoutInfo *info;
7689 info = _clutter_actor_get_layout_info_or_defaults (self);
7690 text_dir = clutter_actor_get_text_direction (self);
7692 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7694 /* this will tweak natural_width to remove the margin, so that
7695 * adjust_for_alignment() will use the correct size
7697 adjust_for_margin (info->margin.left, info->margin.right,
7698 minimum_width, natural_width,
7699 adjusted_x1, adjusted_x2);
7701 adjust_for_alignment (effective_align (info->x_align, text_dir),
7703 adjusted_x1, adjusted_x2);
7707 * clutter_actor_adjust_height:
7708 * @self: a #ClutterActor
7709 * @minimum_height: (inout): the actor's preferred minimum height, which
7710 * will be adjusted depending on the margin
7711 * @natural_height: (inout): the actor's preferred natural height, which
7712 * will be adjusted depending on the margin
7713 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7714 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7716 * Adjusts the preferred and allocated position and size of an actor,
7717 * depending on the margin and alignment properties.
7720 clutter_actor_adjust_height (ClutterActor *self,
7721 gfloat *minimum_height,
7722 gfloat *natural_height,
7723 gfloat *adjusted_y1,
7724 gfloat *adjusted_y2)
7726 const ClutterLayoutInfo *info;
7728 info = _clutter_actor_get_layout_info_or_defaults (self);
7730 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7732 /* this will tweak natural_height to remove the margin, so that
7733 * adjust_for_alignment() will use the correct size
7735 adjust_for_margin (info->margin.top, info->margin.bottom,
7736 minimum_height, natural_height,
7740 /* we don't use effective_align() here, because text direction
7741 * only affects the horizontal axis
7743 adjust_for_alignment (info->y_align,
7750 /* looks for a cached size request for this for_size. If not
7751 * found, returns the oldest entry so it can be overwritten */
7753 _clutter_actor_get_cached_size_request (gfloat for_size,
7754 SizeRequest *cached_size_requests,
7755 SizeRequest **result)
7759 *result = &cached_size_requests[0];
7761 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7765 sr = &cached_size_requests[i];
7768 sr->for_size == for_size)
7770 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7774 else if (sr->age < (*result)->age)
7780 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7786 * clutter_actor_get_preferred_width:
7787 * @self: A #ClutterActor
7788 * @for_height: available height when computing the preferred width,
7789 * or a negative value to indicate that no height is defined
7790 * @min_width_p: (out) (allow-none): return location for minimum width,
7792 * @natural_width_p: (out) (allow-none): return location for the natural
7795 * Computes the requested minimum and natural widths for an actor,
7796 * optionally depending on the specified height, or if they are
7797 * already computed, returns the cached values.
7799 * An actor may not get its request - depending on the layout
7800 * manager that's in effect.
7802 * A request should not incorporate the actor's scale or anchor point;
7803 * those transformations do not affect layout, only rendering.
7808 clutter_actor_get_preferred_width (ClutterActor *self,
7810 gfloat *min_width_p,
7811 gfloat *natural_width_p)
7813 float request_min_width, request_natural_width;
7814 SizeRequest *cached_size_request;
7815 const ClutterLayoutInfo *info;
7816 ClutterActorPrivate *priv;
7817 gboolean found_in_cache;
7819 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7823 info = _clutter_actor_get_layout_info_or_defaults (self);
7825 /* we shortcircuit the case of a fixed size set using set_width() */
7826 if (priv->min_width_set && priv->natural_width_set)
7828 if (min_width_p != NULL)
7829 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7831 if (natural_width_p != NULL)
7832 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7837 /* the remaining cases are:
7839 * - either min_width or natural_width have been set
7840 * - neither min_width or natural_width have been set
7842 * in both cases, we go through the cache (and through the actor in case
7843 * of cache misses) and determine the authoritative value depending on
7847 if (!priv->needs_width_request)
7850 _clutter_actor_get_cached_size_request (for_height,
7851 priv->width_requests,
7852 &cached_size_request);
7856 /* if the actor needs a width request we use the first slot */
7857 found_in_cache = FALSE;
7858 cached_size_request = &priv->width_requests[0];
7861 if (!found_in_cache)
7863 gfloat minimum_width, natural_width;
7864 ClutterActorClass *klass;
7866 minimum_width = natural_width = 0;
7868 /* adjust for the margin */
7869 if (for_height >= 0)
7871 for_height -= (info->margin.top + info->margin.bottom);
7876 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7878 klass = CLUTTER_ACTOR_GET_CLASS (self);
7879 klass->get_preferred_width (self, for_height,
7883 /* adjust for the margin */
7884 minimum_width += (info->margin.left + info->margin.right);
7885 natural_width += (info->margin.left + info->margin.right);
7887 /* Due to accumulated float errors, it's better not to warn
7888 * on this, but just fix it.
7890 if (natural_width < minimum_width)
7891 natural_width = minimum_width;
7893 cached_size_request->min_size = minimum_width;
7894 cached_size_request->natural_size = natural_width;
7895 cached_size_request->for_size = for_height;
7896 cached_size_request->age = priv->cached_width_age;
7898 priv->cached_width_age += 1;
7899 priv->needs_width_request = FALSE;
7902 if (!priv->min_width_set)
7903 request_min_width = cached_size_request->min_size;
7905 request_min_width = info->min_width;
7907 if (!priv->natural_width_set)
7908 request_natural_width = cached_size_request->natural_size;
7910 request_natural_width = info->natural_width;
7913 *min_width_p = request_min_width;
7915 if (natural_width_p)
7916 *natural_width_p = request_natural_width;
7920 * clutter_actor_get_preferred_height:
7921 * @self: A #ClutterActor
7922 * @for_width: available width to assume in computing desired height,
7923 * or a negative value to indicate that no width is defined
7924 * @min_height_p: (out) (allow-none): return location for minimum height,
7926 * @natural_height_p: (out) (allow-none): return location for natural
7929 * Computes the requested minimum and natural heights for an actor,
7930 * or if they are already computed, returns the cached values.
7932 * An actor may not get its request - depending on the layout
7933 * manager that's in effect.
7935 * A request should not incorporate the actor's scale or anchor point;
7936 * those transformations do not affect layout, only rendering.
7941 clutter_actor_get_preferred_height (ClutterActor *self,
7943 gfloat *min_height_p,
7944 gfloat *natural_height_p)
7946 float request_min_height, request_natural_height;
7947 SizeRequest *cached_size_request;
7948 const ClutterLayoutInfo *info;
7949 ClutterActorPrivate *priv;
7950 gboolean found_in_cache;
7952 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7956 info = _clutter_actor_get_layout_info_or_defaults (self);
7958 /* we shortcircuit the case of a fixed size set using set_height() */
7959 if (priv->min_height_set && priv->natural_height_set)
7961 if (min_height_p != NULL)
7962 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7964 if (natural_height_p != NULL)
7965 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7970 /* the remaining cases are:
7972 * - either min_height or natural_height have been set
7973 * - neither min_height or natural_height have been set
7975 * in both cases, we go through the cache (and through the actor in case
7976 * of cache misses) and determine the authoritative value depending on
7980 if (!priv->needs_height_request)
7983 _clutter_actor_get_cached_size_request (for_width,
7984 priv->height_requests,
7985 &cached_size_request);
7989 found_in_cache = FALSE;
7990 cached_size_request = &priv->height_requests[0];
7993 if (!found_in_cache)
7995 gfloat minimum_height, natural_height;
7996 ClutterActorClass *klass;
7998 minimum_height = natural_height = 0;
8000 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8002 /* adjust for margin */
8005 for_width -= (info->margin.left + info->margin.right);
8010 klass = CLUTTER_ACTOR_GET_CLASS (self);
8011 klass->get_preferred_height (self, for_width,
8015 /* adjust for margin */
8016 minimum_height += (info->margin.top + info->margin.bottom);
8017 natural_height += (info->margin.top + info->margin.bottom);
8019 /* Due to accumulated float errors, it's better not to warn
8020 * on this, but just fix it.
8022 if (natural_height < minimum_height)
8023 natural_height = minimum_height;
8025 cached_size_request->min_size = minimum_height;
8026 cached_size_request->natural_size = natural_height;
8027 cached_size_request->for_size = for_width;
8028 cached_size_request->age = priv->cached_height_age;
8030 priv->cached_height_age += 1;
8031 priv->needs_height_request = FALSE;
8034 if (!priv->min_height_set)
8035 request_min_height = cached_size_request->min_size;
8037 request_min_height = info->min_height;
8039 if (!priv->natural_height_set)
8040 request_natural_height = cached_size_request->natural_size;
8042 request_natural_height = info->natural_height;
8045 *min_height_p = request_min_height;
8047 if (natural_height_p)
8048 *natural_height_p = request_natural_height;
8052 * clutter_actor_get_allocation_box:
8053 * @self: A #ClutterActor
8054 * @box: (out): the function fills this in with the actor's allocation
8056 * Gets the layout box an actor has been assigned. The allocation can
8057 * only be assumed valid inside a paint() method; anywhere else, it
8058 * may be out-of-date.
8060 * An allocation does not incorporate the actor's scale or anchor point;
8061 * those transformations do not affect layout, only rendering.
8063 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8064 * of functions inside the implementation of the get_preferred_width()
8065 * or get_preferred_height() virtual functions.</note>
8070 clutter_actor_get_allocation_box (ClutterActor *self,
8071 ClutterActorBox *box)
8073 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8075 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8076 * which limits calling get_allocation to inside paint() basically; or
8077 * we can 2) force a layout, which could be expensive if someone calls
8078 * get_allocation somewhere silly; or we can 3) just return the latest
8079 * value, allowing it to be out-of-date, and assume people know what
8082 * The least-surprises approach that keeps existing code working is
8083 * likely to be 2). People can end up doing some inefficient things,
8084 * though, and in general code that requires 2) is probably broken.
8087 /* this implements 2) */
8088 if (G_UNLIKELY (self->priv->needs_allocation))
8090 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8092 /* do not queue a relayout on an unparented actor */
8094 _clutter_stage_maybe_relayout (stage);
8097 /* commenting out the code above and just keeping this assigment
8100 *box = self->priv->allocation;
8104 * clutter_actor_get_allocation_geometry:
8105 * @self: A #ClutterActor
8106 * @geom: (out): allocation geometry in pixels
8108 * Gets the layout box an actor has been assigned. The allocation can
8109 * only be assumed valid inside a paint() method; anywhere else, it
8110 * may be out-of-date.
8112 * An allocation does not incorporate the actor's scale or anchor point;
8113 * those transformations do not affect layout, only rendering.
8115 * The returned rectangle is in pixels.
8120 clutter_actor_get_allocation_geometry (ClutterActor *self,
8121 ClutterGeometry *geom)
8123 ClutterActorBox box;
8125 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8126 g_return_if_fail (geom != NULL);
8128 clutter_actor_get_allocation_box (self, &box);
8130 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8131 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8132 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8133 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8137 clutter_actor_update_constraints (ClutterActor *self,
8138 ClutterActorBox *allocation)
8140 ClutterActorPrivate *priv = self->priv;
8141 const GList *constraints, *l;
8143 if (priv->constraints == NULL)
8146 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8147 for (l = constraints; l != NULL; l = l->next)
8149 ClutterConstraint *constraint = l->data;
8150 ClutterActorMeta *meta = l->data;
8152 if (clutter_actor_meta_get_enabled (meta))
8154 _clutter_constraint_update_allocation (constraint,
8162 * clutter_actor_adjust_allocation:
8163 * @self: a #ClutterActor
8164 * @allocation: (inout): the allocation to adjust
8166 * Adjusts the passed allocation box taking into account the actor's
8167 * layout information, like alignment, expansion, and margin.
8170 clutter_actor_adjust_allocation (ClutterActor *self,
8171 ClutterActorBox *allocation)
8173 ClutterActorBox adj_allocation;
8174 float alloc_width, alloc_height;
8175 float min_width, min_height;
8176 float nat_width, nat_height;
8177 ClutterRequestMode req_mode;
8179 adj_allocation = *allocation;
8181 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8183 /* we want to hit the cache, so we use the public API */
8184 req_mode = clutter_actor_get_request_mode (self);
8186 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8188 clutter_actor_get_preferred_width (self, -1,
8191 clutter_actor_get_preferred_height (self, alloc_width,
8195 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8197 clutter_actor_get_preferred_height (self, -1,
8200 clutter_actor_get_preferred_height (self, alloc_height,
8205 #ifdef CLUTTER_ENABLE_DEBUG
8206 /* warn about underallocations */
8207 if (_clutter_diagnostic_enabled () &&
8208 (floorf (min_width - alloc_width) > 0 ||
8209 floorf (min_height - alloc_height) > 0))
8211 ClutterActor *parent = clutter_actor_get_parent (self);
8213 /* the only actors that are allowed to be underallocated are the Stage,
8214 * as it doesn't have an implicit size, and Actors that specifically
8215 * told us that they want to opt-out from layout control mechanisms
8216 * through the NO_LAYOUT escape hatch.
8218 if (parent != NULL &&
8219 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8221 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8222 "of %.2f x %.2f from its parent actor '%s', but its "
8223 "requested minimum size is of %.2f x %.2f",
8224 _clutter_actor_get_debug_name (self),
8225 alloc_width, alloc_height,
8226 _clutter_actor_get_debug_name (parent),
8227 min_width, min_height);
8232 clutter_actor_adjust_width (self,
8236 &adj_allocation.x2);
8238 clutter_actor_adjust_height (self,
8242 &adj_allocation.y2);
8244 /* we maintain the invariant that an allocation cannot be adjusted
8245 * to be outside the parent-given box
8247 if (adj_allocation.x1 < allocation->x1 ||
8248 adj_allocation.y1 < allocation->y1 ||
8249 adj_allocation.x2 > allocation->x2 ||
8250 adj_allocation.y2 > allocation->y2)
8252 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8253 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8254 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8255 _clutter_actor_get_debug_name (self),
8256 adj_allocation.x1, adj_allocation.y1,
8257 adj_allocation.x2 - adj_allocation.x1,
8258 adj_allocation.y2 - adj_allocation.y1,
8259 allocation->x1, allocation->y1,
8260 allocation->x2 - allocation->x1,
8261 allocation->y2 - allocation->y1);
8265 *allocation = adj_allocation;
8269 * clutter_actor_allocate:
8270 * @self: A #ClutterActor
8271 * @box: new allocation of the actor, in parent-relative coordinates
8272 * @flags: flags that control the allocation
8274 * Called by the parent of an actor to assign the actor its size.
8275 * Should never be called by applications (except when implementing
8276 * a container or layout manager).
8278 * Actors can know from their allocation box whether they have moved
8279 * with respect to their parent actor. The @flags parameter describes
8280 * additional information about the allocation, for instance whether
8281 * the parent has moved with respect to the stage, for example because
8282 * a grandparent's origin has moved.
8287 clutter_actor_allocate (ClutterActor *self,
8288 const ClutterActorBox *box,
8289 ClutterAllocationFlags flags)
8291 ClutterActorPrivate *priv;
8292 ClutterActorClass *klass;
8293 ClutterActorBox old_allocation, real_allocation;
8294 gboolean origin_changed, child_moved, size_changed;
8295 gboolean stage_allocation_changed;
8297 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8298 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8300 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8301 "which isn't a descendent of the stage!\n",
8302 self, _clutter_actor_get_debug_name (self));
8308 old_allocation = priv->allocation;
8309 real_allocation = *box;
8311 /* constraints are allowed to modify the allocation only here; we do
8312 * this prior to all the other checks so that we can bail out if the
8313 * allocation did not change
8315 clutter_actor_update_constraints (self, &real_allocation);
8317 /* adjust the allocation depending on the align/margin properties */
8318 clutter_actor_adjust_allocation (self, &real_allocation);
8320 if (real_allocation.x2 < real_allocation.x1 ||
8321 real_allocation.y2 < real_allocation.y1)
8323 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8324 _clutter_actor_get_debug_name (self),
8325 real_allocation.x2 - real_allocation.x1,
8326 real_allocation.y2 - real_allocation.y1);
8329 /* we allow 0-sized actors, but not negative-sized ones */
8330 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8331 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8333 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8335 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8336 real_allocation.y1 != old_allocation.y1);
8338 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8339 real_allocation.y2 != old_allocation.y2);
8341 if (origin_changed || child_moved || size_changed)
8342 stage_allocation_changed = TRUE;
8344 stage_allocation_changed = FALSE;
8346 /* If we get an allocation "out of the blue"
8347 * (we did not queue relayout), then we want to
8348 * ignore it. But if we have needs_allocation set,
8349 * we want to guarantee that allocate() virtual
8350 * method is always called, i.e. that queue_relayout()
8351 * always results in an allocate() invocation on
8354 * The optimization here is to avoid re-allocating
8355 * actors that did not queue relayout and were
8358 if (!priv->needs_allocation && !stage_allocation_changed)
8360 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8364 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8365 * clutter_actor_allocate(), it indicates whether the parent has its
8366 * absolute origin moved; when passed in to ClutterActor::allocate()
8367 * virtual method though, it indicates whether the child has its
8368 * absolute origin moved. So we set it when child_moved is TRUE
8371 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8373 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8375 klass = CLUTTER_ACTOR_GET_CLASS (self);
8376 klass->allocate (self, &real_allocation, flags);
8378 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8380 if (stage_allocation_changed)
8381 clutter_actor_queue_redraw (self);
8385 * clutter_actor_set_allocation:
8386 * @self: a #ClutterActor
8387 * @box: a #ClutterActorBox
8388 * @flags: allocation flags
8390 * Stores the allocation of @self as defined by @box.
8392 * This function can only be called from within the implementation of
8393 * the #ClutterActorClass.allocate() virtual function.
8395 * The allocation should have been adjusted to take into account constraints,
8396 * alignment, and margin properties. If you are implementing a #ClutterActor
8397 * subclass that provides its own layout management policy for its children
8398 * instead of using a #ClutterLayoutManager delegate, you should not call
8399 * this function on the children of @self; instead, you should call
8400 * clutter_actor_allocate(), which will adjust the allocation box for
8403 * This function should only be used by subclasses of #ClutterActor
8404 * that wish to store their allocation but cannot chain up to the
8405 * parent's implementation; the default implementation of the
8406 * #ClutterActorClass.allocate() virtual function will call this
8409 * It is important to note that, while chaining up was the recommended
8410 * behaviour for #ClutterActor subclasses prior to the introduction of
8411 * this function, it is recommended to call clutter_actor_set_allocation()
8414 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8415 * to handle the allocation of its children, this function will call
8416 * the clutter_layout_manager_allocate() function only if the
8417 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8418 * expected that the subclass will call clutter_layout_manager_allocate()
8419 * by itself. For instance, the following code:
8423 * my_actor_allocate (ClutterActor *actor,
8424 * const ClutterActorBox *allocation,
8425 * ClutterAllocationFlags flags)
8427 * ClutterActorBox new_alloc;
8428 * ClutterAllocationFlags new_flags;
8430 * adjust_allocation (allocation, &new_alloc);
8432 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8434 * /* this will use the layout manager set on the actor */
8435 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8439 * is equivalent to this:
8443 * my_actor_allocate (ClutterActor *actor,
8444 * const ClutterActorBox *allocation,
8445 * ClutterAllocationFlags flags)
8447 * ClutterLayoutManager *layout;
8448 * ClutterActorBox new_alloc;
8450 * adjust_allocation (allocation, &new_alloc);
8452 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8454 * layout = clutter_actor_get_layout_manager (actor);
8455 * clutter_layout_manager_allocate (layout,
8456 * CLUTTER_CONTAINER (actor),
8465 clutter_actor_set_allocation (ClutterActor *self,
8466 const ClutterActorBox *box,
8467 ClutterAllocationFlags flags)
8469 ClutterActorPrivate *priv;
8472 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8473 g_return_if_fail (box != NULL);
8475 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8477 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8478 "can only be called from within the implementation of "
8479 "the ClutterActor::allocate() virtual function.");
8485 g_object_freeze_notify (G_OBJECT (self));
8487 changed = clutter_actor_set_allocation_internal (self, box, flags);
8489 /* we allocate our children before we notify changes in our geometry,
8490 * so that people connecting to properties will be able to get valid
8491 * data out of the sub-tree of the scene graph that has this actor at
8494 clutter_actor_maybe_layout_children (self, box, flags);
8498 ClutterActorBox signal_box = priv->allocation;
8499 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8501 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8506 g_object_thaw_notify (G_OBJECT (self));
8510 * clutter_actor_set_geometry:
8511 * @self: A #ClutterActor
8512 * @geometry: A #ClutterGeometry
8514 * Sets the actor's fixed position and forces its minimum and natural
8515 * size, in pixels. This means the untransformed actor will have the
8516 * given geometry. This is the same as calling clutter_actor_set_position()
8517 * and clutter_actor_set_size().
8519 * Deprecated: 1.10: Use clutter_actor_set_position() and
8520 * clutter_actor_set_size() instead.
8523 clutter_actor_set_geometry (ClutterActor *self,
8524 const ClutterGeometry *geometry)
8526 g_object_freeze_notify (G_OBJECT (self));
8528 clutter_actor_set_position (self, geometry->x, geometry->y);
8529 clutter_actor_set_size (self, geometry->width, geometry->height);
8531 g_object_thaw_notify (G_OBJECT (self));
8535 * clutter_actor_get_geometry:
8536 * @self: A #ClutterActor
8537 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8539 * Gets the size and position of an actor relative to its parent
8540 * actor. This is the same as calling clutter_actor_get_position() and
8541 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8542 * requested size and position if the actor's allocation is invalid.
8544 * Deprecated: 1.10: Use clutter_actor_get_position() and
8545 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8549 clutter_actor_get_geometry (ClutterActor *self,
8550 ClutterGeometry *geometry)
8552 gfloat x, y, width, height;
8554 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8555 g_return_if_fail (geometry != NULL);
8557 clutter_actor_get_position (self, &x, &y);
8558 clutter_actor_get_size (self, &width, &height);
8560 geometry->x = (int) x;
8561 geometry->y = (int) y;
8562 geometry->width = (int) width;
8563 geometry->height = (int) height;
8567 * clutter_actor_set_position:
8568 * @self: A #ClutterActor
8569 * @x: New left position of actor in pixels.
8570 * @y: New top position of actor in pixels.
8572 * Sets the actor's fixed position in pixels relative to any parent
8575 * If a layout manager is in use, this position will override the
8576 * layout manager and force a fixed position.
8579 clutter_actor_set_position (ClutterActor *self,
8583 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8585 g_object_freeze_notify (G_OBJECT (self));
8587 clutter_actor_set_x (self, x);
8588 clutter_actor_set_y (self, y);
8590 g_object_thaw_notify (G_OBJECT (self));
8594 * clutter_actor_get_fixed_position_set:
8595 * @self: A #ClutterActor
8597 * Checks whether an actor has a fixed position set (and will thus be
8598 * unaffected by any layout manager).
8600 * Return value: %TRUE if the fixed position is set on the actor
8605 clutter_actor_get_fixed_position_set (ClutterActor *self)
8607 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8609 return self->priv->position_set;
8613 * clutter_actor_set_fixed_position_set:
8614 * @self: A #ClutterActor
8615 * @is_set: whether to use fixed position
8617 * Sets whether an actor has a fixed position set (and will thus be
8618 * unaffected by any layout manager).
8623 clutter_actor_set_fixed_position_set (ClutterActor *self,
8626 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8628 if (self->priv->position_set == (is_set != FALSE))
8631 self->priv->position_set = is_set != FALSE;
8632 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8634 clutter_actor_queue_relayout (self);
8638 * clutter_actor_move_by:
8639 * @self: A #ClutterActor
8640 * @dx: Distance to move Actor on X axis.
8641 * @dy: Distance to move Actor on Y axis.
8643 * Moves an actor by the specified distance relative to its current
8644 * position in pixels.
8646 * This function modifies the fixed position of an actor and thus removes
8647 * it from any layout management. Another way to move an actor is with an
8648 * anchor point, see clutter_actor_set_anchor_point().
8653 clutter_actor_move_by (ClutterActor *self,
8657 const ClutterLayoutInfo *info;
8660 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8662 info = _clutter_actor_get_layout_info_or_defaults (self);
8666 clutter_actor_set_position (self, x + dx, y + dy);
8670 clutter_actor_set_min_width (ClutterActor *self,
8673 ClutterActorPrivate *priv = self->priv;
8674 ClutterActorBox old = { 0, };
8675 ClutterLayoutInfo *info;
8677 /* if we are setting the size on a top-level actor and the
8678 * backend only supports static top-levels (e.g. framebuffers)
8679 * then we ignore the passed value and we override it with
8680 * the stage implementation's preferred size.
8682 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8683 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8686 info = _clutter_actor_get_layout_info (self);
8688 if (priv->min_width_set && min_width == info->min_width)
8691 g_object_freeze_notify (G_OBJECT (self));
8693 clutter_actor_store_old_geometry (self, &old);
8695 info->min_width = min_width;
8696 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8697 clutter_actor_set_min_width_set (self, TRUE);
8699 clutter_actor_notify_if_geometry_changed (self, &old);
8701 g_object_thaw_notify (G_OBJECT (self));
8703 clutter_actor_queue_relayout (self);
8707 clutter_actor_set_min_height (ClutterActor *self,
8711 ClutterActorPrivate *priv = self->priv;
8712 ClutterActorBox old = { 0, };
8713 ClutterLayoutInfo *info;
8715 /* if we are setting the size on a top-level actor and the
8716 * backend only supports static top-levels (e.g. framebuffers)
8717 * then we ignore the passed value and we override it with
8718 * the stage implementation's preferred size.
8720 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8721 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8724 info = _clutter_actor_get_layout_info (self);
8726 if (priv->min_height_set && min_height == info->min_height)
8729 g_object_freeze_notify (G_OBJECT (self));
8731 clutter_actor_store_old_geometry (self, &old);
8733 info->min_height = min_height;
8734 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8735 clutter_actor_set_min_height_set (self, TRUE);
8737 clutter_actor_notify_if_geometry_changed (self, &old);
8739 g_object_thaw_notify (G_OBJECT (self));
8741 clutter_actor_queue_relayout (self);
8745 clutter_actor_set_natural_width (ClutterActor *self,
8746 gfloat natural_width)
8748 ClutterActorPrivate *priv = self->priv;
8749 ClutterActorBox old = { 0, };
8750 ClutterLayoutInfo *info;
8752 /* if we are setting the size on a top-level actor and the
8753 * backend only supports static top-levels (e.g. framebuffers)
8754 * then we ignore the passed value and we override it with
8755 * the stage implementation's preferred size.
8757 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8758 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8761 info = _clutter_actor_get_layout_info (self);
8763 if (priv->natural_width_set && natural_width == info->natural_width)
8766 g_object_freeze_notify (G_OBJECT (self));
8768 clutter_actor_store_old_geometry (self, &old);
8770 info->natural_width = natural_width;
8771 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8772 clutter_actor_set_natural_width_set (self, TRUE);
8774 clutter_actor_notify_if_geometry_changed (self, &old);
8776 g_object_thaw_notify (G_OBJECT (self));
8778 clutter_actor_queue_relayout (self);
8782 clutter_actor_set_natural_height (ClutterActor *self,
8783 gfloat natural_height)
8785 ClutterActorPrivate *priv = self->priv;
8786 ClutterActorBox old = { 0, };
8787 ClutterLayoutInfo *info;
8789 /* if we are setting the size on a top-level actor and the
8790 * backend only supports static top-levels (e.g. framebuffers)
8791 * then we ignore the passed value and we override it with
8792 * the stage implementation's preferred size.
8794 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8795 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8798 info = _clutter_actor_get_layout_info (self);
8800 if (priv->natural_height_set && natural_height == info->natural_height)
8803 g_object_freeze_notify (G_OBJECT (self));
8805 clutter_actor_store_old_geometry (self, &old);
8807 info->natural_height = natural_height;
8808 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8809 clutter_actor_set_natural_height_set (self, TRUE);
8811 clutter_actor_notify_if_geometry_changed (self, &old);
8813 g_object_thaw_notify (G_OBJECT (self));
8815 clutter_actor_queue_relayout (self);
8819 clutter_actor_set_min_width_set (ClutterActor *self,
8820 gboolean use_min_width)
8822 ClutterActorPrivate *priv = self->priv;
8823 ClutterActorBox old = { 0, };
8825 if (priv->min_width_set == (use_min_width != FALSE))
8828 clutter_actor_store_old_geometry (self, &old);
8830 priv->min_width_set = use_min_width != FALSE;
8831 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8833 clutter_actor_notify_if_geometry_changed (self, &old);
8835 clutter_actor_queue_relayout (self);
8839 clutter_actor_set_min_height_set (ClutterActor *self,
8840 gboolean use_min_height)
8842 ClutterActorPrivate *priv = self->priv;
8843 ClutterActorBox old = { 0, };
8845 if (priv->min_height_set == (use_min_height != FALSE))
8848 clutter_actor_store_old_geometry (self, &old);
8850 priv->min_height_set = use_min_height != FALSE;
8851 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8853 clutter_actor_notify_if_geometry_changed (self, &old);
8855 clutter_actor_queue_relayout (self);
8859 clutter_actor_set_natural_width_set (ClutterActor *self,
8860 gboolean use_natural_width)
8862 ClutterActorPrivate *priv = self->priv;
8863 ClutterActorBox old = { 0, };
8865 if (priv->natural_width_set == (use_natural_width != FALSE))
8868 clutter_actor_store_old_geometry (self, &old);
8870 priv->natural_width_set = use_natural_width != FALSE;
8871 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8873 clutter_actor_notify_if_geometry_changed (self, &old);
8875 clutter_actor_queue_relayout (self);
8879 clutter_actor_set_natural_height_set (ClutterActor *self,
8880 gboolean use_natural_height)
8882 ClutterActorPrivate *priv = self->priv;
8883 ClutterActorBox old = { 0, };
8885 if (priv->natural_height_set == (use_natural_height != FALSE))
8888 clutter_actor_store_old_geometry (self, &old);
8890 priv->natural_height_set = use_natural_height != FALSE;
8891 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8893 clutter_actor_notify_if_geometry_changed (self, &old);
8895 clutter_actor_queue_relayout (self);
8899 * clutter_actor_set_request_mode:
8900 * @self: a #ClutterActor
8901 * @mode: the request mode
8903 * Sets the geometry request mode of @self.
8905 * The @mode determines the order for invoking
8906 * clutter_actor_get_preferred_width() and
8907 * clutter_actor_get_preferred_height()
8912 clutter_actor_set_request_mode (ClutterActor *self,
8913 ClutterRequestMode mode)
8915 ClutterActorPrivate *priv;
8917 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8921 if (priv->request_mode == mode)
8924 priv->request_mode = mode;
8926 priv->needs_width_request = TRUE;
8927 priv->needs_height_request = TRUE;
8929 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8931 clutter_actor_queue_relayout (self);
8935 * clutter_actor_get_request_mode:
8936 * @self: a #ClutterActor
8938 * Retrieves the geometry request mode of @self
8940 * Return value: the request mode for the actor
8945 clutter_actor_get_request_mode (ClutterActor *self)
8947 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8948 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8950 return self->priv->request_mode;
8953 /* variant of set_width() without checks and without notification
8954 * freeze+thaw, for internal usage only
8957 clutter_actor_set_width_internal (ClutterActor *self,
8962 /* the Stage will use the :min-width to control the minimum
8963 * width to be resized to, so we should not be setting it
8964 * along with the :natural-width
8966 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8967 clutter_actor_set_min_width (self, width);
8969 clutter_actor_set_natural_width (self, width);
8973 /* we only unset the :natural-width for the Stage */
8974 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8975 clutter_actor_set_min_width_set (self, FALSE);
8977 clutter_actor_set_natural_width_set (self, FALSE);
8981 /* variant of set_height() without checks and without notification
8982 * freeze+thaw, for internal usage only
8985 clutter_actor_set_height_internal (ClutterActor *self,
8990 /* see the comment above in set_width_internal() */
8991 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8992 clutter_actor_set_min_height (self, height);
8994 clutter_actor_set_natural_height (self, height);
8998 /* see the comment above in set_width_internal() */
8999 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9000 clutter_actor_set_min_height_set (self, FALSE);
9002 clutter_actor_set_natural_height_set (self, FALSE);
9007 * clutter_actor_set_size:
9008 * @self: A #ClutterActor
9009 * @width: New width of actor in pixels, or -1
9010 * @height: New height of actor in pixels, or -1
9012 * Sets the actor's size request in pixels. This overrides any
9013 * "normal" size request the actor would have. For example
9014 * a text actor might normally request the size of the text;
9015 * this function would force a specific size instead.
9017 * If @width and/or @height are -1 the actor will use its
9018 * "normal" size request instead of overriding it, i.e.
9019 * you can "unset" the size with -1.
9021 * This function sets or unsets both the minimum and natural size.
9024 clutter_actor_set_size (ClutterActor *self,
9028 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9030 g_object_freeze_notify (G_OBJECT (self));
9032 clutter_actor_set_width (self, width);
9033 clutter_actor_set_height (self, height);
9035 g_object_thaw_notify (G_OBJECT (self));
9039 * clutter_actor_get_size:
9040 * @self: A #ClutterActor
9041 * @width: (out) (allow-none): return location for the width, or %NULL.
9042 * @height: (out) (allow-none): return location for the height, or %NULL.
9044 * This function tries to "do what you mean" and return
9045 * the size an actor will have. If the actor has a valid
9046 * allocation, the allocation will be returned; otherwise,
9047 * the actors natural size request will be returned.
9049 * If you care whether you get the request vs. the allocation, you
9050 * should probably call a different function like
9051 * clutter_actor_get_allocation_box() or
9052 * clutter_actor_get_preferred_width().
9057 clutter_actor_get_size (ClutterActor *self,
9061 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9064 *width = clutter_actor_get_width (self);
9067 *height = clutter_actor_get_height (self);
9071 * clutter_actor_get_position:
9072 * @self: a #ClutterActor
9073 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9074 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9076 * This function tries to "do what you mean" and tell you where the
9077 * actor is, prior to any transformations. Retrieves the fixed
9078 * position of an actor in pixels, if one has been set; otherwise, if
9079 * the allocation is valid, returns the actor's allocated position;
9080 * otherwise, returns 0,0.
9082 * The returned position is in pixels.
9087 clutter_actor_get_position (ClutterActor *self,
9091 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9094 *x = clutter_actor_get_x (self);
9097 *y = clutter_actor_get_y (self);
9101 * clutter_actor_get_transformed_position:
9102 * @self: A #ClutterActor
9103 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9104 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9106 * Gets the absolute position of an actor, in pixels relative to the stage.
9111 clutter_actor_get_transformed_position (ClutterActor *self,
9118 v1.x = v1.y = v1.z = 0;
9119 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9129 * clutter_actor_get_transformed_size:
9130 * @self: A #ClutterActor
9131 * @width: (out) (allow-none): return location for the width, or %NULL
9132 * @height: (out) (allow-none): return location for the height, or %NULL
9134 * Gets the absolute size of an actor in pixels, taking into account the
9137 * If the actor has a valid allocation, the allocated size will be used.
9138 * If the actor has not a valid allocation then the preferred size will
9139 * be transformed and returned.
9141 * If you want the transformed allocation, see
9142 * clutter_actor_get_abs_allocation_vertices() instead.
9144 * <note>When the actor (or one of its ancestors) is rotated around the
9145 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9146 * as a generic quadrangle; in that case this function returns the size
9147 * of the smallest rectangle that encapsulates the entire quad. Please
9148 * note that in this case no assumptions can be made about the relative
9149 * position of this envelope to the absolute position of the actor, as
9150 * returned by clutter_actor_get_transformed_position(); if you need this
9151 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9152 * to get the coords of the actual quadrangle.</note>
9157 clutter_actor_get_transformed_size (ClutterActor *self,
9161 ClutterActorPrivate *priv;
9163 gfloat x_min, x_max, y_min, y_max;
9166 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9170 /* if the actor hasn't been allocated yet, get the preferred
9171 * size and transform that
9173 if (priv->needs_allocation)
9175 gfloat natural_width, natural_height;
9176 ClutterActorBox box;
9178 /* Make a fake allocation to transform.
9180 * NB: _clutter_actor_transform_and_project_box expects a box in
9181 * the actor's coordinate space... */
9186 natural_width = natural_height = 0;
9187 clutter_actor_get_preferred_size (self, NULL, NULL,
9191 box.x2 = natural_width;
9192 box.y2 = natural_height;
9194 _clutter_actor_transform_and_project_box (self, &box, v);
9197 clutter_actor_get_abs_allocation_vertices (self, v);
9199 x_min = x_max = v[0].x;
9200 y_min = y_max = v[0].y;
9202 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9218 *width = x_max - x_min;
9221 *height = y_max - y_min;
9225 * clutter_actor_get_width:
9226 * @self: A #ClutterActor
9228 * Retrieves the width of a #ClutterActor.
9230 * If the actor has a valid allocation, this function will return the
9231 * width of the allocated area given to the actor.
9233 * If the actor does not have a valid allocation, this function will
9234 * return the actor's natural width, that is the preferred width of
9237 * If you care whether you get the preferred width or the width that
9238 * has been assigned to the actor, you should probably call a different
9239 * function like clutter_actor_get_allocation_box() to retrieve the
9240 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9243 * If an actor has a fixed width, for instance a width that has been
9244 * assigned using clutter_actor_set_width(), the width returned will
9245 * be the same value.
9247 * Return value: the width of the actor, in pixels
9250 clutter_actor_get_width (ClutterActor *self)
9252 ClutterActorPrivate *priv;
9254 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9258 if (priv->needs_allocation)
9260 gfloat natural_width = 0;
9262 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9263 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9266 gfloat natural_height = 0;
9268 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9269 clutter_actor_get_preferred_width (self, natural_height,
9274 return natural_width;
9277 return priv->allocation.x2 - priv->allocation.x1;
9281 * clutter_actor_get_height:
9282 * @self: A #ClutterActor
9284 * Retrieves the height of a #ClutterActor.
9286 * If the actor has a valid allocation, this function will return the
9287 * height of the allocated area given to the actor.
9289 * If the actor does not have a valid allocation, this function will
9290 * return the actor's natural height, that is the preferred height of
9293 * If you care whether you get the preferred height or the height that
9294 * has been assigned to the actor, you should probably call a different
9295 * function like clutter_actor_get_allocation_box() to retrieve the
9296 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9299 * If an actor has a fixed height, for instance a height that has been
9300 * assigned using clutter_actor_set_height(), the height returned will
9301 * be the same value.
9303 * Return value: the height of the actor, in pixels
9306 clutter_actor_get_height (ClutterActor *self)
9308 ClutterActorPrivate *priv;
9310 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9314 if (priv->needs_allocation)
9316 gfloat natural_height = 0;
9318 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9320 gfloat natural_width = 0;
9322 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9323 clutter_actor_get_preferred_height (self, natural_width,
9324 NULL, &natural_height);
9327 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9329 return natural_height;
9332 return priv->allocation.y2 - priv->allocation.y1;
9336 * clutter_actor_set_width:
9337 * @self: A #ClutterActor
9338 * @width: Requested new width for the actor, in pixels, or -1
9340 * Forces a width on an actor, causing the actor's preferred width
9341 * and height (if any) to be ignored.
9343 * If @width is -1 the actor will use its preferred width request
9344 * instead of overriding it, i.e. you can "unset" the width with -1.
9346 * This function sets both the minimum and natural size of the actor.
9351 clutter_actor_set_width (ClutterActor *self,
9354 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9356 if (clutter_actor_get_easing_duration (self) != 0)
9358 ClutterTransition *transition;
9360 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9361 if (transition == NULL)
9363 float old_width = clutter_actor_get_width (self);
9365 transition = _clutter_actor_create_transition (self,
9366 obj_props[PROP_WIDTH],
9369 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9372 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9374 clutter_actor_queue_relayout (self);
9378 g_object_freeze_notify (G_OBJECT (self));
9380 clutter_actor_set_width_internal (self, width);
9382 g_object_thaw_notify (G_OBJECT (self));
9387 * clutter_actor_set_height:
9388 * @self: A #ClutterActor
9389 * @height: Requested new height for the actor, in pixels, or -1
9391 * Forces a height on an actor, causing the actor's preferred width
9392 * and height (if any) to be ignored.
9394 * If @height is -1 the actor will use its preferred height instead of
9395 * overriding it, i.e. you can "unset" the height with -1.
9397 * This function sets both the minimum and natural size of the actor.
9402 clutter_actor_set_height (ClutterActor *self,
9405 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9407 if (clutter_actor_get_easing_duration (self) != 0)
9409 ClutterTransition *transition;
9411 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9412 if (transition == NULL)
9414 float old_height = clutter_actor_get_height (self);
9416 transition = _clutter_actor_create_transition (self,
9417 obj_props[PROP_HEIGHT],
9420 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9423 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9425 clutter_actor_queue_relayout (self);
9429 g_object_freeze_notify (G_OBJECT (self));
9431 clutter_actor_set_height_internal (self, height);
9433 g_object_thaw_notify (G_OBJECT (self));
9438 clutter_actor_set_x_internal (ClutterActor *self,
9441 ClutterActorPrivate *priv = self->priv;
9442 ClutterLayoutInfo *linfo;
9443 ClutterActorBox old = { 0, };
9445 linfo = _clutter_actor_get_layout_info (self);
9447 if (priv->position_set && linfo->fixed_x == x)
9450 clutter_actor_store_old_geometry (self, &old);
9453 clutter_actor_set_fixed_position_set (self, TRUE);
9455 clutter_actor_notify_if_geometry_changed (self, &old);
9457 clutter_actor_queue_relayout (self);
9461 clutter_actor_set_y_internal (ClutterActor *self,
9464 ClutterActorPrivate *priv = self->priv;
9465 ClutterLayoutInfo *linfo;
9466 ClutterActorBox old = { 0, };
9468 linfo = _clutter_actor_get_layout_info (self);
9470 if (priv->position_set && linfo->fixed_y == y)
9473 clutter_actor_store_old_geometry (self, &old);
9476 clutter_actor_set_fixed_position_set (self, TRUE);
9478 clutter_actor_notify_if_geometry_changed (self, &old);
9482 * clutter_actor_set_x:
9483 * @self: a #ClutterActor
9484 * @x: the actor's position on the X axis
9486 * Sets the actor's X coordinate, relative to its parent, in pixels.
9488 * Overrides any layout manager and forces a fixed position for
9491 * The #ClutterActor:x property is animatable.
9496 clutter_actor_set_x (ClutterActor *self,
9499 const ClutterLayoutInfo *linfo;
9501 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9503 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9505 if (clutter_actor_get_easing_duration (self) != 0)
9507 ClutterTransition *transition;
9509 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9510 if (transition == NULL)
9512 transition = _clutter_actor_create_transition (self,
9517 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9520 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9522 clutter_actor_queue_relayout (self);
9525 clutter_actor_set_x_internal (self, x);
9529 * clutter_actor_set_y:
9530 * @self: a #ClutterActor
9531 * @y: the actor's position on the Y axis
9533 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9535 * Overrides any layout manager and forces a fixed position for
9538 * The #ClutterActor:y property is animatable.
9543 clutter_actor_set_y (ClutterActor *self,
9546 const ClutterLayoutInfo *linfo;
9548 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9550 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9552 if (clutter_actor_get_easing_duration (self) != 0)
9554 ClutterTransition *transition;
9556 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9557 if (transition == NULL)
9559 transition = _clutter_actor_create_transition (self,
9564 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9567 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9569 clutter_actor_queue_relayout (self);
9572 clutter_actor_set_y_internal (self, y);
9574 clutter_actor_queue_relayout (self);
9578 * clutter_actor_get_x:
9579 * @self: A #ClutterActor
9581 * Retrieves the X coordinate of a #ClutterActor.
9583 * This function tries to "do what you mean", by returning the
9584 * correct value depending on the actor's state.
9586 * If the actor has a valid allocation, this function will return
9587 * the X coordinate of the origin of the allocation box.
9589 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9590 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9591 * function will return that coordinate.
9593 * If both the allocation and a fixed position are missing, this function
9596 * Return value: the X coordinate, in pixels, ignoring any
9597 * transformation (i.e. scaling, rotation)
9600 clutter_actor_get_x (ClutterActor *self)
9602 ClutterActorPrivate *priv;
9604 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9608 if (priv->needs_allocation)
9610 if (priv->position_set)
9612 const ClutterLayoutInfo *info;
9614 info = _clutter_actor_get_layout_info_or_defaults (self);
9616 return info->fixed_x;
9622 return priv->allocation.x1;
9626 * clutter_actor_get_y:
9627 * @self: A #ClutterActor
9629 * Retrieves the Y coordinate of a #ClutterActor.
9631 * This function tries to "do what you mean", by returning the
9632 * correct value depending on the actor's state.
9634 * If the actor has a valid allocation, this function will return
9635 * the Y coordinate of the origin of the allocation box.
9637 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9638 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9639 * function will return that coordinate.
9641 * If both the allocation and a fixed position are missing, this function
9644 * Return value: the Y coordinate, in pixels, ignoring any
9645 * transformation (i.e. scaling, rotation)
9648 clutter_actor_get_y (ClutterActor *self)
9650 ClutterActorPrivate *priv;
9652 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9656 if (priv->needs_allocation)
9658 if (priv->position_set)
9660 const ClutterLayoutInfo *info;
9662 info = _clutter_actor_get_layout_info_or_defaults (self);
9664 return info->fixed_y;
9670 return priv->allocation.y1;
9674 * clutter_actor_set_scale:
9675 * @self: A #ClutterActor
9676 * @scale_x: double factor to scale actor by horizontally.
9677 * @scale_y: double factor to scale actor by vertically.
9679 * Scales an actor with the given factors. The scaling is relative to
9680 * the scale center and the anchor point. The scale center is
9681 * unchanged by this function and defaults to 0,0.
9683 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9689 clutter_actor_set_scale (ClutterActor *self,
9693 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9695 g_object_freeze_notify (G_OBJECT (self));
9697 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9698 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9700 g_object_thaw_notify (G_OBJECT (self));
9704 * clutter_actor_set_scale_full:
9705 * @self: A #ClutterActor
9706 * @scale_x: double factor to scale actor by horizontally.
9707 * @scale_y: double factor to scale actor by vertically.
9708 * @center_x: X coordinate of the center of the scale.
9709 * @center_y: Y coordinate of the center of the scale
9711 * Scales an actor with the given factors around the given center
9712 * point. The center point is specified in pixels relative to the
9713 * anchor point (usually the top left corner of the actor).
9715 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9721 clutter_actor_set_scale_full (ClutterActor *self,
9727 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9729 g_object_freeze_notify (G_OBJECT (self));
9731 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9732 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9733 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9734 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9736 g_object_thaw_notify (G_OBJECT (self));
9740 * clutter_actor_set_scale_with_gravity:
9741 * @self: A #ClutterActor
9742 * @scale_x: double factor to scale actor by horizontally.
9743 * @scale_y: double factor to scale actor by vertically.
9744 * @gravity: the location of the scale center expressed as a compass
9747 * Scales an actor with the given factors around the given
9748 * center point. The center point is specified as one of the compass
9749 * directions in #ClutterGravity. For example, setting it to north
9750 * will cause the top of the actor to remain unchanged and the rest of
9751 * the actor to expand left, right and downwards.
9753 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9759 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9762 ClutterGravity gravity)
9764 ClutterTransformInfo *info;
9767 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9769 obj = G_OBJECT (self);
9771 g_object_freeze_notify (obj);
9773 info = _clutter_actor_get_transform_info (self);
9774 info->scale_x = scale_x;
9775 info->scale_y = scale_y;
9777 if (gravity == CLUTTER_GRAVITY_NONE)
9778 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9780 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9782 self->priv->transform_valid = FALSE;
9784 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9785 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9786 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9787 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9788 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9790 clutter_actor_queue_redraw (self);
9792 g_object_thaw_notify (obj);
9796 * clutter_actor_get_scale:
9797 * @self: A #ClutterActor
9798 * @scale_x: (out) (allow-none): Location to store horizonal
9799 * scale factor, or %NULL.
9800 * @scale_y: (out) (allow-none): Location to store vertical
9801 * scale factor, or %NULL.
9803 * Retrieves an actors scale factors.
9808 clutter_actor_get_scale (ClutterActor *self,
9812 const ClutterTransformInfo *info;
9814 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9816 info = _clutter_actor_get_transform_info_or_defaults (self);
9819 *scale_x = info->scale_x;
9822 *scale_y = info->scale_y;
9826 * clutter_actor_get_scale_center:
9827 * @self: A #ClutterActor
9828 * @center_x: (out) (allow-none): Location to store the X position
9829 * of the scale center, or %NULL.
9830 * @center_y: (out) (allow-none): Location to store the Y position
9831 * of the scale center, or %NULL.
9833 * Retrieves the scale center coordinate in pixels relative to the top
9834 * left corner of the actor. If the scale center was specified using a
9835 * #ClutterGravity this will calculate the pixel offset using the
9836 * current size of the actor.
9841 clutter_actor_get_scale_center (ClutterActor *self,
9845 const ClutterTransformInfo *info;
9847 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9849 info = _clutter_actor_get_transform_info_or_defaults (self);
9851 clutter_anchor_coord_get_units (self, &info->scale_center,
9858 * clutter_actor_get_scale_gravity:
9859 * @self: A #ClutterActor
9861 * Retrieves the scale center as a compass direction. If the scale
9862 * center was specified in pixels or units this will return
9863 * %CLUTTER_GRAVITY_NONE.
9865 * Return value: the scale gravity
9870 clutter_actor_get_scale_gravity (ClutterActor *self)
9872 const ClutterTransformInfo *info;
9874 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9876 info = _clutter_actor_get_transform_info_or_defaults (self);
9878 return clutter_anchor_coord_get_gravity (&info->scale_center);
9882 clutter_actor_set_opacity_internal (ClutterActor *self,
9885 ClutterActorPrivate *priv = self->priv;
9887 if (priv->opacity != opacity)
9889 priv->opacity = opacity;
9891 /* Queue a redraw from the flatten effect so that it can use
9892 its cached image if available instead of having to redraw the
9893 actual actor. If it doesn't end up using the FBO then the
9894 effect is still able to continue the paint anyway. If there
9895 is no flatten effect yet then this is equivalent to queueing
9897 _clutter_actor_queue_redraw_full (self,
9900 priv->flatten_effect);
9902 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9907 * clutter_actor_set_opacity:
9908 * @self: A #ClutterActor
9909 * @opacity: New opacity value for the actor.
9911 * Sets the actor's opacity, with zero being completely transparent and
9912 * 255 (0xff) being fully opaque.
9914 * The #ClutterActor:opacity property is animatable.
9917 clutter_actor_set_opacity (ClutterActor *self,
9920 ClutterActorPrivate *priv;
9922 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9926 if (clutter_actor_get_easing_duration (self) != 0)
9928 ClutterTransition *transition;
9930 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9931 if (transition == NULL)
9933 transition = _clutter_actor_create_transition (self,
9934 obj_props[PROP_OPACITY],
9937 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9940 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9942 clutter_actor_queue_redraw (self);
9945 clutter_actor_set_opacity_internal (self, opacity);
9949 * clutter_actor_get_paint_opacity_internal:
9950 * @self: a #ClutterActor
9952 * Retrieves the absolute opacity of the actor, as it appears on the stage
9954 * This function does not do type checks
9956 * Return value: the absolute opacity of the actor
9959 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9961 ClutterActorPrivate *priv = self->priv;
9962 ClutterActor *parent;
9964 /* override the top-level opacity to always be 255; even in
9965 * case of ClutterStage:use-alpha being TRUE we want the rest
9966 * of the scene to be painted
9968 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9971 if (priv->opacity_override >= 0)
9972 return priv->opacity_override;
9974 parent = priv->parent;
9976 /* Factor in the actual actors opacity with parents */
9979 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9981 if (opacity != 0xff)
9982 return (opacity * priv->opacity) / 0xff;
9985 return priv->opacity;
9990 * clutter_actor_get_paint_opacity:
9991 * @self: A #ClutterActor
9993 * Retrieves the absolute opacity of the actor, as it appears on the stage.
9995 * This function traverses the hierarchy chain and composites the opacity of
9996 * the actor with that of its parents.
9998 * This function is intended for subclasses to use in the paint virtual
9999 * function, to paint themselves with the correct opacity.
10001 * Return value: The actor opacity value.
10006 clutter_actor_get_paint_opacity (ClutterActor *self)
10008 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10010 return clutter_actor_get_paint_opacity_internal (self);
10014 * clutter_actor_get_opacity:
10015 * @self: a #ClutterActor
10017 * Retrieves the opacity value of an actor, as set by
10018 * clutter_actor_set_opacity().
10020 * For retrieving the absolute opacity of the actor inside a paint
10021 * virtual function, see clutter_actor_get_paint_opacity().
10023 * Return value: the opacity of the actor
10026 clutter_actor_get_opacity (ClutterActor *self)
10028 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10030 return self->priv->opacity;
10034 * clutter_actor_set_offscreen_redirect:
10035 * @self: A #ClutterActor
10036 * @redirect: New offscreen redirect flags for the actor.
10038 * Defines the circumstances where the actor should be redirected into
10039 * an offscreen image. The offscreen image is used to flatten the
10040 * actor into a single image while painting for two main reasons.
10041 * Firstly, when the actor is painted a second time without any of its
10042 * contents changing it can simply repaint the cached image without
10043 * descending further down the actor hierarchy. Secondly, it will make
10044 * the opacity look correct even if there are overlapping primitives
10047 * Caching the actor could in some cases be a performance win and in
10048 * some cases be a performance lose so it is important to determine
10049 * which value is right for an actor before modifying this value. For
10050 * example, there is never any reason to flatten an actor that is just
10051 * a single texture (such as a #ClutterTexture) because it is
10052 * effectively already cached in an image so the offscreen would be
10053 * redundant. Also if the actor contains primitives that are far apart
10054 * with a large transparent area in the middle (such as a large
10055 * CluterGroup with a small actor in the top left and a small actor in
10056 * the bottom right) then the cached image will contain the entire
10057 * image of the large area and the paint will waste time blending all
10058 * of the transparent pixels in the middle.
10060 * The default method of implementing opacity on a container simply
10061 * forwards on the opacity to all of the children. If the children are
10062 * overlapping then it will appear as if they are two separate glassy
10063 * objects and there will be a break in the color where they
10064 * overlap. By redirecting to an offscreen buffer it will be as if the
10065 * two opaque objects are combined into one and then made transparent
10066 * which is usually what is expected.
10068 * The image below demonstrates the difference between redirecting and
10069 * not. The image shows two Clutter groups, each containing a red and
10070 * a green rectangle which overlap. The opacity on the group is set to
10071 * 128 (which is 50%). When the offscreen redirect is not used, the
10072 * red rectangle can be seen through the blue rectangle as if the two
10073 * rectangles were separately transparent. When the redirect is used
10074 * the group as a whole is transparent instead so the red rectangle is
10075 * not visible where they overlap.
10077 * <figure id="offscreen-redirect">
10078 * <title>Sample of using an offscreen redirect for transparency</title>
10079 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10082 * The default value for this property is 0, so we effectively will
10083 * never redirect an actor offscreen by default. This means that there
10084 * are times that transparent actors may look glassy as described
10085 * above. The reason this is the default is because there is a
10086 * performance trade off between quality and performance here. In many
10087 * cases the default form of glassy opacity looks good enough, but if
10088 * it's not you will need to set the
10089 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10090 * redirection for opacity.
10092 * Custom actors that don't contain any overlapping primitives are
10093 * recommended to override the has_overlaps() virtual to return %FALSE
10094 * for maximum efficiency.
10099 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10100 ClutterOffscreenRedirect redirect)
10102 ClutterActorPrivate *priv;
10104 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10108 if (priv->offscreen_redirect != redirect)
10110 priv->offscreen_redirect = redirect;
10112 /* Queue a redraw from the effect so that it can use its cached
10113 image if available instead of having to redraw the actual
10114 actor. If it doesn't end up using the FBO then the effect is
10115 still able to continue the paint anyway. If there is no
10116 effect then this is equivalent to queuing a full redraw */
10117 _clutter_actor_queue_redraw_full (self,
10120 priv->flatten_effect);
10122 g_object_notify_by_pspec (G_OBJECT (self),
10123 obj_props[PROP_OFFSCREEN_REDIRECT]);
10128 * clutter_actor_get_offscreen_redirect:
10129 * @self: a #ClutterActor
10131 * Retrieves whether to redirect the actor to an offscreen buffer, as
10132 * set by clutter_actor_set_offscreen_redirect().
10134 * Return value: the value of the offscreen-redirect property of the actor
10138 ClutterOffscreenRedirect
10139 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10141 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10143 return self->priv->offscreen_redirect;
10147 * clutter_actor_set_name:
10148 * @self: A #ClutterActor
10149 * @name: Textual tag to apply to actor
10151 * Sets the given name to @self. The name can be used to identify
10155 clutter_actor_set_name (ClutterActor *self,
10158 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10160 g_free (self->priv->name);
10161 self->priv->name = g_strdup (name);
10163 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10167 * clutter_actor_get_name:
10168 * @self: A #ClutterActor
10170 * Retrieves the name of @self.
10172 * Return value: the name of the actor, or %NULL. The returned string is
10173 * owned by the actor and should not be modified or freed.
10176 clutter_actor_get_name (ClutterActor *self)
10178 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10180 return self->priv->name;
10184 * clutter_actor_get_gid:
10185 * @self: A #ClutterActor
10187 * Retrieves the unique id for @self.
10189 * Return value: Globally unique value for this object instance.
10193 * Deprecated: 1.8: The id is not used any longer.
10196 clutter_actor_get_gid (ClutterActor *self)
10198 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10200 return self->priv->id;
10204 clutter_actor_set_depth_internal (ClutterActor *self,
10207 ClutterTransformInfo *info;
10209 info = _clutter_actor_get_transform_info (self);
10211 if (info->depth != depth)
10213 /* Sets Z value - XXX 2.0: should we invert? */
10214 info->depth = depth;
10216 self->priv->transform_valid = FALSE;
10218 /* FIXME - remove this crap; sadly, there are still containers
10219 * in Clutter that depend on this utter brain damage
10221 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10223 clutter_actor_queue_redraw (self);
10225 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10230 * clutter_actor_set_depth:
10231 * @self: a #ClutterActor
10234 * Sets the Z coordinate of @self to @depth.
10236 * The unit used by @depth is dependant on the perspective setup. See
10237 * also clutter_stage_set_perspective().
10240 clutter_actor_set_depth (ClutterActor *self,
10243 const ClutterTransformInfo *tinfo;
10245 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10247 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10249 if (clutter_actor_get_easing_duration (self) != 0)
10251 ClutterTransition *transition;
10253 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10254 if (transition == NULL)
10256 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10259 clutter_timeline_start (CLUTTER_TIMELINE (transition));
10262 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10264 clutter_actor_queue_redraw (self);
10267 clutter_actor_set_depth_internal (self, depth);
10271 * clutter_actor_get_depth:
10272 * @self: a #ClutterActor
10274 * Retrieves the depth of @self.
10276 * Return value: the depth of the actor
10279 clutter_actor_get_depth (ClutterActor *self)
10281 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10283 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10287 * clutter_actor_set_rotation:
10288 * @self: a #ClutterActor
10289 * @axis: the axis of rotation
10290 * @angle: the angle of rotation
10291 * @x: X coordinate of the rotation center
10292 * @y: Y coordinate of the rotation center
10293 * @z: Z coordinate of the rotation center
10295 * Sets the rotation angle of @self around the given axis.
10297 * The rotation center coordinates used depend on the value of @axis:
10299 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10300 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10301 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10304 * The rotation coordinates are relative to the anchor point of the
10305 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10306 * point is set, the upper left corner is assumed as the origin.
10311 clutter_actor_set_rotation (ClutterActor *self,
10312 ClutterRotateAxis axis,
10320 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10326 g_object_freeze_notify (G_OBJECT (self));
10328 clutter_actor_set_rotation_angle (self, axis, angle);
10329 clutter_actor_set_rotation_center_internal (self, axis, &v);
10331 g_object_thaw_notify (G_OBJECT (self));
10335 * clutter_actor_set_z_rotation_from_gravity:
10336 * @self: a #ClutterActor
10337 * @angle: the angle of rotation
10338 * @gravity: the center point of the rotation
10340 * Sets the rotation angle of @self around the Z axis using the center
10341 * point specified as a compass point. For example to rotate such that
10342 * the center of the actor remains static you can use
10343 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10344 * will move accordingly.
10349 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10351 ClutterGravity gravity)
10353 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10355 if (gravity == CLUTTER_GRAVITY_NONE)
10356 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10359 GObject *obj = G_OBJECT (self);
10360 ClutterTransformInfo *info;
10362 info = _clutter_actor_get_transform_info (self);
10364 g_object_freeze_notify (obj);
10366 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10368 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10369 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10370 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10372 g_object_thaw_notify (obj);
10377 * clutter_actor_get_rotation:
10378 * @self: a #ClutterActor
10379 * @axis: the axis of rotation
10380 * @x: (out): return value for the X coordinate of the center of rotation
10381 * @y: (out): return value for the Y coordinate of the center of rotation
10382 * @z: (out): return value for the Z coordinate of the center of rotation
10384 * Retrieves the angle and center of rotation on the given axis,
10385 * set using clutter_actor_set_rotation().
10387 * Return value: the angle of rotation
10392 clutter_actor_get_rotation (ClutterActor *self,
10393 ClutterRotateAxis axis,
10398 const ClutterTransformInfo *info;
10399 const AnchorCoord *anchor_coord;
10400 gdouble retval = 0;
10402 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10404 info = _clutter_actor_get_transform_info_or_defaults (self);
10408 case CLUTTER_X_AXIS:
10409 anchor_coord = &info->rx_center;
10410 retval = info->rx_angle;
10413 case CLUTTER_Y_AXIS:
10414 anchor_coord = &info->ry_center;
10415 retval = info->ry_angle;
10418 case CLUTTER_Z_AXIS:
10419 anchor_coord = &info->rz_center;
10420 retval = info->rz_angle;
10424 anchor_coord = NULL;
10429 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10435 * clutter_actor_get_z_rotation_gravity:
10436 * @self: A #ClutterActor
10438 * Retrieves the center for the rotation around the Z axis as a
10439 * compass direction. If the center was specified in pixels or units
10440 * this will return %CLUTTER_GRAVITY_NONE.
10442 * Return value: the Z rotation center
10447 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10449 const ClutterTransformInfo *info;
10451 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10453 info = _clutter_actor_get_transform_info_or_defaults (self);
10455 return clutter_anchor_coord_get_gravity (&info->rz_center);
10459 * clutter_actor_set_clip:
10460 * @self: A #ClutterActor
10461 * @xoff: X offset of the clip rectangle
10462 * @yoff: Y offset of the clip rectangle
10463 * @width: Width of the clip rectangle
10464 * @height: Height of the clip rectangle
10466 * Sets clip area for @self. The clip area is always computed from the
10467 * upper left corner of the actor, even if the anchor point is set
10473 clutter_actor_set_clip (ClutterActor *self,
10479 ClutterActorPrivate *priv;
10481 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10485 if (priv->has_clip &&
10486 priv->clip.x == xoff &&
10487 priv->clip.y == yoff &&
10488 priv->clip.width == width &&
10489 priv->clip.height == height)
10492 priv->clip.x = xoff;
10493 priv->clip.y = yoff;
10494 priv->clip.width = width;
10495 priv->clip.height = height;
10497 priv->has_clip = TRUE;
10499 clutter_actor_queue_redraw (self);
10501 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10502 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10506 * clutter_actor_remove_clip:
10507 * @self: A #ClutterActor
10509 * Removes clip area from @self.
10512 clutter_actor_remove_clip (ClutterActor *self)
10514 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10516 if (!self->priv->has_clip)
10519 self->priv->has_clip = FALSE;
10521 clutter_actor_queue_redraw (self);
10523 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10527 * clutter_actor_has_clip:
10528 * @self: a #ClutterActor
10530 * Determines whether the actor has a clip area set or not.
10532 * Return value: %TRUE if the actor has a clip area set.
10537 clutter_actor_has_clip (ClutterActor *self)
10539 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10541 return self->priv->has_clip;
10545 * clutter_actor_get_clip:
10546 * @self: a #ClutterActor
10547 * @xoff: (out) (allow-none): return location for the X offset of
10548 * the clip rectangle, or %NULL
10549 * @yoff: (out) (allow-none): return location for the Y offset of
10550 * the clip rectangle, or %NULL
10551 * @width: (out) (allow-none): return location for the width of
10552 * the clip rectangle, or %NULL
10553 * @height: (out) (allow-none): return location for the height of
10554 * the clip rectangle, or %NULL
10556 * Gets the clip area for @self, if any is set
10561 clutter_actor_get_clip (ClutterActor *self,
10567 ClutterActorPrivate *priv;
10569 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10573 if (!priv->has_clip)
10577 *xoff = priv->clip.x;
10580 *yoff = priv->clip.y;
10583 *width = priv->clip.width;
10585 if (height != NULL)
10586 *height = priv->clip.height;
10590 * clutter_actor_get_children:
10591 * @self: a #ClutterActor
10593 * Retrieves the list of children of @self.
10595 * Return value: (transfer container) (element-type ClutterActor): A newly
10596 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10602 clutter_actor_get_children (ClutterActor *self)
10604 ClutterActor *iter;
10607 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10609 /* we walk the list backward so that we can use prepend(),
10612 for (iter = self->priv->last_child, res = NULL;
10614 iter = iter->priv->prev_sibling)
10616 res = g_list_prepend (res, iter);
10623 * insert_child_at_depth:
10624 * @self: a #ClutterActor
10625 * @child: a #ClutterActor
10627 * Inserts @child inside the list of children held by @self, using
10628 * the depth as the insertion criteria.
10630 * This sadly makes the insertion not O(1), but we can keep the
10631 * list sorted so that the painters algorithm we use for painting
10632 * the children will work correctly.
10635 insert_child_at_depth (ClutterActor *self,
10636 ClutterActor *child,
10637 gpointer dummy G_GNUC_UNUSED)
10639 ClutterActor *iter;
10642 child->priv->parent = self;
10645 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10647 /* special-case the first child */
10648 if (self->priv->n_children == 0)
10650 self->priv->first_child = child;
10651 self->priv->last_child = child;
10653 child->priv->next_sibling = NULL;
10654 child->priv->prev_sibling = NULL;
10659 /* Find the right place to insert the child so that it will still be
10660 sorted and the child will be after all of the actors at the same
10662 for (iter = self->priv->first_child;
10664 iter = iter->priv->next_sibling)
10669 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10671 if (iter_depth > child_depth)
10677 ClutterActor *tmp = iter->priv->prev_sibling;
10680 tmp->priv->next_sibling = child;
10682 /* Insert the node before the found one */
10683 child->priv->prev_sibling = iter->priv->prev_sibling;
10684 child->priv->next_sibling = iter;
10685 iter->priv->prev_sibling = child;
10689 ClutterActor *tmp = self->priv->last_child;
10692 tmp->priv->next_sibling = child;
10694 /* insert the node at the end of the list */
10695 child->priv->prev_sibling = self->priv->last_child;
10696 child->priv->next_sibling = NULL;
10699 if (child->priv->prev_sibling == NULL)
10700 self->priv->first_child = child;
10702 if (child->priv->next_sibling == NULL)
10703 self->priv->last_child = child;
10707 insert_child_at_index (ClutterActor *self,
10708 ClutterActor *child,
10711 gint index_ = GPOINTER_TO_INT (data_);
10713 child->priv->parent = self;
10717 ClutterActor *tmp = self->priv->first_child;
10720 tmp->priv->prev_sibling = child;
10722 child->priv->prev_sibling = NULL;
10723 child->priv->next_sibling = tmp;
10725 else if (index_ < 0 || index_ >= self->priv->n_children)
10727 ClutterActor *tmp = self->priv->last_child;
10730 tmp->priv->next_sibling = child;
10732 child->priv->prev_sibling = tmp;
10733 child->priv->next_sibling = NULL;
10737 ClutterActor *iter;
10740 for (iter = self->priv->first_child, i = 0;
10742 iter = iter->priv->next_sibling, i += 1)
10746 ClutterActor *tmp = iter->priv->prev_sibling;
10748 child->priv->prev_sibling = tmp;
10749 child->priv->next_sibling = iter;
10751 iter->priv->prev_sibling = child;
10754 tmp->priv->next_sibling = child;
10761 if (child->priv->prev_sibling == NULL)
10762 self->priv->first_child = child;
10764 if (child->priv->next_sibling == NULL)
10765 self->priv->last_child = child;
10769 insert_child_above (ClutterActor *self,
10770 ClutterActor *child,
10773 ClutterActor *sibling = data;
10775 child->priv->parent = self;
10777 if (sibling == NULL)
10778 sibling = self->priv->last_child;
10780 child->priv->prev_sibling = sibling;
10782 if (sibling != NULL)
10784 ClutterActor *tmp = sibling->priv->next_sibling;
10786 child->priv->next_sibling = tmp;
10789 tmp->priv->prev_sibling = child;
10791 sibling->priv->next_sibling = child;
10794 child->priv->next_sibling = NULL;
10796 if (child->priv->prev_sibling == NULL)
10797 self->priv->first_child = child;
10799 if (child->priv->next_sibling == NULL)
10800 self->priv->last_child = child;
10804 insert_child_below (ClutterActor *self,
10805 ClutterActor *child,
10808 ClutterActor *sibling = data;
10810 child->priv->parent = self;
10812 if (sibling == NULL)
10813 sibling = self->priv->first_child;
10815 child->priv->next_sibling = sibling;
10817 if (sibling != NULL)
10819 ClutterActor *tmp = sibling->priv->prev_sibling;
10821 child->priv->prev_sibling = tmp;
10824 tmp->priv->next_sibling = child;
10826 sibling->priv->prev_sibling = child;
10829 child->priv->prev_sibling = NULL;
10831 if (child->priv->prev_sibling == NULL)
10832 self->priv->first_child = child;
10834 if (child->priv->next_sibling == NULL)
10835 self->priv->last_child = child;
10838 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10839 ClutterActor *child,
10843 ADD_CHILD_CREATE_META = 1 << 0,
10844 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10845 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10846 ADD_CHILD_CHECK_STATE = 1 << 3,
10847 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10849 /* default flags for public API */
10850 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10851 ADD_CHILD_EMIT_PARENT_SET |
10852 ADD_CHILD_EMIT_ACTOR_ADDED |
10853 ADD_CHILD_CHECK_STATE |
10854 ADD_CHILD_NOTIFY_FIRST_LAST,
10856 /* flags for legacy/deprecated API */
10857 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10858 ADD_CHILD_CHECK_STATE |
10859 ADD_CHILD_NOTIFY_FIRST_LAST
10860 } ClutterActorAddChildFlags;
10863 * clutter_actor_add_child_internal:
10864 * @self: a #ClutterActor
10865 * @child: a #ClutterActor
10866 * @flags: control flags for actions
10867 * @add_func: delegate function
10868 * @data: (closure): data to pass to @add_func
10870 * Adds @child to the list of children of @self.
10872 * The actual insertion inside the list is delegated to @add_func: this
10873 * function will just set up the state, perform basic checks, and emit
10876 * The @flags argument is used to perform additional operations.
10879 clutter_actor_add_child_internal (ClutterActor *self,
10880 ClutterActor *child,
10881 ClutterActorAddChildFlags flags,
10882 ClutterActorAddChildFunc add_func,
10885 ClutterTextDirection text_dir;
10886 gboolean create_meta;
10887 gboolean emit_parent_set, emit_actor_added;
10888 gboolean check_state;
10889 gboolean notify_first_last;
10890 ClutterActor *old_first_child, *old_last_child;
10892 if (child->priv->parent != NULL)
10894 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10895 "use clutter_actor_remove_child() first.",
10896 _clutter_actor_get_debug_name (child),
10897 _clutter_actor_get_debug_name (child->priv->parent));
10901 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10903 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10904 "a child of another actor.",
10905 _clutter_actor_get_debug_name (child));
10910 /* XXX - this check disallows calling methods that change the stacking
10911 * order within the destruction sequence, by triggering a critical
10912 * warning first, and leaving the actor in an undefined state, which
10913 * then ends up being caught by an assertion.
10915 * the reproducible sequence is:
10917 * - actor gets destroyed;
10918 * - another actor, linked to the first, will try to change the
10919 * stacking order of the first actor;
10920 * - changing the stacking order is a composite operation composed
10921 * by the following steps:
10922 * 1. ref() the child;
10923 * 2. remove_child_internal(), which removes the reference;
10924 * 3. add_child_internal(), which adds a reference;
10925 * - the state of the actor is not changed between (2) and (3), as
10926 * it could be an expensive recomputation;
10927 * - if (3) bails out, then the actor is in an undefined state, but
10929 * - the destruction sequence terminates, but the actor is unparented
10930 * while its state indicates being parented instead.
10931 * - assertion failure.
10933 * the obvious fix would be to decompose each set_child_*_sibling()
10934 * method into proper remove_child()/add_child(), with state validation;
10935 * this may cause excessive work, though, and trigger a cascade of other
10936 * bugs in code that assumes that a change in the stacking order is an
10937 * atomic operation.
10939 * another potential fix is to just remove this check here, and let
10940 * code doing stacking order changes inside the destruction sequence
10941 * of an actor continue doing the work.
10943 * the third fix is to silently bail out early from every
10944 * set_child_*_sibling() and set_child_at_index() method, and avoid
10947 * I have a preference for the second solution, since it involves the
10948 * least amount of work, and the least amount of code duplication.
10950 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10952 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10954 g_warning ("The actor '%s' is currently being destroyed, and "
10955 "cannot be added as a child of another actor.",
10956 _clutter_actor_get_debug_name (child));
10961 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10962 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10963 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10964 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10965 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10967 old_first_child = self->priv->first_child;
10968 old_last_child = self->priv->last_child;
10970 g_object_freeze_notify (G_OBJECT (self));
10973 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10975 g_object_ref_sink (child);
10976 child->priv->parent = NULL;
10977 child->priv->next_sibling = NULL;
10978 child->priv->prev_sibling = NULL;
10980 /* delegate the actual insertion */
10981 add_func (self, child, data);
10983 g_assert (child->priv->parent == self);
10985 self->priv->n_children += 1;
10987 self->priv->age += 1;
10989 /* if push_internal() has been called then we automatically set
10990 * the flag on the actor
10992 if (self->priv->internal_child)
10993 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10995 /* clutter_actor_reparent() will emit ::parent-set for us */
10996 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10997 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11001 /* If parent is mapped or realized, we need to also be mapped or
11002 * realized once we're inside the parent.
11004 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11006 /* propagate the parent's text direction to the child */
11007 text_dir = clutter_actor_get_text_direction (self);
11008 clutter_actor_set_text_direction (child, text_dir);
11011 if (child->priv->show_on_set_parent)
11012 clutter_actor_show (child);
11014 if (CLUTTER_ACTOR_IS_MAPPED (child))
11015 clutter_actor_queue_redraw (child);
11017 /* maintain the invariant that if an actor needs layout,
11018 * its parents do as well
11020 if (child->priv->needs_width_request ||
11021 child->priv->needs_height_request ||
11022 child->priv->needs_allocation)
11024 /* we work around the short-circuiting we do
11025 * in clutter_actor_queue_relayout() since we
11026 * want to force a relayout
11028 child->priv->needs_width_request = TRUE;
11029 child->priv->needs_height_request = TRUE;
11030 child->priv->needs_allocation = TRUE;
11032 clutter_actor_queue_relayout (child->priv->parent);
11035 if (emit_actor_added)
11036 g_signal_emit_by_name (self, "actor-added", child);
11038 if (notify_first_last)
11040 if (old_first_child != self->priv->first_child)
11041 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11043 if (old_last_child != self->priv->last_child)
11044 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11047 g_object_thaw_notify (G_OBJECT (self));
11051 * clutter_actor_add_child:
11052 * @self: a #ClutterActor
11053 * @child: a #ClutterActor
11055 * Adds @child to the children of @self.
11057 * This function will acquire a reference on @child that will only
11058 * be released when calling clutter_actor_remove_child().
11060 * This function will take into consideration the #ClutterActor:depth
11061 * of @child, and will keep the list of children sorted.
11063 * This function will emit the #ClutterContainer::actor-added signal
11069 clutter_actor_add_child (ClutterActor *self,
11070 ClutterActor *child)
11072 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11073 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11074 g_return_if_fail (self != child);
11075 g_return_if_fail (child->priv->parent == NULL);
11077 clutter_actor_add_child_internal (self, child,
11078 ADD_CHILD_DEFAULT_FLAGS,
11079 insert_child_at_depth,
11084 * clutter_actor_insert_child_at_index:
11085 * @self: a #ClutterActor
11086 * @child: a #ClutterActor
11087 * @index_: the index
11089 * Inserts @child into the list of children of @self, using the
11090 * given @index_. If @index_ is greater than the number of children
11091 * in @self, or is less than 0, then the new child is added at the end.
11093 * This function will acquire a reference on @child that will only
11094 * be released when calling clutter_actor_remove_child().
11096 * This function will not take into consideration the #ClutterActor:depth
11099 * This function will emit the #ClutterContainer::actor-added signal
11105 clutter_actor_insert_child_at_index (ClutterActor *self,
11106 ClutterActor *child,
11109 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11110 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11111 g_return_if_fail (self != child);
11112 g_return_if_fail (child->priv->parent == NULL);
11114 clutter_actor_add_child_internal (self, child,
11115 ADD_CHILD_DEFAULT_FLAGS,
11116 insert_child_at_index,
11117 GINT_TO_POINTER (index_));
11121 * clutter_actor_insert_child_above:
11122 * @self: a #ClutterActor
11123 * @child: a #ClutterActor
11124 * @sibling: (allow-none): a child of @self, or %NULL
11126 * Inserts @child into the list of children of @self, above another
11127 * child of @self or, if @sibling is %NULL, above all the children
11130 * This function will acquire a reference on @child that will only
11131 * be released when calling clutter_actor_remove_child().
11133 * This function will not take into consideration the #ClutterActor:depth
11136 * This function will emit the #ClutterContainer::actor-added signal
11142 clutter_actor_insert_child_above (ClutterActor *self,
11143 ClutterActor *child,
11144 ClutterActor *sibling)
11146 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11147 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11148 g_return_if_fail (self != child);
11149 g_return_if_fail (child != sibling);
11150 g_return_if_fail (child->priv->parent == NULL);
11151 g_return_if_fail (sibling == NULL ||
11152 (CLUTTER_IS_ACTOR (sibling) &&
11153 sibling->priv->parent == self));
11155 clutter_actor_add_child_internal (self, child,
11156 ADD_CHILD_DEFAULT_FLAGS,
11157 insert_child_above,
11162 * clutter_actor_insert_child_below:
11163 * @self: a #ClutterActor
11164 * @child: a #ClutterActor
11165 * @sibling: (allow-none): a child of @self, or %NULL
11167 * Inserts @child into the list of children of @self, below another
11168 * child of @self or, if @sibling is %NULL, below all the children
11171 * This function will acquire a reference on @child that will only
11172 * be released when calling clutter_actor_remove_child().
11174 * This function will not take into consideration the #ClutterActor:depth
11177 * This function will emit the #ClutterContainer::actor-added signal
11183 clutter_actor_insert_child_below (ClutterActor *self,
11184 ClutterActor *child,
11185 ClutterActor *sibling)
11187 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11188 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11189 g_return_if_fail (self != child);
11190 g_return_if_fail (child != sibling);
11191 g_return_if_fail (child->priv->parent == NULL);
11192 g_return_if_fail (sibling == NULL ||
11193 (CLUTTER_IS_ACTOR (sibling) &&
11194 sibling->priv->parent == self));
11196 clutter_actor_add_child_internal (self, child,
11197 ADD_CHILD_DEFAULT_FLAGS,
11198 insert_child_below,
11203 * clutter_actor_set_parent:
11204 * @self: A #ClutterActor
11205 * @parent: A new #ClutterActor parent
11207 * Sets the parent of @self to @parent.
11209 * This function will result in @parent acquiring a reference on @self,
11210 * eventually by sinking its floating reference first. The reference
11211 * will be released by clutter_actor_unparent().
11213 * This function should only be called by legacy #ClutterActor<!-- -->s
11214 * implementing the #ClutterContainer interface.
11216 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11219 clutter_actor_set_parent (ClutterActor *self,
11220 ClutterActor *parent)
11222 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11223 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11224 g_return_if_fail (self != parent);
11225 g_return_if_fail (self->priv->parent == NULL);
11227 /* as this function will be called inside ClutterContainer::add
11228 * implementations or when building up a composite actor, we have
11229 * to preserve the old behaviour, and not create child meta or
11230 * emit the ::actor-added signal, to avoid recursion or double
11233 clutter_actor_add_child_internal (parent, self,
11234 ADD_CHILD_LEGACY_FLAGS,
11235 insert_child_at_depth,
11240 * clutter_actor_get_parent:
11241 * @self: A #ClutterActor
11243 * Retrieves the parent of @self.
11245 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11246 * if no parent is set
11249 clutter_actor_get_parent (ClutterActor *self)
11251 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11253 return self->priv->parent;
11257 * clutter_actor_get_paint_visibility:
11258 * @self: A #ClutterActor
11260 * Retrieves the 'paint' visibility of an actor recursively checking for non
11263 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11265 * Return Value: %TRUE if the actor is visibile and will be painted.
11270 clutter_actor_get_paint_visibility (ClutterActor *actor)
11272 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11274 return CLUTTER_ACTOR_IS_MAPPED (actor);
11278 * clutter_actor_remove_child:
11279 * @self: a #ClutterActor
11280 * @child: a #ClutterActor
11282 * Removes @child from the children of @self.
11284 * This function will release the reference added by
11285 * clutter_actor_add_child(), so if you want to keep using @child
11286 * you will have to acquire a referenced on it before calling this
11289 * This function will emit the #ClutterContainer::actor-removed
11295 clutter_actor_remove_child (ClutterActor *self,
11296 ClutterActor *child)
11298 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11299 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11300 g_return_if_fail (self != child);
11301 g_return_if_fail (child->priv->parent != NULL);
11302 g_return_if_fail (child->priv->parent == self);
11304 clutter_actor_remove_child_internal (self, child,
11305 REMOVE_CHILD_DEFAULT_FLAGS);
11309 * clutter_actor_remove_all_children:
11310 * @self: a #ClutterActor
11312 * Removes all children of @self.
11314 * This function releases the reference added by inserting a child actor
11315 * in the list of children of @self.
11317 * If the reference count of a child drops to zero, the child will be
11318 * destroyed. If you want to ensure the destruction of all the children
11319 * of @self, use clutter_actor_destroy_all_children().
11324 clutter_actor_remove_all_children (ClutterActor *self)
11326 ClutterActorIter iter;
11328 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11330 if (self->priv->n_children == 0)
11333 g_object_freeze_notify (G_OBJECT (self));
11335 clutter_actor_iter_init (&iter, self);
11336 while (clutter_actor_iter_next (&iter, NULL))
11337 clutter_actor_iter_remove (&iter);
11339 g_object_thaw_notify (G_OBJECT (self));
11342 g_assert (self->priv->first_child == NULL);
11343 g_assert (self->priv->last_child == NULL);
11344 g_assert (self->priv->n_children == 0);
11348 * clutter_actor_destroy_all_children:
11349 * @self: a #ClutterActor
11351 * Destroys all children of @self.
11353 * This function releases the reference added by inserting a child
11354 * actor in the list of children of @self, and ensures that the
11355 * #ClutterActor::destroy signal is emitted on each child of the
11358 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11359 * when its reference count drops to 0; the default handler of the
11360 * #ClutterActor::destroy signal will destroy all the children of an
11361 * actor. This function ensures that all children are destroyed, instead
11362 * of just removed from @self, unlike clutter_actor_remove_all_children()
11363 * which will merely release the reference and remove each child.
11365 * Unless you acquired an additional reference on each child of @self
11366 * prior to calling clutter_actor_remove_all_children() and want to reuse
11367 * the actors, you should use clutter_actor_destroy_all_children() in
11368 * order to make sure that children are destroyed and signal handlers
11369 * are disconnected even in cases where circular references prevent this
11370 * from automatically happening through reference counting alone.
11375 clutter_actor_destroy_all_children (ClutterActor *self)
11377 ClutterActorIter iter;
11379 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11381 if (self->priv->n_children == 0)
11384 g_object_freeze_notify (G_OBJECT (self));
11386 clutter_actor_iter_init (&iter, self);
11387 while (clutter_actor_iter_next (&iter, NULL))
11388 clutter_actor_iter_destroy (&iter);
11390 g_object_thaw_notify (G_OBJECT (self));
11393 g_assert (self->priv->first_child == NULL);
11394 g_assert (self->priv->last_child == NULL);
11395 g_assert (self->priv->n_children == 0);
11398 typedef struct _InsertBetweenData {
11399 ClutterActor *prev_sibling;
11400 ClutterActor *next_sibling;
11401 } InsertBetweenData;
11404 insert_child_between (ClutterActor *self,
11405 ClutterActor *child,
11408 InsertBetweenData *data = data_;
11409 ClutterActor *prev_sibling = data->prev_sibling;
11410 ClutterActor *next_sibling = data->next_sibling;
11412 child->priv->parent = self;
11413 child->priv->prev_sibling = prev_sibling;
11414 child->priv->next_sibling = next_sibling;
11416 if (prev_sibling != NULL)
11417 prev_sibling->priv->next_sibling = child;
11419 if (next_sibling != NULL)
11420 next_sibling->priv->prev_sibling = child;
11422 if (child->priv->prev_sibling == NULL)
11423 self->priv->first_child = child;
11425 if (child->priv->next_sibling == NULL)
11426 self->priv->last_child = child;
11430 * clutter_actor_replace_child:
11431 * @self: a #ClutterActor
11432 * @old_child: the child of @self to replace
11433 * @new_child: the #ClutterActor to replace @old_child
11435 * Replaces @old_child with @new_child in the list of children of @self.
11440 clutter_actor_replace_child (ClutterActor *self,
11441 ClutterActor *old_child,
11442 ClutterActor *new_child)
11444 ClutterActor *prev_sibling, *next_sibling;
11445 InsertBetweenData clos;
11447 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11448 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11449 g_return_if_fail (old_child->priv->parent == self);
11450 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11451 g_return_if_fail (old_child != new_child);
11452 g_return_if_fail (new_child != self);
11453 g_return_if_fail (new_child->priv->parent == NULL);
11455 prev_sibling = old_child->priv->prev_sibling;
11456 next_sibling = old_child->priv->next_sibling;
11457 clutter_actor_remove_child_internal (self, old_child,
11458 REMOVE_CHILD_DEFAULT_FLAGS);
11460 clos.prev_sibling = prev_sibling;
11461 clos.next_sibling = next_sibling;
11462 clutter_actor_add_child_internal (self, new_child,
11463 ADD_CHILD_DEFAULT_FLAGS,
11464 insert_child_between,
11469 * clutter_actor_unparent:
11470 * @self: a #ClutterActor
11472 * Removes the parent of @self.
11474 * This will cause the parent of @self to release the reference
11475 * acquired when calling clutter_actor_set_parent(), so if you
11476 * want to keep @self you will have to acquire a reference of
11477 * your own, through g_object_ref().
11479 * This function should only be called by legacy #ClutterActor<!-- -->s
11480 * implementing the #ClutterContainer interface.
11484 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11487 clutter_actor_unparent (ClutterActor *self)
11489 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11491 if (self->priv->parent == NULL)
11494 clutter_actor_remove_child_internal (self->priv->parent, self,
11495 REMOVE_CHILD_LEGACY_FLAGS);
11499 * clutter_actor_reparent:
11500 * @self: a #ClutterActor
11501 * @new_parent: the new #ClutterActor parent
11503 * Resets the parent actor of @self.
11505 * This function is logically equivalent to calling clutter_actor_unparent()
11506 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11507 * ensures the child is not finalized when unparented, and emits the
11508 * #ClutterActor::parent-set signal only once.
11510 * In reality, calling this function is less useful than it sounds, as some
11511 * application code may rely on changes in the intermediate state between
11512 * removal and addition of the actor from its old parent to the @new_parent.
11513 * Thus, it is strongly encouraged to avoid using this function in application
11518 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11519 * clutter_actor_add_child() instead; remember to take a reference on
11520 * the actor being removed before calling clutter_actor_remove_child()
11521 * to avoid the reference count dropping to zero and the actor being
11525 clutter_actor_reparent (ClutterActor *self,
11526 ClutterActor *new_parent)
11528 ClutterActorPrivate *priv;
11530 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11531 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11532 g_return_if_fail (self != new_parent);
11534 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11536 g_warning ("Cannot set a parent on a toplevel actor");
11540 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11542 g_warning ("Cannot set a parent currently being destroyed");
11548 if (priv->parent != new_parent)
11550 ClutterActor *old_parent;
11552 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11554 old_parent = priv->parent;
11556 g_object_ref (self);
11558 if (old_parent != NULL)
11560 /* go through the Container implementation if this is a regular
11561 * child and not an internal one
11563 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11565 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11567 /* this will have to call unparent() */
11568 clutter_container_remove_actor (parent, self);
11571 clutter_actor_remove_child_internal (old_parent, self,
11572 REMOVE_CHILD_LEGACY_FLAGS);
11575 /* Note, will call set_parent() */
11576 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11577 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11579 clutter_actor_add_child_internal (new_parent, self,
11580 ADD_CHILD_LEGACY_FLAGS,
11581 insert_child_at_depth,
11584 /* we emit the ::parent-set signal once */
11585 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11587 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11589 /* the IN_REPARENT flag suspends state updates */
11590 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11592 g_object_unref (self);
11597 * clutter_actor_contains:
11598 * @self: A #ClutterActor
11599 * @descendant: A #ClutterActor, possibly contained in @self
11601 * Determines if @descendant is contained inside @self (either as an
11602 * immediate child, or as a deeper descendant). If @self and
11603 * @descendant point to the same actor then it will also return %TRUE.
11605 * Return value: whether @descendent is contained within @self
11610 clutter_actor_contains (ClutterActor *self,
11611 ClutterActor *descendant)
11613 ClutterActor *actor;
11615 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11616 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11618 for (actor = descendant; actor; actor = actor->priv->parent)
11626 * clutter_actor_set_child_above_sibling:
11627 * @self: a #ClutterActor
11628 * @child: a #ClutterActor child of @self
11629 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11631 * Sets @child to be above @sibling in the list of children of @self.
11633 * If @sibling is %NULL, @child will be the new last child of @self.
11635 * This function is logically equivalent to removing @child and using
11636 * clutter_actor_insert_child_above(), but it will not emit signals
11637 * or change state on @child.
11642 clutter_actor_set_child_above_sibling (ClutterActor *self,
11643 ClutterActor *child,
11644 ClutterActor *sibling)
11646 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11647 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11648 g_return_if_fail (child->priv->parent == self);
11649 g_return_if_fail (child != sibling);
11650 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11652 if (sibling != NULL)
11653 g_return_if_fail (sibling->priv->parent == self);
11655 /* we don't want to change the state of child, or emit signals, or
11656 * regenerate ChildMeta instances here, but we still want to follow
11657 * the correct sequence of steps encoded in remove_child() and
11658 * add_child(), so that correctness is ensured, and we only go
11659 * through one known code path.
11661 g_object_ref (child);
11662 clutter_actor_remove_child_internal (self, child, 0);
11663 clutter_actor_add_child_internal (self, child,
11664 ADD_CHILD_NOTIFY_FIRST_LAST,
11665 insert_child_above,
11668 clutter_actor_queue_relayout (self);
11672 * clutter_actor_set_child_below_sibling:
11673 * @self: a #ClutterActor
11674 * @child: a #ClutterActor child of @self
11675 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11677 * Sets @child to be below @sibling in the list of children of @self.
11679 * If @sibling is %NULL, @child will be the new first child of @self.
11681 * This function is logically equivalent to removing @self and using
11682 * clutter_actor_insert_child_below(), but it will not emit signals
11683 * or change state on @child.
11688 clutter_actor_set_child_below_sibling (ClutterActor *self,
11689 ClutterActor *child,
11690 ClutterActor *sibling)
11692 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11693 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11694 g_return_if_fail (child->priv->parent == self);
11695 g_return_if_fail (child != sibling);
11696 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11698 if (sibling != NULL)
11699 g_return_if_fail (sibling->priv->parent == self);
11701 /* see the comment in set_child_above_sibling() */
11702 g_object_ref (child);
11703 clutter_actor_remove_child_internal (self, child, 0);
11704 clutter_actor_add_child_internal (self, child,
11705 ADD_CHILD_NOTIFY_FIRST_LAST,
11706 insert_child_below,
11709 clutter_actor_queue_relayout (self);
11713 * clutter_actor_set_child_at_index:
11714 * @self: a #ClutterActor
11715 * @child: a #ClutterActor child of @self
11716 * @index_: the new index for @child
11718 * Changes the index of @child in the list of children of @self.
11720 * This function is logically equivalent to removing @child and
11721 * calling clutter_actor_insert_child_at_index(), but it will not
11722 * emit signals or change state on @child.
11727 clutter_actor_set_child_at_index (ClutterActor *self,
11728 ClutterActor *child,
11731 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11732 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11733 g_return_if_fail (child->priv->parent == self);
11734 g_return_if_fail (index_ <= self->priv->n_children);
11736 g_object_ref (child);
11737 clutter_actor_remove_child_internal (self, child, 0);
11738 clutter_actor_add_child_internal (self, child,
11739 ADD_CHILD_NOTIFY_FIRST_LAST,
11740 insert_child_at_index,
11741 GINT_TO_POINTER (index_));
11743 clutter_actor_queue_relayout (self);
11747 * clutter_actor_raise:
11748 * @self: A #ClutterActor
11749 * @below: (allow-none): A #ClutterActor to raise above.
11751 * Puts @self above @below.
11753 * Both actors must have the same parent, and the parent must implement
11754 * the #ClutterContainer interface
11756 * This function calls clutter_container_raise_child() internally.
11758 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11761 clutter_actor_raise (ClutterActor *self,
11762 ClutterActor *below)
11764 ClutterActor *parent;
11766 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11768 parent = clutter_actor_get_parent (self);
11769 if (parent == NULL)
11771 g_warning ("%s: Actor '%s' is not inside a container",
11773 _clutter_actor_get_debug_name (self));
11779 if (parent != clutter_actor_get_parent (below))
11781 g_warning ("%s Actor '%s' is not in the same container as "
11784 _clutter_actor_get_debug_name (self),
11785 _clutter_actor_get_debug_name (below));
11790 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11794 * clutter_actor_lower:
11795 * @self: A #ClutterActor
11796 * @above: (allow-none): A #ClutterActor to lower below
11798 * Puts @self below @above.
11800 * Both actors must have the same parent, and the parent must implement
11801 * the #ClutterContainer interface.
11803 * This function calls clutter_container_lower_child() internally.
11805 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11808 clutter_actor_lower (ClutterActor *self,
11809 ClutterActor *above)
11811 ClutterActor *parent;
11813 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11815 parent = clutter_actor_get_parent (self);
11816 if (parent == NULL)
11818 g_warning ("%s: Actor of type %s is not inside a container",
11820 _clutter_actor_get_debug_name (self));
11826 if (parent != clutter_actor_get_parent (above))
11828 g_warning ("%s: Actor '%s' is not in the same container as "
11831 _clutter_actor_get_debug_name (self),
11832 _clutter_actor_get_debug_name (above));
11837 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11841 * clutter_actor_raise_top:
11842 * @self: A #ClutterActor
11844 * Raises @self to the top.
11846 * This function calls clutter_actor_raise() internally.
11848 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11849 * a %NULL sibling, instead.
11852 clutter_actor_raise_top (ClutterActor *self)
11854 clutter_actor_raise (self, NULL);
11858 * clutter_actor_lower_bottom:
11859 * @self: A #ClutterActor
11861 * Lowers @self to the bottom.
11863 * This function calls clutter_actor_lower() internally.
11865 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11866 * a %NULL sibling, instead.
11869 clutter_actor_lower_bottom (ClutterActor *self)
11871 clutter_actor_lower (self, NULL);
11879 * clutter_actor_event:
11880 * @actor: a #ClutterActor
11881 * @event: a #ClutterEvent
11882 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11884 * This function is used to emit an event on the main stage.
11885 * You should rarely need to use this function, except for
11886 * synthetising events.
11888 * Return value: the return value from the signal emission: %TRUE
11889 * if the actor handled the event, or %FALSE if the event was
11895 clutter_actor_event (ClutterActor *actor,
11896 ClutterEvent *event,
11899 gboolean retval = FALSE;
11900 gint signal_num = -1;
11902 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11903 g_return_val_if_fail (event != NULL, FALSE);
11905 g_object_ref (actor);
11909 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11915 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11919 switch (event->type)
11921 case CLUTTER_NOTHING:
11923 case CLUTTER_BUTTON_PRESS:
11924 signal_num = BUTTON_PRESS_EVENT;
11926 case CLUTTER_BUTTON_RELEASE:
11927 signal_num = BUTTON_RELEASE_EVENT;
11929 case CLUTTER_SCROLL:
11930 signal_num = SCROLL_EVENT;
11932 case CLUTTER_KEY_PRESS:
11933 signal_num = KEY_PRESS_EVENT;
11935 case CLUTTER_KEY_RELEASE:
11936 signal_num = KEY_RELEASE_EVENT;
11938 case CLUTTER_MOTION:
11939 signal_num = MOTION_EVENT;
11941 case CLUTTER_ENTER:
11942 signal_num = ENTER_EVENT;
11944 case CLUTTER_LEAVE:
11945 signal_num = LEAVE_EVENT;
11947 case CLUTTER_DELETE:
11948 case CLUTTER_DESTROY_NOTIFY:
11949 case CLUTTER_CLIENT_MESSAGE:
11955 if (signal_num != -1)
11956 g_signal_emit (actor, actor_signals[signal_num], 0,
11961 g_object_unref (actor);
11967 * clutter_actor_set_reactive:
11968 * @actor: a #ClutterActor
11969 * @reactive: whether the actor should be reactive to events
11971 * Sets @actor as reactive. Reactive actors will receive events.
11976 clutter_actor_set_reactive (ClutterActor *actor,
11979 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11981 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11985 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11987 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11989 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11993 * clutter_actor_get_reactive:
11994 * @actor: a #ClutterActor
11996 * Checks whether @actor is marked as reactive.
11998 * Return value: %TRUE if the actor is reactive
12003 clutter_actor_get_reactive (ClutterActor *actor)
12005 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12007 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12011 * clutter_actor_get_anchor_point:
12012 * @self: a #ClutterActor
12013 * @anchor_x: (out): return location for the X coordinate of the anchor point
12014 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12016 * Gets the current anchor point of the @actor in pixels.
12021 clutter_actor_get_anchor_point (ClutterActor *self,
12025 const ClutterTransformInfo *info;
12027 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12029 info = _clutter_actor_get_transform_info_or_defaults (self);
12030 clutter_anchor_coord_get_units (self, &info->anchor,
12037 * clutter_actor_set_anchor_point:
12038 * @self: a #ClutterActor
12039 * @anchor_x: X coordinate of the anchor point
12040 * @anchor_y: Y coordinate of the anchor point
12042 * Sets an anchor point for @self. The anchor point is a point in the
12043 * coordinate space of an actor to which the actor position within its
12044 * parent is relative; the default is (0, 0), i.e. the top-left corner
12050 clutter_actor_set_anchor_point (ClutterActor *self,
12054 ClutterTransformInfo *info;
12055 ClutterActorPrivate *priv;
12056 gboolean changed = FALSE;
12057 gfloat old_anchor_x, old_anchor_y;
12060 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12062 obj = G_OBJECT (self);
12064 info = _clutter_actor_get_transform_info (self);
12066 g_object_freeze_notify (obj);
12068 clutter_anchor_coord_get_units (self, &info->anchor,
12073 if (info->anchor.is_fractional)
12074 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12076 if (old_anchor_x != anchor_x)
12078 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12082 if (old_anchor_y != anchor_y)
12084 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12088 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12092 priv->transform_valid = FALSE;
12093 clutter_actor_queue_redraw (self);
12096 g_object_thaw_notify (obj);
12100 * clutter_actor_get_anchor_point_gravity:
12101 * @self: a #ClutterActor
12103 * Retrieves the anchor position expressed as a #ClutterGravity. If
12104 * the anchor point was specified using pixels or units this will
12105 * return %CLUTTER_GRAVITY_NONE.
12107 * Return value: the #ClutterGravity used by the anchor point
12112 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12114 const ClutterTransformInfo *info;
12116 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12118 info = _clutter_actor_get_transform_info_or_defaults (self);
12120 return clutter_anchor_coord_get_gravity (&info->anchor);
12124 * clutter_actor_move_anchor_point:
12125 * @self: a #ClutterActor
12126 * @anchor_x: X coordinate of the anchor point
12127 * @anchor_y: Y coordinate of the anchor point
12129 * Sets an anchor point for the actor, and adjusts the actor postion so that
12130 * the relative position of the actor toward its parent remains the same.
12135 clutter_actor_move_anchor_point (ClutterActor *self,
12139 gfloat old_anchor_x, old_anchor_y;
12140 const ClutterTransformInfo *info;
12142 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12144 info = _clutter_actor_get_transform_info (self);
12145 clutter_anchor_coord_get_units (self, &info->anchor,
12150 g_object_freeze_notify (G_OBJECT (self));
12152 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12154 if (self->priv->position_set)
12155 clutter_actor_move_by (self,
12156 anchor_x - old_anchor_x,
12157 anchor_y - old_anchor_y);
12159 g_object_thaw_notify (G_OBJECT (self));
12163 * clutter_actor_move_anchor_point_from_gravity:
12164 * @self: a #ClutterActor
12165 * @gravity: #ClutterGravity.
12167 * Sets an anchor point on the actor based on the given gravity, adjusting the
12168 * actor postion so that its relative position within its parent remains
12171 * Since version 1.0 the anchor point will be stored as a gravity so
12172 * that if the actor changes size then the anchor point will move. For
12173 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12174 * and later double the size of the actor, the anchor point will move
12175 * to the bottom right.
12180 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12181 ClutterGravity gravity)
12183 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12184 const ClutterTransformInfo *info;
12185 ClutterActorPrivate *priv;
12187 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12190 info = _clutter_actor_get_transform_info (self);
12192 g_object_freeze_notify (G_OBJECT (self));
12194 clutter_anchor_coord_get_units (self, &info->anchor,
12198 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12199 clutter_anchor_coord_get_units (self, &info->anchor,
12204 if (priv->position_set)
12205 clutter_actor_move_by (self,
12206 new_anchor_x - old_anchor_x,
12207 new_anchor_y - old_anchor_y);
12209 g_object_thaw_notify (G_OBJECT (self));
12213 * clutter_actor_set_anchor_point_from_gravity:
12214 * @self: a #ClutterActor
12215 * @gravity: #ClutterGravity.
12217 * Sets an anchor point on the actor, based on the given gravity (this is a
12218 * convenience function wrapping clutter_actor_set_anchor_point()).
12220 * Since version 1.0 the anchor point will be stored as a gravity so
12221 * that if the actor changes size then the anchor point will move. For
12222 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12223 * and later double the size of the actor, the anchor point will move
12224 * to the bottom right.
12229 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12230 ClutterGravity gravity)
12232 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12234 if (gravity == CLUTTER_GRAVITY_NONE)
12235 clutter_actor_set_anchor_point (self, 0, 0);
12238 GObject *obj = G_OBJECT (self);
12239 ClutterTransformInfo *info;
12241 g_object_freeze_notify (obj);
12243 info = _clutter_actor_get_transform_info (self);
12244 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12246 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12247 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12248 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12250 self->priv->transform_valid = FALSE;
12252 clutter_actor_queue_redraw (self);
12254 g_object_thaw_notify (obj);
12259 clutter_container_iface_init (ClutterContainerIface *iface)
12261 /* we don't override anything, as ClutterContainer already has a default
12262 * implementation that we can use, and which calls into our own API.
12277 parse_units (ClutterActor *self,
12278 ParseDimension dimension,
12281 GValue value = { 0, };
12284 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12287 json_node_get_value (node, &value);
12289 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12291 retval = (gfloat) g_value_get_int64 (&value);
12293 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12295 retval = g_value_get_double (&value);
12297 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12299 ClutterUnits units;
12302 res = clutter_units_from_string (&units, g_value_get_string (&value));
12304 retval = clutter_units_to_pixels (&units);
12307 g_warning ("Invalid value '%s': integers, strings or floating point "
12308 "values can be used for the x, y, width and height "
12309 "properties. Valid modifiers for strings are 'px', 'mm', "
12311 g_value_get_string (&value));
12317 g_warning ("Invalid value of type '%s': integers, strings of floating "
12318 "point values can be used for the x, y, width, height "
12319 "anchor-x and anchor-y properties.",
12320 g_type_name (G_VALUE_TYPE (&value)));
12323 g_value_unset (&value);
12329 ClutterRotateAxis axis;
12338 static inline gboolean
12339 parse_rotation_array (ClutterActor *actor,
12341 RotationInfo *info)
12345 if (json_array_get_length (array) != 2)
12349 element = json_array_get_element (array, 0);
12350 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12351 info->angle = json_node_get_double (element);
12356 element = json_array_get_element (array, 1);
12357 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12359 JsonArray *center = json_node_get_array (element);
12361 if (json_array_get_length (center) != 2)
12364 switch (info->axis)
12366 case CLUTTER_X_AXIS:
12367 info->center_y = parse_units (actor, PARSE_Y,
12368 json_array_get_element (center, 0));
12369 info->center_z = parse_units (actor, PARSE_Y,
12370 json_array_get_element (center, 1));
12373 case CLUTTER_Y_AXIS:
12374 info->center_x = parse_units (actor, PARSE_X,
12375 json_array_get_element (center, 0));
12376 info->center_z = parse_units (actor, PARSE_X,
12377 json_array_get_element (center, 1));
12380 case CLUTTER_Z_AXIS:
12381 info->center_x = parse_units (actor, PARSE_X,
12382 json_array_get_element (center, 0));
12383 info->center_y = parse_units (actor, PARSE_Y,
12384 json_array_get_element (center, 1));
12393 parse_rotation (ClutterActor *actor,
12395 RotationInfo *info)
12399 gboolean retval = FALSE;
12401 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12403 g_warning ("Invalid node of type '%s' found, expecting an array",
12404 json_node_type_name (node));
12408 array = json_node_get_array (node);
12409 len = json_array_get_length (array);
12411 for (i = 0; i < len; i++)
12413 JsonNode *element = json_array_get_element (array, i);
12414 JsonObject *object;
12417 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12419 g_warning ("Invalid node of type '%s' found, expecting an object",
12420 json_node_type_name (element));
12424 object = json_node_get_object (element);
12426 if (json_object_has_member (object, "x-axis"))
12428 member = json_object_get_member (object, "x-axis");
12430 info->axis = CLUTTER_X_AXIS;
12432 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12434 info->angle = json_node_get_double (member);
12437 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12438 retval = parse_rotation_array (actor,
12439 json_node_get_array (member),
12444 else if (json_object_has_member (object, "y-axis"))
12446 member = json_object_get_member (object, "y-axis");
12448 info->axis = CLUTTER_Y_AXIS;
12450 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12452 info->angle = json_node_get_double (member);
12455 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12456 retval = parse_rotation_array (actor,
12457 json_node_get_array (member),
12462 else if (json_object_has_member (object, "z-axis"))
12464 member = json_object_get_member (object, "z-axis");
12466 info->axis = CLUTTER_Z_AXIS;
12468 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12470 info->angle = json_node_get_double (member);
12473 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12474 retval = parse_rotation_array (actor,
12475 json_node_get_array (member),
12486 parse_actor_metas (ClutterScript *script,
12487 ClutterActor *actor,
12490 GList *elements, *l;
12491 GSList *retval = NULL;
12493 if (!JSON_NODE_HOLDS_ARRAY (node))
12496 elements = json_array_get_elements (json_node_get_array (node));
12498 for (l = elements; l != NULL; l = l->next)
12500 JsonNode *element = l->data;
12501 const gchar *id_ = _clutter_script_get_id_from_node (element);
12504 if (id_ == NULL || *id_ == '\0')
12507 meta = clutter_script_get_object (script, id_);
12511 retval = g_slist_prepend (retval, meta);
12514 g_list_free (elements);
12516 return g_slist_reverse (retval);
12520 parse_behaviours (ClutterScript *script,
12521 ClutterActor *actor,
12524 GList *elements, *l;
12525 GSList *retval = NULL;
12527 if (!JSON_NODE_HOLDS_ARRAY (node))
12530 elements = json_array_get_elements (json_node_get_array (node));
12532 for (l = elements; l != NULL; l = l->next)
12534 JsonNode *element = l->data;
12535 const gchar *id_ = _clutter_script_get_id_from_node (element);
12536 GObject *behaviour;
12538 if (id_ == NULL || *id_ == '\0')
12541 behaviour = clutter_script_get_object (script, id_);
12542 if (behaviour == NULL)
12545 retval = g_slist_prepend (retval, behaviour);
12548 g_list_free (elements);
12550 return g_slist_reverse (retval);
12554 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12555 ClutterScript *script,
12560 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12561 gboolean retval = FALSE;
12563 if ((name[0] == 'x' && name[1] == '\0') ||
12564 (name[0] == 'y' && name[1] == '\0') ||
12565 (strcmp (name, "width") == 0) ||
12566 (strcmp (name, "height") == 0) ||
12567 (strcmp (name, "anchor_x") == 0) ||
12568 (strcmp (name, "anchor_y") == 0))
12570 ParseDimension dimension;
12573 if (name[0] == 'x')
12574 dimension = PARSE_X;
12575 else if (name[0] == 'y')
12576 dimension = PARSE_Y;
12577 else if (name[0] == 'w')
12578 dimension = PARSE_WIDTH;
12579 else if (name[0] == 'h')
12580 dimension = PARSE_HEIGHT;
12581 else if (name[0] == 'a' && name[7] == 'x')
12582 dimension = PARSE_ANCHOR_X;
12583 else if (name[0] == 'a' && name[7] == 'y')
12584 dimension = PARSE_ANCHOR_Y;
12588 units = parse_units (actor, dimension, node);
12590 /* convert back to pixels: all properties are pixel-based */
12591 g_value_init (value, G_TYPE_FLOAT);
12592 g_value_set_float (value, units);
12596 else if (strcmp (name, "rotation") == 0)
12598 RotationInfo *info;
12600 info = g_slice_new0 (RotationInfo);
12601 retval = parse_rotation (actor, node, info);
12605 g_value_init (value, G_TYPE_POINTER);
12606 g_value_set_pointer (value, info);
12609 g_slice_free (RotationInfo, info);
12611 else if (strcmp (name, "behaviours") == 0)
12615 #ifdef CLUTTER_ENABLE_DEBUG
12616 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12617 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12618 "and it should not be used in newly "
12619 "written ClutterScript definitions.");
12622 l = parse_behaviours (script, actor, node);
12624 g_value_init (value, G_TYPE_POINTER);
12625 g_value_set_pointer (value, l);
12629 else if (strcmp (name, "actions") == 0 ||
12630 strcmp (name, "constraints") == 0 ||
12631 strcmp (name, "effects") == 0)
12635 l = parse_actor_metas (script, actor, node);
12637 g_value_init (value, G_TYPE_POINTER);
12638 g_value_set_pointer (value, l);
12647 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12648 ClutterScript *script,
12650 const GValue *value)
12652 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12654 #ifdef CLUTTER_ENABLE_DEBUG
12655 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12657 gchar *tmp = g_strdup_value_contents (value);
12659 CLUTTER_NOTE (SCRIPT,
12660 "in ClutterActor::set_custom_property('%s') = %s",
12666 #endif /* CLUTTER_ENABLE_DEBUG */
12668 if (strcmp (name, "rotation") == 0)
12670 RotationInfo *info;
12672 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12675 info = g_value_get_pointer (value);
12677 clutter_actor_set_rotation (actor,
12678 info->axis, info->angle,
12683 g_slice_free (RotationInfo, info);
12688 if (strcmp (name, "behaviours") == 0)
12690 GSList *behaviours, *l;
12692 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12695 behaviours = g_value_get_pointer (value);
12696 for (l = behaviours; l != NULL; l = l->next)
12698 ClutterBehaviour *behaviour = l->data;
12700 clutter_behaviour_apply (behaviour, actor);
12703 g_slist_free (behaviours);
12708 if (strcmp (name, "actions") == 0 ||
12709 strcmp (name, "constraints") == 0 ||
12710 strcmp (name, "effects") == 0)
12714 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12717 metas = g_value_get_pointer (value);
12718 for (l = metas; l != NULL; l = l->next)
12720 if (name[0] == 'a')
12721 clutter_actor_add_action (actor, l->data);
12723 if (name[0] == 'c')
12724 clutter_actor_add_constraint (actor, l->data);
12726 if (name[0] == 'e')
12727 clutter_actor_add_effect (actor, l->data);
12730 g_slist_free (metas);
12735 g_object_set_property (G_OBJECT (scriptable), name, value);
12739 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12741 iface->parse_custom_node = clutter_actor_parse_custom_node;
12742 iface->set_custom_property = clutter_actor_set_custom_property;
12745 static ClutterActorMeta *
12746 get_meta_from_animation_property (ClutterActor *actor,
12750 ClutterActorPrivate *priv = actor->priv;
12751 ClutterActorMeta *meta = NULL;
12754 /* if this is not a special property, fall through */
12755 if (name[0] != '@')
12758 /* detect the properties named using the following spec:
12760 * @<section>.<meta-name>.<property-name>
12762 * where <section> can be one of the following:
12768 * and <meta-name> is the name set on a specific ActorMeta
12771 tokens = g_strsplit (name + 1, ".", -1);
12772 if (tokens == NULL || g_strv_length (tokens) != 3)
12774 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12776 g_strfreev (tokens);
12780 if (strcmp (tokens[0], "actions") == 0)
12781 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12783 if (strcmp (tokens[0], "constraints") == 0)
12784 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12786 if (strcmp (tokens[0], "effects") == 0)
12787 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12789 if (name_p != NULL)
12790 *name_p = g_strdup (tokens[2]);
12792 CLUTTER_NOTE (ANIMATION,
12793 "Looking for property '%s' of object '%s' in section '%s'",
12798 g_strfreev (tokens);
12803 static GParamSpec *
12804 clutter_actor_find_property (ClutterAnimatable *animatable,
12805 const gchar *property_name)
12807 ClutterActorMeta *meta = NULL;
12808 GObjectClass *klass = NULL;
12809 GParamSpec *pspec = NULL;
12810 gchar *p_name = NULL;
12812 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12818 klass = G_OBJECT_GET_CLASS (meta);
12820 pspec = g_object_class_find_property (klass, p_name);
12824 klass = G_OBJECT_GET_CLASS (animatable);
12826 pspec = g_object_class_find_property (klass, property_name);
12835 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12836 const gchar *property_name,
12839 ClutterActorMeta *meta = NULL;
12840 gchar *p_name = NULL;
12842 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12847 g_object_get_property (G_OBJECT (meta), p_name, initial);
12849 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12855 * clutter_actor_set_animatable_property:
12856 * @actor: a #ClutterActor
12857 * @prop_id: the paramspec id
12858 * @value: the value to set
12859 * @pspec: the paramspec
12861 * Sets values of animatable properties.
12863 * This is a variant of clutter_actor_set_property() that gets called
12864 * by the #ClutterAnimatable implementation of #ClutterActor for the
12865 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12868 * Unlike the implementation of #GObjectClass.set_property(), this
12869 * function will not update the interval if a transition involving an
12870 * animatable property is in progress - this avoids cycles with the
12871 * transition API calling the public API.
12874 clutter_actor_set_animatable_property (ClutterActor *actor,
12876 const GValue *value,
12882 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12886 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12890 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12894 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12898 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12902 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12905 case PROP_BACKGROUND_COLOR:
12906 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12910 clutter_actor_set_scale_factor_internal (actor,
12911 g_value_get_double (value),
12916 clutter_actor_set_scale_factor_internal (actor,
12917 g_value_get_double (value),
12921 case PROP_ROTATION_ANGLE_X:
12922 clutter_actor_set_rotation_angle_internal (actor,
12924 g_value_get_double (value));
12927 case PROP_ROTATION_ANGLE_Y:
12928 clutter_actor_set_rotation_angle_internal (actor,
12930 g_value_get_double (value));
12933 case PROP_ROTATION_ANGLE_Z:
12934 clutter_actor_set_rotation_angle_internal (actor,
12936 g_value_get_double (value));
12940 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12946 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12947 const gchar *property_name,
12948 const GValue *final)
12950 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12951 ClutterActorMeta *meta = NULL;
12952 gchar *p_name = NULL;
12954 meta = get_meta_from_animation_property (actor,
12958 g_object_set_property (G_OBJECT (meta), p_name, final);
12961 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12964 pspec = g_object_class_find_property (obj_class, property_name);
12966 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12968 /* XXX - I'm going to the special hell for this */
12969 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12972 g_object_set_property (G_OBJECT (animatable), property_name, final);
12979 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12981 iface->find_property = clutter_actor_find_property;
12982 iface->get_initial_state = clutter_actor_get_initial_state;
12983 iface->set_final_state = clutter_actor_set_final_state;
12987 * clutter_actor_transform_stage_point:
12988 * @self: A #ClutterActor
12989 * @x: (in): x screen coordinate of the point to unproject
12990 * @y: (in): y screen coordinate of the point to unproject
12991 * @x_out: (out): return location for the unprojected x coordinance
12992 * @y_out: (out): return location for the unprojected y coordinance
12994 * This function translates screen coordinates (@x, @y) to
12995 * coordinates relative to the actor. For example, it can be used to translate
12996 * screen events from global screen coordinates into actor-local coordinates.
12998 * The conversion can fail, notably if the transform stack results in the
12999 * actor being projected on the screen as a mere line.
13001 * The conversion should not be expected to be pixel-perfect due to the
13002 * nature of the operation. In general the error grows when the skewing
13003 * of the actor rectangle on screen increases.
13005 * <note><para>This function can be computationally intensive.</para></note>
13007 * <note><para>This function only works when the allocation is up-to-date,
13008 * i.e. inside of paint().</para></note>
13010 * Return value: %TRUE if conversion was successful.
13015 clutter_actor_transform_stage_point (ClutterActor *self,
13021 ClutterVertex v[4];
13024 int du, dv, xi, yi;
13026 float xf, yf, wf, det;
13027 ClutterActorPrivate *priv;
13029 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13033 /* This implementation is based on the quad -> quad projection algorithm
13034 * described by Paul Heckbert in:
13036 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13038 * and the sample implementation at:
13040 * http://www.cs.cmu.edu/~ph/src/texfund/
13042 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13043 * quad to rectangle only, which significantly simplifies things; the
13044 * function calls have been unrolled, and most of the math is done in fixed
13048 clutter_actor_get_abs_allocation_vertices (self, v);
13050 /* Keeping these as ints simplifies the multiplication (no significant
13051 * loss of precision here).
13053 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13054 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13059 #define UX2FP(x) (x)
13060 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13062 /* First, find mapping from unit uv square to xy quadrilateral; this
13063 * equivalent to the pmap_square_quad() functions in the sample
13064 * implementation, which we can simplify, since our target is always
13067 px = v[0].x - v[1].x + v[3].x - v[2].x;
13068 py = v[0].y - v[1].y + v[3].y - v[2].y;
13072 /* affine transform */
13073 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13074 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13075 RQ[2][0] = UX2FP (v[0].x);
13076 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13077 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13078 RQ[2][1] = UX2FP (v[0].y);
13085 /* projective transform */
13086 double dx1, dx2, dy1, dy2, del;
13088 dx1 = UX2FP (v[1].x - v[3].x);
13089 dx2 = UX2FP (v[2].x - v[3].x);
13090 dy1 = UX2FP (v[1].y - v[3].y);
13091 dy2 = UX2FP (v[2].y - v[3].y);
13093 del = DET2FP (dx1, dx2, dy1, dy2);
13098 * The division here needs to be done in floating point for
13099 * precisions reasons.
13101 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13102 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13103 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13105 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13106 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13107 RQ[2][0] = UX2FP (v[0].x);
13108 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13109 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13110 RQ[2][1] = UX2FP (v[0].y);
13114 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13115 * square. Since our rectangle is based at 0,0 we only need to scale.
13125 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13128 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13129 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13130 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13131 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13132 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13133 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13134 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13135 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13136 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13139 * Check the resulting matrix is OK.
13141 det = (RQ[0][0] * ST[0][0])
13142 + (RQ[0][1] * ST[0][1])
13143 + (RQ[0][2] * ST[0][2]);
13148 * Now transform our point with the ST matrix; the notional w
13149 * coordinate is 1, hence the last part is simply added.
13154 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13155 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13156 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13174 static ClutterGeometry*
13175 clutter_geometry_copy (const ClutterGeometry *geometry)
13177 return g_slice_dup (ClutterGeometry, geometry);
13181 clutter_geometry_free (ClutterGeometry *geometry)
13183 if (G_LIKELY (geometry != NULL))
13184 g_slice_free (ClutterGeometry, geometry);
13188 * clutter_geometry_union:
13189 * @geometry_a: a #ClutterGeometry
13190 * @geometry_b: another #ClutterGeometry
13191 * @result: (out): location to store the result
13193 * Find the union of two rectangles represented as #ClutterGeometry.
13198 clutter_geometry_union (const ClutterGeometry *geometry_a,
13199 const ClutterGeometry *geometry_b,
13200 ClutterGeometry *result)
13202 /* We don't try to handle rectangles that can't be represented
13203 * as a signed integer box */
13204 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13205 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13206 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13207 geometry_b->x + (gint)geometry_b->width);
13208 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13209 geometry_b->y + (gint)geometry_b->height);
13212 result->width = x_2 - x_1;
13213 result->height = y_2 - y_1;
13217 * clutter_geometry_intersects:
13218 * @geometry0: The first geometry to test
13219 * @geometry1: The second geometry to test
13221 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13222 * they do else %FALSE.
13224 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13230 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13231 const ClutterGeometry *geometry1)
13233 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13234 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13235 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13236 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13243 clutter_geometry_progress (const GValue *a,
13248 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13249 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13250 ClutterGeometry res = { 0, };
13251 gint a_width = a_geom->width;
13252 gint b_width = b_geom->width;
13253 gint a_height = a_geom->height;
13254 gint b_height = b_geom->height;
13256 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13257 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13259 res.width = a_width + (b_width - a_width) * progress;
13260 res.height = a_height + (b_height - a_height) * progress;
13262 g_value_set_boxed (retval, &res);
13267 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13268 clutter_geometry_copy,
13269 clutter_geometry_free,
13270 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13277 * clutter_vertex_new:
13282 * Creates a new #ClutterVertex for the point in 3D space
13283 * identified by the 3 coordinates @x, @y, @z
13285 * Return value: the newly allocate #ClutterVertex. Use
13286 * clutter_vertex_free() to free the resources
13291 clutter_vertex_new (gfloat x,
13295 ClutterVertex *vertex;
13297 vertex = g_slice_new (ClutterVertex);
13306 * clutter_vertex_copy:
13307 * @vertex: a #ClutterVertex
13311 * Return value: a newly allocated copy of #ClutterVertex. Use
13312 * clutter_vertex_free() to free the allocated resources
13317 clutter_vertex_copy (const ClutterVertex *vertex)
13319 if (G_LIKELY (vertex != NULL))
13320 return g_slice_dup (ClutterVertex, vertex);
13326 * clutter_vertex_free:
13327 * @vertex: a #ClutterVertex
13329 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13334 clutter_vertex_free (ClutterVertex *vertex)
13336 if (G_UNLIKELY (vertex != NULL))
13337 g_slice_free (ClutterVertex, vertex);
13341 * clutter_vertex_equal:
13342 * @vertex_a: a #ClutterVertex
13343 * @vertex_b: a #ClutterVertex
13345 * Compares @vertex_a and @vertex_b for equality
13347 * Return value: %TRUE if the passed #ClutterVertex are equal
13352 clutter_vertex_equal (const ClutterVertex *vertex_a,
13353 const ClutterVertex *vertex_b)
13355 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13357 if (vertex_a == vertex_b)
13360 return vertex_a->x == vertex_b->x &&
13361 vertex_a->y == vertex_b->y &&
13362 vertex_a->z == vertex_b->z;
13366 clutter_vertex_progress (const GValue *a,
13371 const ClutterVertex *av = g_value_get_boxed (a);
13372 const ClutterVertex *bv = g_value_get_boxed (b);
13373 ClutterVertex res = { 0, };
13375 res.x = av->x + (bv->x - av->x) * progress;
13376 res.y = av->y + (bv->y - av->y) * progress;
13377 res.z = av->z + (bv->z - av->z) * progress;
13379 g_value_set_boxed (retval, &res);
13384 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13385 clutter_vertex_copy,
13386 clutter_vertex_free,
13387 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13390 * clutter_actor_is_rotated:
13391 * @self: a #ClutterActor
13393 * Checks whether any rotation is applied to the actor.
13395 * Return value: %TRUE if the actor is rotated.
13400 clutter_actor_is_rotated (ClutterActor *self)
13402 const ClutterTransformInfo *info;
13404 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13406 info = _clutter_actor_get_transform_info_or_defaults (self);
13408 if (info->rx_angle || info->ry_angle || info->rz_angle)
13415 * clutter_actor_is_scaled:
13416 * @self: a #ClutterActor
13418 * Checks whether the actor is scaled in either dimension.
13420 * Return value: %TRUE if the actor is scaled.
13425 clutter_actor_is_scaled (ClutterActor *self)
13427 const ClutterTransformInfo *info;
13429 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13431 info = _clutter_actor_get_transform_info_or_defaults (self);
13433 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13440 _clutter_actor_get_stage_internal (ClutterActor *actor)
13442 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13443 actor = actor->priv->parent;
13449 * clutter_actor_get_stage:
13450 * @actor: a #ClutterActor
13452 * Retrieves the #ClutterStage where @actor is contained.
13454 * Return value: (transfer none) (type Clutter.Stage): the stage
13455 * containing the actor, or %NULL
13460 clutter_actor_get_stage (ClutterActor *actor)
13462 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13464 return _clutter_actor_get_stage_internal (actor);
13468 * clutter_actor_allocate_available_size:
13469 * @self: a #ClutterActor
13470 * @x: the actor's X coordinate
13471 * @y: the actor's Y coordinate
13472 * @available_width: the maximum available width, or -1 to use the
13473 * actor's natural width
13474 * @available_height: the maximum available height, or -1 to use the
13475 * actor's natural height
13476 * @flags: flags controlling the allocation
13478 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13479 * preferred size, but limiting it to the maximum available width
13480 * and height provided.
13482 * This function will do the right thing when dealing with the
13483 * actor's request mode.
13485 * The implementation of this function is equivalent to:
13488 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13490 * clutter_actor_get_preferred_width (self, available_height,
13492 * &natural_width);
13493 * width = CLAMP (natural_width, min_width, available_width);
13495 * clutter_actor_get_preferred_height (self, width,
13497 * &natural_height);
13498 * height = CLAMP (natural_height, min_height, available_height);
13502 * clutter_actor_get_preferred_height (self, available_width,
13504 * &natural_height);
13505 * height = CLAMP (natural_height, min_height, available_height);
13507 * clutter_actor_get_preferred_width (self, height,
13509 * &natural_width);
13510 * width = CLAMP (natural_width, min_width, available_width);
13513 * box.x1 = x; box.y1 = y;
13514 * box.x2 = box.x1 + available_width;
13515 * box.y2 = box.y1 + available_height;
13516 * clutter_actor_allocate (self, &box, flags);
13519 * This function can be used by fluid layout managers to allocate
13520 * an actor's preferred size without making it bigger than the area
13521 * available for the container.
13526 clutter_actor_allocate_available_size (ClutterActor *self,
13529 gfloat available_width,
13530 gfloat available_height,
13531 ClutterAllocationFlags flags)
13533 ClutterActorPrivate *priv;
13534 gfloat width, height;
13535 gfloat min_width, min_height;
13536 gfloat natural_width, natural_height;
13537 ClutterActorBox box;
13539 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13543 width = height = 0.0;
13545 switch (priv->request_mode)
13547 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13548 clutter_actor_get_preferred_width (self, available_height,
13551 width = CLAMP (natural_width, min_width, available_width);
13553 clutter_actor_get_preferred_height (self, width,
13556 height = CLAMP (natural_height, min_height, available_height);
13559 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13560 clutter_actor_get_preferred_height (self, available_width,
13563 height = CLAMP (natural_height, min_height, available_height);
13565 clutter_actor_get_preferred_width (self, height,
13568 width = CLAMP (natural_width, min_width, available_width);
13575 box.x2 = box.x1 + width;
13576 box.y2 = box.y1 + height;
13577 clutter_actor_allocate (self, &box, flags);
13581 * clutter_actor_allocate_preferred_size:
13582 * @self: a #ClutterActor
13583 * @flags: flags controlling the allocation
13585 * Allocates the natural size of @self.
13587 * This function is a utility call for #ClutterActor implementations
13588 * that allocates the actor's preferred natural size. It can be used
13589 * by fixed layout managers (like #ClutterGroup or so called
13590 * 'composite actors') inside the ClutterActor::allocate
13591 * implementation to give each child exactly how much space it
13594 * This function is not meant to be used by applications. It is also
13595 * not meant to be used outside the implementation of the
13596 * ClutterActor::allocate virtual function.
13601 clutter_actor_allocate_preferred_size (ClutterActor *self,
13602 ClutterAllocationFlags flags)
13604 gfloat actor_x, actor_y;
13605 gfloat natural_width, natural_height;
13606 ClutterActorBox actor_box;
13608 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13610 actor_x = clutter_actor_get_x (self);
13611 actor_y = clutter_actor_get_y (self);
13613 clutter_actor_get_preferred_size (self,
13618 actor_box.x1 = actor_x;
13619 actor_box.y1 = actor_y;
13620 actor_box.x2 = actor_box.x1 + natural_width;
13621 actor_box.y2 = actor_box.y1 + natural_height;
13623 clutter_actor_allocate (self, &actor_box, flags);
13627 * clutter_actor_allocate_align_fill:
13628 * @self: a #ClutterActor
13629 * @box: a #ClutterActorBox, containing the available width and height
13630 * @x_align: the horizontal alignment, between 0 and 1
13631 * @y_align: the vertical alignment, between 0 and 1
13632 * @x_fill: whether the actor should fill horizontally
13633 * @y_fill: whether the actor should fill vertically
13634 * @flags: allocation flags to be passed to clutter_actor_allocate()
13636 * Allocates @self by taking into consideration the available allocation
13637 * area; an alignment factor on either axis; and whether the actor should
13638 * fill the allocation on either axis.
13640 * The @box should contain the available allocation width and height;
13641 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13642 * allocation will be offset by their value.
13644 * This function takes into consideration the geometry request specified by
13645 * the #ClutterActor:request-mode property, and the text direction.
13647 * This function is useful for fluid layout managers, like #ClutterBinLayout
13648 * or #ClutterTableLayout
13653 clutter_actor_allocate_align_fill (ClutterActor *self,
13654 const ClutterActorBox *box,
13659 ClutterAllocationFlags flags)
13661 ClutterActorPrivate *priv;
13662 ClutterActorBox allocation = { 0, };
13663 gfloat x_offset, y_offset;
13664 gfloat available_width, available_height;
13665 gfloat child_width, child_height;
13667 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13668 g_return_if_fail (box != NULL);
13669 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13670 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13674 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13675 clutter_actor_box_get_size (box, &available_width, &available_height);
13677 if (available_width < 0)
13678 available_width = 0;
13680 if (available_height < 0)
13681 available_height = 0;
13685 allocation.x1 = x_offset;
13686 allocation.x2 = allocation.x1 + available_width;
13691 allocation.y1 = y_offset;
13692 allocation.y2 = allocation.y1 + available_height;
13695 /* if we are filling horizontally and vertically then we're done */
13696 if (x_fill && y_fill)
13699 child_width = child_height = 0.0f;
13701 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13703 gfloat min_width, natural_width;
13704 gfloat min_height, natural_height;
13706 clutter_actor_get_preferred_width (self, available_height,
13710 child_width = CLAMP (natural_width, min_width, available_width);
13714 clutter_actor_get_preferred_height (self, child_width,
13718 child_height = CLAMP (natural_height, min_height, available_height);
13723 gfloat min_width, natural_width;
13724 gfloat min_height, natural_height;
13726 clutter_actor_get_preferred_height (self, available_width,
13730 child_height = CLAMP (natural_height, min_height, available_height);
13734 clutter_actor_get_preferred_width (self, child_height,
13738 child_width = CLAMP (natural_width, min_width, available_width);
13742 /* invert the horizontal alignment for RTL languages */
13743 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13744 x_align = 1.0 - x_align;
13748 allocation.x1 = x_offset
13749 + ((available_width - child_width) * x_align);
13750 allocation.x2 = allocation.x1 + child_width;
13755 allocation.y1 = y_offset
13756 + ((available_height - child_height) * y_align);
13757 allocation.y2 = allocation.y1 + child_height;
13761 clutter_actor_box_clamp_to_pixel (&allocation);
13762 clutter_actor_allocate (self, &allocation, flags);
13766 * clutter_actor_grab_key_focus:
13767 * @self: a #ClutterActor
13769 * Sets the key focus of the #ClutterStage including @self
13770 * to this #ClutterActor.
13775 clutter_actor_grab_key_focus (ClutterActor *self)
13777 ClutterActor *stage;
13779 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13781 stage = _clutter_actor_get_stage_internal (self);
13783 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13787 * clutter_actor_get_pango_context:
13788 * @self: a #ClutterActor
13790 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13791 * is already configured using the appropriate font map, resolution
13792 * and font options.
13794 * Unlike clutter_actor_create_pango_context(), this context is owend
13795 * by the #ClutterActor and it will be updated each time the options
13796 * stored by the #ClutterBackend change.
13798 * You can use the returned #PangoContext to create a #PangoLayout
13799 * and render text using cogl_pango_render_layout() to reuse the
13800 * glyphs cache also used by Clutter.
13802 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13803 * The returned #PangoContext is owned by the actor and should not be
13804 * unreferenced by the application code
13809 clutter_actor_get_pango_context (ClutterActor *self)
13811 ClutterActorPrivate *priv;
13813 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13817 if (priv->pango_context != NULL)
13818 return priv->pango_context;
13820 priv->pango_context = _clutter_context_get_pango_context ();
13821 g_object_ref (priv->pango_context);
13823 return priv->pango_context;
13827 * clutter_actor_create_pango_context:
13828 * @self: a #ClutterActor
13830 * Creates a #PangoContext for the given actor. The #PangoContext
13831 * is already configured using the appropriate font map, resolution
13832 * and font options.
13834 * See also clutter_actor_get_pango_context().
13836 * Return value: (transfer full): the newly created #PangoContext.
13837 * Use g_object_unref() on the returned value to deallocate its
13843 clutter_actor_create_pango_context (ClutterActor *self)
13845 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13847 return _clutter_context_create_pango_context ();
13851 * clutter_actor_create_pango_layout:
13852 * @self: a #ClutterActor
13853 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13855 * Creates a new #PangoLayout from the same #PangoContext used
13856 * by the #ClutterActor. The #PangoLayout is already configured
13857 * with the font map, resolution and font options, and the
13860 * If you want to keep around a #PangoLayout created by this
13861 * function you will have to connect to the #ClutterBackend::font-changed
13862 * and #ClutterBackend::resolution-changed signals, and call
13863 * pango_layout_context_changed() in response to them.
13865 * Return value: (transfer full): the newly created #PangoLayout.
13866 * Use g_object_unref() when done
13871 clutter_actor_create_pango_layout (ClutterActor *self,
13874 PangoContext *context;
13875 PangoLayout *layout;
13877 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13879 context = clutter_actor_get_pango_context (self);
13880 layout = pango_layout_new (context);
13883 pango_layout_set_text (layout, text, -1);
13888 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13889 * ClutterOffscreenEffect.
13892 _clutter_actor_set_opacity_override (ClutterActor *self,
13895 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13897 self->priv->opacity_override = opacity;
13901 _clutter_actor_get_opacity_override (ClutterActor *self)
13903 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13905 return self->priv->opacity_override;
13908 /* Allows you to disable applying the actors model view transform during
13909 * a paint. Used by ClutterClone. */
13911 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13914 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13916 self->priv->enable_model_view_transform = enable;
13920 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13923 ClutterActorPrivate *priv;
13925 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13929 priv->enable_paint_unmapped = enable;
13931 if (priv->enable_paint_unmapped)
13933 /* Make sure that the parents of the widget are realized first;
13934 * otherwise checks in clutter_actor_update_map_state() will
13937 clutter_actor_realize (self);
13939 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13943 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13948 clutter_anchor_coord_get_units (ClutterActor *self,
13949 const AnchorCoord *coord,
13954 if (coord->is_fractional)
13956 gfloat actor_width, actor_height;
13958 clutter_actor_get_size (self, &actor_width, &actor_height);
13961 *x = actor_width * coord->v.fraction.x;
13964 *y = actor_height * coord->v.fraction.y;
13972 *x = coord->v.units.x;
13975 *y = coord->v.units.y;
13978 *z = coord->v.units.z;
13983 clutter_anchor_coord_set_units (AnchorCoord *coord,
13988 coord->is_fractional = FALSE;
13989 coord->v.units.x = x;
13990 coord->v.units.y = y;
13991 coord->v.units.z = z;
13994 static ClutterGravity
13995 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13997 if (coord->is_fractional)
13999 if (coord->v.fraction.x == 0.0)
14001 if (coord->v.fraction.y == 0.0)
14002 return CLUTTER_GRAVITY_NORTH_WEST;
14003 else if (coord->v.fraction.y == 0.5)
14004 return CLUTTER_GRAVITY_WEST;
14005 else if (coord->v.fraction.y == 1.0)
14006 return CLUTTER_GRAVITY_SOUTH_WEST;
14008 return CLUTTER_GRAVITY_NONE;
14010 else if (coord->v.fraction.x == 0.5)
14012 if (coord->v.fraction.y == 0.0)
14013 return CLUTTER_GRAVITY_NORTH;
14014 else if (coord->v.fraction.y == 0.5)
14015 return CLUTTER_GRAVITY_CENTER;
14016 else if (coord->v.fraction.y == 1.0)
14017 return CLUTTER_GRAVITY_SOUTH;
14019 return CLUTTER_GRAVITY_NONE;
14021 else if (coord->v.fraction.x == 1.0)
14023 if (coord->v.fraction.y == 0.0)
14024 return CLUTTER_GRAVITY_NORTH_EAST;
14025 else if (coord->v.fraction.y == 0.5)
14026 return CLUTTER_GRAVITY_EAST;
14027 else if (coord->v.fraction.y == 1.0)
14028 return CLUTTER_GRAVITY_SOUTH_EAST;
14030 return CLUTTER_GRAVITY_NONE;
14033 return CLUTTER_GRAVITY_NONE;
14036 return CLUTTER_GRAVITY_NONE;
14040 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14041 ClutterGravity gravity)
14045 case CLUTTER_GRAVITY_NORTH:
14046 coord->v.fraction.x = 0.5;
14047 coord->v.fraction.y = 0.0;
14050 case CLUTTER_GRAVITY_NORTH_EAST:
14051 coord->v.fraction.x = 1.0;
14052 coord->v.fraction.y = 0.0;
14055 case CLUTTER_GRAVITY_EAST:
14056 coord->v.fraction.x = 1.0;
14057 coord->v.fraction.y = 0.5;
14060 case CLUTTER_GRAVITY_SOUTH_EAST:
14061 coord->v.fraction.x = 1.0;
14062 coord->v.fraction.y = 1.0;
14065 case CLUTTER_GRAVITY_SOUTH:
14066 coord->v.fraction.x = 0.5;
14067 coord->v.fraction.y = 1.0;
14070 case CLUTTER_GRAVITY_SOUTH_WEST:
14071 coord->v.fraction.x = 0.0;
14072 coord->v.fraction.y = 1.0;
14075 case CLUTTER_GRAVITY_WEST:
14076 coord->v.fraction.x = 0.0;
14077 coord->v.fraction.y = 0.5;
14080 case CLUTTER_GRAVITY_NORTH_WEST:
14081 coord->v.fraction.x = 0.0;
14082 coord->v.fraction.y = 0.0;
14085 case CLUTTER_GRAVITY_CENTER:
14086 coord->v.fraction.x = 0.5;
14087 coord->v.fraction.y = 0.5;
14091 coord->v.fraction.x = 0.0;
14092 coord->v.fraction.y = 0.0;
14096 coord->is_fractional = TRUE;
14100 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14102 if (coord->is_fractional)
14103 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14105 return (coord->v.units.x == 0.0
14106 && coord->v.units.y == 0.0
14107 && coord->v.units.z == 0.0);
14111 * clutter_actor_get_flags:
14112 * @self: a #ClutterActor
14114 * Retrieves the flags set on @self
14116 * Return value: a bitwise or of #ClutterActorFlags or 0
14121 clutter_actor_get_flags (ClutterActor *self)
14123 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14125 return self->flags;
14129 * clutter_actor_set_flags:
14130 * @self: a #ClutterActor
14131 * @flags: the flags to set
14133 * Sets @flags on @self
14135 * This function will emit notifications for the changed properties
14140 clutter_actor_set_flags (ClutterActor *self,
14141 ClutterActorFlags flags)
14143 ClutterActorFlags old_flags;
14145 gboolean was_reactive_set, reactive_set;
14146 gboolean was_realized_set, realized_set;
14147 gboolean was_mapped_set, mapped_set;
14148 gboolean was_visible_set, visible_set;
14150 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14152 if (self->flags == flags)
14155 obj = G_OBJECT (self);
14156 g_object_ref (obj);
14157 g_object_freeze_notify (obj);
14159 old_flags = self->flags;
14161 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14162 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14163 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14164 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14166 self->flags |= flags;
14168 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14169 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14170 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14171 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14173 if (reactive_set != was_reactive_set)
14174 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14176 if (realized_set != was_realized_set)
14177 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14179 if (mapped_set != was_mapped_set)
14180 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14182 if (visible_set != was_visible_set)
14183 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14185 g_object_thaw_notify (obj);
14186 g_object_unref (obj);
14190 * clutter_actor_unset_flags:
14191 * @self: a #ClutterActor
14192 * @flags: the flags to unset
14194 * Unsets @flags on @self
14196 * This function will emit notifications for the changed properties
14201 clutter_actor_unset_flags (ClutterActor *self,
14202 ClutterActorFlags flags)
14204 ClutterActorFlags old_flags;
14206 gboolean was_reactive_set, reactive_set;
14207 gboolean was_realized_set, realized_set;
14208 gboolean was_mapped_set, mapped_set;
14209 gboolean was_visible_set, visible_set;
14211 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14213 obj = G_OBJECT (self);
14214 g_object_freeze_notify (obj);
14216 old_flags = self->flags;
14218 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14219 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14220 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14221 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14223 self->flags &= ~flags;
14225 if (self->flags == old_flags)
14228 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14229 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14230 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14231 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14233 if (reactive_set != was_reactive_set)
14234 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14236 if (realized_set != was_realized_set)
14237 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14239 if (mapped_set != was_mapped_set)
14240 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14242 if (visible_set != was_visible_set)
14243 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14245 g_object_thaw_notify (obj);
14249 * clutter_actor_get_transformation_matrix:
14250 * @self: a #ClutterActor
14251 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14253 * Retrieves the transformations applied to @self relative to its
14259 clutter_actor_get_transformation_matrix (ClutterActor *self,
14260 CoglMatrix *matrix)
14262 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14264 cogl_matrix_init_identity (matrix);
14266 _clutter_actor_apply_modelview_transform (self, matrix);
14270 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14271 gboolean is_in_clone_paint)
14273 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14274 self->priv->in_clone_paint = is_in_clone_paint;
14278 * clutter_actor_is_in_clone_paint:
14279 * @self: a #ClutterActor
14281 * Checks whether @self is being currently painted by a #ClutterClone
14283 * This function is useful only inside the ::paint virtual function
14284 * implementations or within handlers for the #ClutterActor::paint
14287 * This function should not be used by applications
14289 * Return value: %TRUE if the #ClutterActor is currently being painted
14290 * by a #ClutterClone, and %FALSE otherwise
14295 clutter_actor_is_in_clone_paint (ClutterActor *self)
14297 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14299 return self->priv->in_clone_paint;
14303 set_direction_recursive (ClutterActor *actor,
14304 gpointer user_data)
14306 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14308 clutter_actor_set_text_direction (actor, text_dir);
14314 * clutter_actor_set_text_direction:
14315 * @self: a #ClutterActor
14316 * @text_dir: the text direction for @self
14318 * Sets the #ClutterTextDirection for an actor
14320 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14322 * If @self implements #ClutterContainer then this function will recurse
14323 * inside all the children of @self (including the internal ones).
14325 * Composite actors not implementing #ClutterContainer, or actors requiring
14326 * special handling when the text direction changes, should connect to
14327 * the #GObject::notify signal for the #ClutterActor:text-direction property
14332 clutter_actor_set_text_direction (ClutterActor *self,
14333 ClutterTextDirection text_dir)
14335 ClutterActorPrivate *priv;
14337 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14338 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14342 if (priv->text_direction != text_dir)
14344 priv->text_direction = text_dir;
14346 /* we need to emit the notify::text-direction first, so that
14347 * the sub-classes can catch that and do specific handling of
14348 * the text direction; see clutter_text_direction_changed_cb()
14349 * inside clutter-text.c
14351 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14353 _clutter_actor_foreach_child (self, set_direction_recursive,
14354 GINT_TO_POINTER (text_dir));
14356 clutter_actor_queue_relayout (self);
14361 _clutter_actor_set_has_pointer (ClutterActor *self,
14362 gboolean has_pointer)
14364 ClutterActorPrivate *priv = self->priv;
14366 if (priv->has_pointer != has_pointer)
14368 priv->has_pointer = has_pointer;
14370 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14375 * clutter_actor_get_text_direction:
14376 * @self: a #ClutterActor
14378 * Retrieves the value set using clutter_actor_set_text_direction()
14380 * If no text direction has been previously set, the default text
14381 * direction, as returned by clutter_get_default_text_direction(), will
14382 * be returned instead
14384 * Return value: the #ClutterTextDirection for the actor
14388 ClutterTextDirection
14389 clutter_actor_get_text_direction (ClutterActor *self)
14391 ClutterActorPrivate *priv;
14393 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14394 CLUTTER_TEXT_DIRECTION_LTR);
14398 /* if no direction has been set yet use the default */
14399 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14400 priv->text_direction = clutter_get_default_text_direction ();
14402 return priv->text_direction;
14406 * clutter_actor_push_internal:
14407 * @self: a #ClutterActor
14409 * Should be used by actors implementing the #ClutterContainer and with
14410 * internal children added through clutter_actor_set_parent(), for instance:
14414 * my_actor_init (MyActor *self)
14416 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14418 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14420 * /* calling clutter_actor_set_parent() now will result in
14421 * * the internal flag being set on a child of MyActor
14424 * /* internal child - a background texture */
14425 * self->priv->background_tex = clutter_texture_new ();
14426 * clutter_actor_set_parent (self->priv->background_tex,
14427 * CLUTTER_ACTOR (self));
14429 * /* internal child - a label */
14430 * self->priv->label = clutter_text_new ();
14431 * clutter_actor_set_parent (self->priv->label,
14432 * CLUTTER_ACTOR (self));
14434 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14436 * /* calling clutter_actor_set_parent() now will not result in
14437 * * the internal flag being set on a child of MyActor
14442 * This function will be used by Clutter to toggle an "internal child"
14443 * flag whenever clutter_actor_set_parent() is called; internal children
14444 * are handled differently by Clutter, specifically when destroying their
14447 * Call clutter_actor_pop_internal() when you finished adding internal
14450 * Nested calls to clutter_actor_push_internal() are allowed, but each
14451 * one must by followed by a clutter_actor_pop_internal() call.
14455 * Deprecated: 1.10: All children of an actor are accessible through
14456 * the #ClutterActor API, and #ClutterActor implements the
14457 * #ClutterContainer interface, so this function is only useful
14458 * for legacy containers overriding the default implementation.
14461 clutter_actor_push_internal (ClutterActor *self)
14463 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14465 self->priv->internal_child += 1;
14469 * clutter_actor_pop_internal:
14470 * @self: a #ClutterActor
14472 * Disables the effects of clutter_actor_push_internal().
14476 * Deprecated: 1.10: All children of an actor are accessible through
14477 * the #ClutterActor API. This function is only useful for legacy
14478 * containers overriding the default implementation of the
14479 * #ClutterContainer interface.
14482 clutter_actor_pop_internal (ClutterActor *self)
14484 ClutterActorPrivate *priv;
14486 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14490 if (priv->internal_child == 0)
14492 g_warning ("Mismatched %s: you need to call "
14493 "clutter_actor_push_composite() at least once before "
14494 "calling this function", G_STRFUNC);
14498 priv->internal_child -= 1;
14502 * clutter_actor_has_pointer:
14503 * @self: a #ClutterActor
14505 * Checks whether an actor contains the pointer of a
14506 * #ClutterInputDevice
14508 * Return value: %TRUE if the actor contains the pointer, and
14514 clutter_actor_has_pointer (ClutterActor *self)
14516 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14518 return self->priv->has_pointer;
14521 /* XXX: This is a workaround for not being able to break the ABI of
14522 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14523 * clutter_actor_queue_clipped_redraw() for details.
14525 ClutterPaintVolume *
14526 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14528 return g_object_get_data (G_OBJECT (self),
14529 "-clutter-actor-queue-redraw-clip");
14533 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14534 ClutterPaintVolume *clip)
14536 g_object_set_data (G_OBJECT (self),
14537 "-clutter-actor-queue-redraw-clip",
14542 * clutter_actor_has_allocation:
14543 * @self: a #ClutterActor
14545 * Checks if the actor has an up-to-date allocation assigned to
14546 * it. This means that the actor should have an allocation: it's
14547 * visible and has a parent. It also means that there is no
14548 * outstanding relayout request in progress for the actor or its
14549 * children (There might be other outstanding layout requests in
14550 * progress that will cause the actor to get a new allocation
14551 * when the stage is laid out, however).
14553 * If this function returns %FALSE, then the actor will normally
14554 * be allocated before it is next drawn on the screen.
14556 * Return value: %TRUE if the actor has an up-to-date allocation
14561 clutter_actor_has_allocation (ClutterActor *self)
14563 ClutterActorPrivate *priv;
14565 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14569 return priv->parent != NULL &&
14570 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14571 !priv->needs_allocation;
14575 * clutter_actor_add_action:
14576 * @self: a #ClutterActor
14577 * @action: a #ClutterAction
14579 * Adds @action to the list of actions applied to @self
14581 * A #ClutterAction can only belong to one actor at a time
14583 * The #ClutterActor will hold a reference on @action until either
14584 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14590 clutter_actor_add_action (ClutterActor *self,
14591 ClutterAction *action)
14593 ClutterActorPrivate *priv;
14595 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14596 g_return_if_fail (CLUTTER_IS_ACTION (action));
14600 if (priv->actions == NULL)
14602 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14603 priv->actions->actor = self;
14606 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14608 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14612 * clutter_actor_add_action_with_name:
14613 * @self: a #ClutterActor
14614 * @name: the name to set on the action
14615 * @action: a #ClutterAction
14617 * A convenience function for setting the name of a #ClutterAction
14618 * while adding it to the list of actions applied to @self
14620 * This function is the logical equivalent of:
14623 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14624 * clutter_actor_add_action (self, action);
14630 clutter_actor_add_action_with_name (ClutterActor *self,
14632 ClutterAction *action)
14634 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14635 g_return_if_fail (name != NULL);
14636 g_return_if_fail (CLUTTER_IS_ACTION (action));
14638 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14639 clutter_actor_add_action (self, action);
14643 * clutter_actor_remove_action:
14644 * @self: a #ClutterActor
14645 * @action: a #ClutterAction
14647 * Removes @action from the list of actions applied to @self
14649 * The reference held by @self on the #ClutterAction will be released
14654 clutter_actor_remove_action (ClutterActor *self,
14655 ClutterAction *action)
14657 ClutterActorPrivate *priv;
14659 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14660 g_return_if_fail (CLUTTER_IS_ACTION (action));
14664 if (priv->actions == NULL)
14667 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14669 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14673 * clutter_actor_remove_action_by_name:
14674 * @self: a #ClutterActor
14675 * @name: the name of the action to remove
14677 * Removes the #ClutterAction with the given name from the list
14678 * of actions applied to @self
14683 clutter_actor_remove_action_by_name (ClutterActor *self,
14686 ClutterActorPrivate *priv;
14687 ClutterActorMeta *meta;
14689 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14690 g_return_if_fail (name != NULL);
14694 if (priv->actions == NULL)
14697 meta = _clutter_meta_group_get_meta (priv->actions, name);
14701 _clutter_meta_group_remove_meta (priv->actions, meta);
14703 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14707 * clutter_actor_get_actions:
14708 * @self: a #ClutterActor
14710 * Retrieves the list of actions applied to @self
14712 * Return value: (transfer container) (element-type Clutter.Action): a copy
14713 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14714 * owned by the #ClutterActor. Use g_list_free() to free the resources
14715 * allocated by the returned #GList
14720 clutter_actor_get_actions (ClutterActor *self)
14722 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14724 if (self->priv->actions == NULL)
14727 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14731 * clutter_actor_get_action:
14732 * @self: a #ClutterActor
14733 * @name: the name of the action to retrieve
14735 * Retrieves the #ClutterAction with the given name in the list
14736 * of actions applied to @self
14738 * Return value: (transfer none): a #ClutterAction for the given
14739 * name, or %NULL. The returned #ClutterAction is owned by the
14740 * actor and it should not be unreferenced directly
14745 clutter_actor_get_action (ClutterActor *self,
14748 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14749 g_return_val_if_fail (name != NULL, NULL);
14751 if (self->priv->actions == NULL)
14754 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14758 * clutter_actor_clear_actions:
14759 * @self: a #ClutterActor
14761 * Clears the list of actions applied to @self
14766 clutter_actor_clear_actions (ClutterActor *self)
14768 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14770 if (self->priv->actions == NULL)
14773 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14777 * clutter_actor_add_constraint:
14778 * @self: a #ClutterActor
14779 * @constraint: a #ClutterConstraint
14781 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14784 * The #ClutterActor will hold a reference on the @constraint until
14785 * either clutter_actor_remove_constraint() or
14786 * clutter_actor_clear_constraints() is called.
14791 clutter_actor_add_constraint (ClutterActor *self,
14792 ClutterConstraint *constraint)
14794 ClutterActorPrivate *priv;
14796 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14797 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14801 if (priv->constraints == NULL)
14803 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14804 priv->constraints->actor = self;
14807 _clutter_meta_group_add_meta (priv->constraints,
14808 CLUTTER_ACTOR_META (constraint));
14809 clutter_actor_queue_relayout (self);
14811 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14815 * clutter_actor_add_constraint_with_name:
14816 * @self: a #ClutterActor
14817 * @name: the name to set on the constraint
14818 * @constraint: a #ClutterConstraint
14820 * A convenience function for setting the name of a #ClutterConstraint
14821 * while adding it to the list of constraints applied to @self
14823 * This function is the logical equivalent of:
14826 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14827 * clutter_actor_add_constraint (self, constraint);
14833 clutter_actor_add_constraint_with_name (ClutterActor *self,
14835 ClutterConstraint *constraint)
14837 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14838 g_return_if_fail (name != NULL);
14839 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14841 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14842 clutter_actor_add_constraint (self, constraint);
14846 * clutter_actor_remove_constraint:
14847 * @self: a #ClutterActor
14848 * @constraint: a #ClutterConstraint
14850 * Removes @constraint from the list of constraints applied to @self
14852 * The reference held by @self on the #ClutterConstraint will be released
14857 clutter_actor_remove_constraint (ClutterActor *self,
14858 ClutterConstraint *constraint)
14860 ClutterActorPrivate *priv;
14862 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14863 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14867 if (priv->constraints == NULL)
14870 _clutter_meta_group_remove_meta (priv->constraints,
14871 CLUTTER_ACTOR_META (constraint));
14872 clutter_actor_queue_relayout (self);
14874 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14878 * clutter_actor_remove_constraint_by_name:
14879 * @self: a #ClutterActor
14880 * @name: the name of the constraint to remove
14882 * Removes the #ClutterConstraint with the given name from the list
14883 * of constraints applied to @self
14888 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14891 ClutterActorPrivate *priv;
14892 ClutterActorMeta *meta;
14894 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14895 g_return_if_fail (name != NULL);
14899 if (priv->constraints == NULL)
14902 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14906 _clutter_meta_group_remove_meta (priv->constraints, meta);
14907 clutter_actor_queue_relayout (self);
14911 * clutter_actor_get_constraints:
14912 * @self: a #ClutterActor
14914 * Retrieves the list of constraints applied to @self
14916 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14917 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14918 * owned by the #ClutterActor. Use g_list_free() to free the resources
14919 * allocated by the returned #GList
14924 clutter_actor_get_constraints (ClutterActor *self)
14926 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14928 if (self->priv->constraints == NULL)
14931 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14935 * clutter_actor_get_constraint:
14936 * @self: a #ClutterActor
14937 * @name: the name of the constraint to retrieve
14939 * Retrieves the #ClutterConstraint with the given name in the list
14940 * of constraints applied to @self
14942 * Return value: (transfer none): a #ClutterConstraint for the given
14943 * name, or %NULL. The returned #ClutterConstraint is owned by the
14944 * actor and it should not be unreferenced directly
14948 ClutterConstraint *
14949 clutter_actor_get_constraint (ClutterActor *self,
14952 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14953 g_return_val_if_fail (name != NULL, NULL);
14955 if (self->priv->constraints == NULL)
14958 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14962 * clutter_actor_clear_constraints:
14963 * @self: a #ClutterActor
14965 * Clears the list of constraints applied to @self
14970 clutter_actor_clear_constraints (ClutterActor *self)
14972 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14974 if (self->priv->constraints == NULL)
14977 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14979 clutter_actor_queue_relayout (self);
14983 * clutter_actor_set_clip_to_allocation:
14984 * @self: a #ClutterActor
14985 * @clip_set: %TRUE to apply a clip tracking the allocation
14987 * Sets whether @self should be clipped to the same size as its
14993 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14996 ClutterActorPrivate *priv;
14998 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15000 clip_set = !!clip_set;
15004 if (priv->clip_to_allocation != clip_set)
15006 priv->clip_to_allocation = clip_set;
15008 clutter_actor_queue_redraw (self);
15010 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15015 * clutter_actor_get_clip_to_allocation:
15016 * @self: a #ClutterActor
15018 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15020 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15025 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15027 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15029 return self->priv->clip_to_allocation;
15033 * clutter_actor_add_effect:
15034 * @self: a #ClutterActor
15035 * @effect: a #ClutterEffect
15037 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15039 * The #ClutterActor will hold a reference on the @effect until either
15040 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15046 clutter_actor_add_effect (ClutterActor *self,
15047 ClutterEffect *effect)
15049 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15050 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15052 _clutter_actor_add_effect_internal (self, effect);
15054 clutter_actor_queue_redraw (self);
15056 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15060 * clutter_actor_add_effect_with_name:
15061 * @self: a #ClutterActor
15062 * @name: the name to set on the effect
15063 * @effect: a #ClutterEffect
15065 * A convenience function for setting the name of a #ClutterEffect
15066 * while adding it to the list of effectss applied to @self
15068 * This function is the logical equivalent of:
15071 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15072 * clutter_actor_add_effect (self, effect);
15078 clutter_actor_add_effect_with_name (ClutterActor *self,
15080 ClutterEffect *effect)
15082 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15083 g_return_if_fail (name != NULL);
15084 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15086 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15087 clutter_actor_add_effect (self, effect);
15091 * clutter_actor_remove_effect:
15092 * @self: a #ClutterActor
15093 * @effect: a #ClutterEffect
15095 * Removes @effect from the list of effects applied to @self
15097 * The reference held by @self on the #ClutterEffect will be released
15102 clutter_actor_remove_effect (ClutterActor *self,
15103 ClutterEffect *effect)
15105 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15106 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15108 _clutter_actor_remove_effect_internal (self, effect);
15110 clutter_actor_queue_redraw (self);
15112 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15116 * clutter_actor_remove_effect_by_name:
15117 * @self: a #ClutterActor
15118 * @name: the name of the effect to remove
15120 * Removes the #ClutterEffect with the given name from the list
15121 * of effects applied to @self
15126 clutter_actor_remove_effect_by_name (ClutterActor *self,
15129 ClutterActorPrivate *priv;
15130 ClutterActorMeta *meta;
15132 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15133 g_return_if_fail (name != NULL);
15137 if (priv->effects == NULL)
15140 meta = _clutter_meta_group_get_meta (priv->effects, name);
15144 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15148 * clutter_actor_get_effects:
15149 * @self: a #ClutterActor
15151 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15153 * Return value: (transfer container) (element-type Clutter.Effect): a list
15154 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15155 * list are owned by Clutter and they should not be freed. You should
15156 * free the returned list using g_list_free() when done
15161 clutter_actor_get_effects (ClutterActor *self)
15163 ClutterActorPrivate *priv;
15165 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15169 if (priv->effects == NULL)
15172 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15176 * clutter_actor_get_effect:
15177 * @self: a #ClutterActor
15178 * @name: the name of the effect to retrieve
15180 * Retrieves the #ClutterEffect with the given name in the list
15181 * of effects applied to @self
15183 * Return value: (transfer none): a #ClutterEffect for the given
15184 * name, or %NULL. The returned #ClutterEffect is owned by the
15185 * actor and it should not be unreferenced directly
15190 clutter_actor_get_effect (ClutterActor *self,
15193 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15194 g_return_val_if_fail (name != NULL, NULL);
15196 if (self->priv->effects == NULL)
15199 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15203 * clutter_actor_clear_effects:
15204 * @self: a #ClutterActor
15206 * Clears the list of effects applied to @self
15211 clutter_actor_clear_effects (ClutterActor *self)
15213 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15215 if (self->priv->effects == NULL)
15218 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15220 clutter_actor_queue_redraw (self);
15224 * clutter_actor_has_key_focus:
15225 * @self: a #ClutterActor
15227 * Checks whether @self is the #ClutterActor that has key focus
15229 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15234 clutter_actor_has_key_focus (ClutterActor *self)
15236 ClutterActor *stage;
15238 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15240 stage = _clutter_actor_get_stage_internal (self);
15244 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15248 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15249 ClutterPaintVolume *pv)
15251 ClutterActorPrivate *priv = self->priv;
15253 /* Actors are only expected to report a valid paint volume
15254 * while they have a valid allocation. */
15255 if (G_UNLIKELY (priv->needs_allocation))
15257 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15258 "Actor needs allocation",
15259 _clutter_actor_get_debug_name (self));
15263 /* Check if there are any handlers connected to the paint
15264 * signal. If there are then all bets are off for what the paint
15265 * volume for this actor might possibly be!
15267 * XXX: It's expected that this is going to end up being quite a
15268 * costly check to have to do here, but we haven't come up with
15269 * another solution that can reliably catch paint signal handlers at
15270 * the right time to either avoid artefacts due to invalid stage
15271 * clipping or due to incorrect culling.
15273 * Previously we checked in clutter_actor_paint(), but at that time
15274 * we may already be using a stage clip that could be derived from
15275 * an invalid paint-volume. We used to try and handle that by
15276 * queuing a follow up, unclipped, redraw but still the previous
15277 * checking wasn't enough to catch invalid volumes involved in
15278 * culling (considering that containers may derive their volume from
15279 * children that haven't yet been painted)
15281 * Longer term, improved solutions could be:
15282 * - Disallow painting in the paint signal, only allow using it
15283 * for tracking when paints happen. We can add another API that
15284 * allows monkey patching the paint of arbitrary actors but in a
15285 * more controlled way and that also supports modifying the
15287 * - If we could be notified somehow when signal handlers are
15288 * connected we wouldn't have to poll for handlers like this.
15290 if (g_signal_has_handler_pending (self,
15291 actor_signals[PAINT],
15295 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15296 "Actor has \"paint\" signal handlers",
15297 _clutter_actor_get_debug_name (self));
15301 _clutter_paint_volume_init_static (pv, self);
15303 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15305 clutter_paint_volume_free (pv);
15306 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15307 "Actor failed to report a volume",
15308 _clutter_actor_get_debug_name (self));
15312 /* since effects can modify the paint volume, we allow them to actually
15313 * do this by making get_paint_volume() "context sensitive"
15315 if (priv->effects != NULL)
15317 if (priv->current_effect != NULL)
15319 const GList *effects, *l;
15321 /* if we are being called from within the paint sequence of
15322 * an actor, get the paint volume up to the current effect
15324 effects = _clutter_meta_group_peek_metas (priv->effects);
15326 l != NULL || (l != NULL && l->data != priv->current_effect);
15329 if (!_clutter_effect_get_paint_volume (l->data, pv))
15331 clutter_paint_volume_free (pv);
15332 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15333 "Effect (%s) failed to report a volume",
15334 _clutter_actor_get_debug_name (self),
15335 _clutter_actor_meta_get_debug_name (l->data));
15342 const GList *effects, *l;
15344 /* otherwise, get the cumulative volume */
15345 effects = _clutter_meta_group_peek_metas (priv->effects);
15346 for (l = effects; l != NULL; l = l->next)
15347 if (!_clutter_effect_get_paint_volume (l->data, pv))
15349 clutter_paint_volume_free (pv);
15350 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15351 "Effect (%s) failed to report a volume",
15352 _clutter_actor_get_debug_name (self),
15353 _clutter_actor_meta_get_debug_name (l->data));
15362 /* The public clutter_actor_get_paint_volume API returns a const
15363 * pointer since we return a pointer directly to the cached
15364 * PaintVolume associated with the actor and don't want the user to
15365 * inadvertently modify it, but for internal uses we sometimes need
15366 * access to the same PaintVolume but need to apply some book-keeping
15367 * modifications to it so we don't want a const pointer.
15369 static ClutterPaintVolume *
15370 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15372 ClutterActorPrivate *priv;
15376 if (priv->paint_volume_valid)
15377 clutter_paint_volume_free (&priv->paint_volume);
15379 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15381 priv->paint_volume_valid = TRUE;
15382 return &priv->paint_volume;
15386 priv->paint_volume_valid = FALSE;
15392 * clutter_actor_get_paint_volume:
15393 * @self: a #ClutterActor
15395 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15396 * when a paint volume can't be determined.
15398 * The paint volume is defined as the 3D space occupied by an actor
15399 * when being painted.
15401 * This function will call the <function>get_paint_volume()</function>
15402 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15403 * should not usually care about overriding the default implementation,
15404 * unless they are, for instance: painting outside their allocation, or
15405 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15408 * <note>2D actors overriding <function>get_paint_volume()</function>
15409 * ensure their volume has a depth of 0. (This will be true so long as
15410 * you don't call clutter_paint_volume_set_depth().)</note>
15412 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15413 * or %NULL if no volume could be determined. The returned pointer
15414 * is not guaranteed to be valid across multiple frames; if you want
15415 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15419 const ClutterPaintVolume *
15420 clutter_actor_get_paint_volume (ClutterActor *self)
15422 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15424 return _clutter_actor_get_paint_volume_mutable (self);
15428 * clutter_actor_get_transformed_paint_volume:
15429 * @self: a #ClutterActor
15430 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15431 * (or %NULL for the stage)
15433 * Retrieves the 3D paint volume of an actor like
15434 * clutter_actor_get_paint_volume() does (Please refer to the
15435 * documentation of clutter_actor_get_paint_volume() for more
15436 * details.) and it additionally transforms the paint volume into the
15437 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15438 * is passed for @relative_to_ancestor)
15440 * This can be used by containers that base their paint volume on
15441 * the volume of their children. Such containers can query the
15442 * transformed paint volume of all of its children and union them
15443 * together using clutter_paint_volume_union().
15445 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15446 * or %NULL if no volume could be determined. The returned pointer is
15447 * not guaranteed to be valid across multiple frames; if you wish to
15448 * keep it, you will have to copy it using clutter_paint_volume_copy().
15452 const ClutterPaintVolume *
15453 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15454 ClutterActor *relative_to_ancestor)
15456 const ClutterPaintVolume *volume;
15457 ClutterActor *stage;
15458 ClutterPaintVolume *transformed_volume;
15460 stage = _clutter_actor_get_stage_internal (self);
15461 if (G_UNLIKELY (stage == NULL))
15464 if (relative_to_ancestor == NULL)
15465 relative_to_ancestor = stage;
15467 volume = clutter_actor_get_paint_volume (self);
15468 if (volume == NULL)
15471 transformed_volume =
15472 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15474 _clutter_paint_volume_copy_static (volume, transformed_volume);
15476 _clutter_paint_volume_transform_relative (transformed_volume,
15477 relative_to_ancestor);
15479 return transformed_volume;
15483 * clutter_actor_get_paint_box:
15484 * @self: a #ClutterActor
15485 * @box: (out): return location for a #ClutterActorBox
15487 * Retrieves the paint volume of the passed #ClutterActor, and
15488 * transforms it into a 2D bounding box in stage coordinates.
15490 * This function is useful to determine the on screen area occupied by
15491 * the actor. The box is only an approximation and may often be
15492 * considerably larger due to the optimizations used to calculate the
15493 * box. The box is never smaller though, so it can reliably be used
15496 * There are times when a 2D paint box can't be determined, e.g.
15497 * because the actor isn't yet parented under a stage or because
15498 * the actor is unable to determine a paint volume.
15500 * Return value: %TRUE if a 2D paint box could be determined, else
15506 clutter_actor_get_paint_box (ClutterActor *self,
15507 ClutterActorBox *box)
15509 ClutterActor *stage;
15510 ClutterPaintVolume *pv;
15512 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15513 g_return_val_if_fail (box != NULL, FALSE);
15515 stage = _clutter_actor_get_stage_internal (self);
15516 if (G_UNLIKELY (!stage))
15519 pv = _clutter_actor_get_paint_volume_mutable (self);
15520 if (G_UNLIKELY (!pv))
15523 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15529 * clutter_actor_has_overlaps:
15530 * @self: A #ClutterActor
15532 * Asks the actor's implementation whether it may contain overlapping
15535 * For example; Clutter may use this to determine whether the painting
15536 * should be redirected to an offscreen buffer to correctly implement
15537 * the opacity property.
15539 * Custom actors can override the default response by implementing the
15540 * #ClutterActor <function>has_overlaps</function> virtual function. See
15541 * clutter_actor_set_offscreen_redirect() for more information.
15543 * Return value: %TRUE if the actor may have overlapping primitives, and
15549 clutter_actor_has_overlaps (ClutterActor *self)
15551 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15553 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15557 * clutter_actor_has_effects:
15558 * @self: A #ClutterActor
15560 * Returns whether the actor has any effects applied.
15562 * Return value: %TRUE if the actor has any effects,
15568 clutter_actor_has_effects (ClutterActor *self)
15570 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15572 if (self->priv->effects == NULL)
15575 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15579 * clutter_actor_has_constraints:
15580 * @self: A #ClutterActor
15582 * Returns whether the actor has any constraints applied.
15584 * Return value: %TRUE if the actor has any constraints,
15590 clutter_actor_has_constraints (ClutterActor *self)
15592 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15594 return self->priv->constraints != NULL;
15598 * clutter_actor_has_actions:
15599 * @self: A #ClutterActor
15601 * Returns whether the actor has any actions applied.
15603 * Return value: %TRUE if the actor has any actions,
15609 clutter_actor_has_actions (ClutterActor *self)
15611 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15613 return self->priv->actions != NULL;
15617 * clutter_actor_get_n_children:
15618 * @self: a #ClutterActor
15620 * Retrieves the number of children of @self.
15622 * Return value: the number of children of an actor
15627 clutter_actor_get_n_children (ClutterActor *self)
15629 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15631 return self->priv->n_children;
15635 * clutter_actor_get_child_at_index:
15636 * @self: a #ClutterActor
15637 * @index_: the position in the list of children
15639 * Retrieves the actor at the given @index_ inside the list of
15640 * children of @self.
15642 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15647 clutter_actor_get_child_at_index (ClutterActor *self,
15650 ClutterActor *iter;
15653 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15654 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15656 for (iter = self->priv->first_child, i = 0;
15657 iter != NULL && i < index_;
15658 iter = iter->priv->next_sibling, i += 1)
15665 * _clutter_actor_foreach_child:
15666 * @actor: The actor whos children you want to iterate
15667 * @callback: The function to call for each child
15668 * @user_data: Private data to pass to @callback
15670 * Calls a given @callback once for each child of the specified @actor and
15671 * passing the @user_data pointer each time.
15673 * Return value: returns %TRUE if all children were iterated, else
15674 * %FALSE if a callback broke out of iteration early.
15677 _clutter_actor_foreach_child (ClutterActor *self,
15678 ClutterForeachCallback callback,
15679 gpointer user_data)
15681 ClutterActorPrivate *priv = self->priv;
15682 ClutterActor *iter;
15685 for (cont = TRUE, iter = priv->first_child;
15686 cont && iter != NULL;
15687 iter = iter->priv->next_sibling)
15689 cont = callback (iter, user_data);
15696 /* For debugging purposes this gives us a simple way to print out
15697 * the scenegraph e.g in gdb using:
15699 * _clutter_actor_traverse (stage,
15701 * clutter_debug_print_actor_cb,
15706 static ClutterActorTraverseVisitFlags
15707 clutter_debug_print_actor_cb (ClutterActor *actor,
15711 g_print ("%*s%s:%p\n",
15713 _clutter_actor_get_debug_name (actor),
15716 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15721 _clutter_actor_traverse_breadth (ClutterActor *actor,
15722 ClutterTraverseCallback callback,
15723 gpointer user_data)
15725 GQueue *queue = g_queue_new ();
15726 ClutterActor dummy;
15727 int current_depth = 0;
15729 g_queue_push_tail (queue, actor);
15730 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15732 while ((actor = g_queue_pop_head (queue)))
15734 ClutterActorTraverseVisitFlags flags;
15736 if (actor == &dummy)
15739 g_queue_push_tail (queue, &dummy);
15743 flags = callback (actor, current_depth, user_data);
15744 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15746 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15748 ClutterActor *iter;
15750 for (iter = actor->priv->first_child;
15752 iter = iter->priv->next_sibling)
15754 g_queue_push_tail (queue, iter);
15759 g_queue_free (queue);
15762 static ClutterActorTraverseVisitFlags
15763 _clutter_actor_traverse_depth (ClutterActor *actor,
15764 ClutterTraverseCallback before_children_callback,
15765 ClutterTraverseCallback after_children_callback,
15767 gpointer user_data)
15769 ClutterActorTraverseVisitFlags flags;
15771 flags = before_children_callback (actor, current_depth, user_data);
15772 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15773 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15775 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15777 ClutterActor *iter;
15779 for (iter = actor->priv->first_child;
15781 iter = iter->priv->next_sibling)
15783 flags = _clutter_actor_traverse_depth (iter,
15784 before_children_callback,
15785 after_children_callback,
15789 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15790 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15794 if (after_children_callback)
15795 return after_children_callback (actor, current_depth, user_data);
15797 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15800 /* _clutter_actor_traverse:
15801 * @actor: The actor to start traversing the graph from
15802 * @flags: These flags may affect how the traversal is done
15803 * @before_children_callback: A function to call before visiting the
15804 * children of the current actor.
15805 * @after_children_callback: A function to call after visiting the
15806 * children of the current actor. (Ignored if
15807 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15808 * @user_data: The private data to pass to the callbacks
15810 * Traverses the scenegraph starting at the specified @actor and
15811 * descending through all its children and its children's children.
15812 * For each actor traversed @before_children_callback and
15813 * @after_children_callback are called with the specified
15814 * @user_data, before and after visiting that actor's children.
15816 * The callbacks can return flags that affect the ongoing traversal
15817 * such as by skipping over an actors children or bailing out of
15818 * any further traversing.
15821 _clutter_actor_traverse (ClutterActor *actor,
15822 ClutterActorTraverseFlags flags,
15823 ClutterTraverseCallback before_children_callback,
15824 ClutterTraverseCallback after_children_callback,
15825 gpointer user_data)
15827 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15828 _clutter_actor_traverse_breadth (actor,
15829 before_children_callback,
15831 else /* DEPTH_FIRST */
15832 _clutter_actor_traverse_depth (actor,
15833 before_children_callback,
15834 after_children_callback,
15835 0, /* start depth */
15840 on_layout_manager_changed (ClutterLayoutManager *manager,
15841 ClutterActor *self)
15843 clutter_actor_queue_relayout (self);
15847 * clutter_actor_set_layout_manager:
15848 * @self: a #ClutterActor
15849 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15851 * Sets the #ClutterLayoutManager delegate object that will be used to
15852 * lay out the children of @self.
15854 * The #ClutterActor will take a reference on the passed @manager which
15855 * will be released either when the layout manager is removed, or when
15856 * the actor is destroyed.
15861 clutter_actor_set_layout_manager (ClutterActor *self,
15862 ClutterLayoutManager *manager)
15864 ClutterActorPrivate *priv;
15866 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15867 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15871 if (priv->layout_manager != NULL)
15873 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15874 G_CALLBACK (on_layout_manager_changed),
15876 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15877 g_object_unref (priv->layout_manager);
15880 priv->layout_manager = manager;
15882 if (priv->layout_manager != NULL)
15884 g_object_ref_sink (priv->layout_manager);
15885 clutter_layout_manager_set_container (priv->layout_manager,
15886 CLUTTER_CONTAINER (self));
15887 g_signal_connect (priv->layout_manager, "layout-changed",
15888 G_CALLBACK (on_layout_manager_changed),
15892 clutter_actor_queue_relayout (self);
15894 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15898 * clutter_actor_get_layout_manager:
15899 * @self: a #ClutterActor
15901 * Retrieves the #ClutterLayoutManager used by @self.
15903 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15908 ClutterLayoutManager *
15909 clutter_actor_get_layout_manager (ClutterActor *self)
15911 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15913 return self->priv->layout_manager;
15916 static const ClutterLayoutInfo default_layout_info = {
15919 { 0, 0, 0, 0 }, /* margin */
15920 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15921 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15922 0.f, 0.f, /* min_width, natural_width */
15923 0.f, 0.f, /* natual_width, natural_height */
15927 layout_info_free (gpointer data)
15929 if (G_LIKELY (data != NULL))
15930 g_slice_free (ClutterLayoutInfo, data);
15934 * _clutter_actor_get_layout_info:
15935 * @self: a #ClutterActor
15937 * Retrieves a pointer to the ClutterLayoutInfo structure.
15939 * If the actor does not have a ClutterLayoutInfo associated to it, one
15940 * will be created and initialized to the default values.
15942 * This function should be used for setters.
15944 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15947 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15949 ClutterLayoutInfo *
15950 _clutter_actor_get_layout_info (ClutterActor *self)
15952 ClutterLayoutInfo *retval;
15954 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15955 if (retval == NULL)
15957 retval = g_slice_new (ClutterLayoutInfo);
15959 *retval = default_layout_info;
15961 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15970 * _clutter_actor_get_layout_info_or_defaults:
15971 * @self: a #ClutterActor
15973 * Retrieves the ClutterLayoutInfo structure associated to an actor.
15975 * If the actor does not have a ClutterLayoutInfo structure associated to it,
15976 * then the default structure will be returned.
15978 * This function should only be used for getters.
15980 * Return value: a const pointer to the ClutterLayoutInfo structure
15982 const ClutterLayoutInfo *
15983 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15985 const ClutterLayoutInfo *info;
15987 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15989 return &default_layout_info;
15995 * clutter_actor_set_x_align:
15996 * @self: a #ClutterActor
15997 * @x_align: the horizontal alignment policy
15999 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16000 * actor received extra horizontal space.
16002 * See also the #ClutterActor:x-align property.
16007 clutter_actor_set_x_align (ClutterActor *self,
16008 ClutterActorAlign x_align)
16010 ClutterLayoutInfo *info;
16012 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16014 info = _clutter_actor_get_layout_info (self);
16016 if (info->x_align != x_align)
16018 info->x_align = x_align;
16020 clutter_actor_queue_relayout (self);
16022 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16027 * clutter_actor_get_x_align:
16028 * @self: a #ClutterActor
16030 * Retrieves the horizontal alignment policy set using
16031 * clutter_actor_set_x_align().
16033 * Return value: the horizontal alignment policy.
16038 clutter_actor_get_x_align (ClutterActor *self)
16040 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16042 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16046 * clutter_actor_set_y_align:
16047 * @self: a #ClutterActor
16048 * @y_align: the vertical alignment policy
16050 * Sets the vertical alignment policy of a #ClutterActor, in case the
16051 * actor received extra vertical space.
16053 * See also the #ClutterActor:y-align property.
16058 clutter_actor_set_y_align (ClutterActor *self,
16059 ClutterActorAlign y_align)
16061 ClutterLayoutInfo *info;
16063 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16065 info = _clutter_actor_get_layout_info (self);
16067 if (info->y_align != y_align)
16069 info->y_align = y_align;
16071 clutter_actor_queue_relayout (self);
16073 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16078 * clutter_actor_get_y_align:
16079 * @self: a #ClutterActor
16081 * Retrieves the vertical alignment policy set using
16082 * clutter_actor_set_y_align().
16084 * Return value: the vertical alignment policy.
16089 clutter_actor_get_y_align (ClutterActor *self)
16091 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16093 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16098 * clutter_margin_new:
16100 * Creates a new #ClutterMargin.
16102 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16103 * clutter_margin_free() to free the resources associated with it when
16109 clutter_margin_new (void)
16111 return g_slice_new0 (ClutterMargin);
16115 * clutter_margin_copy:
16116 * @margin_: a #ClutterMargin
16118 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16119 * the newly created structure.
16121 * Return value: (transfer full): a copy of the #ClutterMargin.
16126 clutter_margin_copy (const ClutterMargin *margin_)
16128 if (G_LIKELY (margin_ != NULL))
16129 return g_slice_dup (ClutterMargin, margin_);
16135 * clutter_margin_free:
16136 * @margin_: a #ClutterMargin
16138 * Frees the resources allocated by clutter_margin_new() and
16139 * clutter_margin_copy().
16144 clutter_margin_free (ClutterMargin *margin_)
16146 if (G_LIKELY (margin_ != NULL))
16147 g_slice_free (ClutterMargin, margin_);
16150 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16151 clutter_margin_copy,
16152 clutter_margin_free)
16155 * clutter_actor_set_margin:
16156 * @self: a #ClutterActor
16157 * @margin: a #ClutterMargin
16159 * Sets all the components of the margin of a #ClutterActor.
16164 clutter_actor_set_margin (ClutterActor *self,
16165 const ClutterMargin *margin)
16167 ClutterLayoutInfo *info;
16171 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16172 g_return_if_fail (margin != NULL);
16174 obj = G_OBJECT (self);
16177 g_object_freeze_notify (obj);
16179 info = _clutter_actor_get_layout_info (self);
16181 if (info->margin.top != margin->top)
16183 info->margin.top = margin->top;
16184 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16188 if (info->margin.right != margin->right)
16190 info->margin.right = margin->right;
16191 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16195 if (info->margin.bottom != margin->bottom)
16197 info->margin.bottom = margin->bottom;
16198 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16202 if (info->margin.left != margin->left)
16204 info->margin.left = margin->left;
16205 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16210 clutter_actor_queue_relayout (self);
16212 g_object_thaw_notify (obj);
16216 * clutter_actor_get_margin:
16217 * @self: a #ClutterActor
16218 * @margin: (out caller-allocates): return location for a #ClutterMargin
16220 * Retrieves all the components of the margin of a #ClutterActor.
16225 clutter_actor_get_margin (ClutterActor *self,
16226 ClutterMargin *margin)
16228 const ClutterLayoutInfo *info;
16230 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16231 g_return_if_fail (margin != NULL);
16233 info = _clutter_actor_get_layout_info_or_defaults (self);
16235 *margin = info->margin;
16239 * clutter_actor_set_margin_top:
16240 * @self: a #ClutterActor
16241 * @margin: the top margin
16243 * Sets the margin from the top of a #ClutterActor.
16248 clutter_actor_set_margin_top (ClutterActor *self,
16251 ClutterLayoutInfo *info;
16253 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16254 g_return_if_fail (margin >= 0.f);
16256 info = _clutter_actor_get_layout_info (self);
16258 if (info->margin.top == margin)
16261 info->margin.top = margin;
16263 clutter_actor_queue_relayout (self);
16265 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16269 * clutter_actor_get_margin_top:
16270 * @self: a #ClutterActor
16272 * Retrieves the top margin of a #ClutterActor.
16274 * Return value: the top margin
16279 clutter_actor_get_margin_top (ClutterActor *self)
16281 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16283 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16287 * clutter_actor_set_margin_bottom:
16288 * @self: a #ClutterActor
16289 * @margin: the bottom margin
16291 * Sets the margin from the bottom of a #ClutterActor.
16296 clutter_actor_set_margin_bottom (ClutterActor *self,
16299 ClutterLayoutInfo *info;
16301 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16302 g_return_if_fail (margin >= 0.f);
16304 info = _clutter_actor_get_layout_info (self);
16306 if (info->margin.bottom == margin)
16309 info->margin.bottom = margin;
16311 clutter_actor_queue_relayout (self);
16313 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16317 * clutter_actor_get_margin_bottom:
16318 * @self: a #ClutterActor
16320 * Retrieves the bottom margin of a #ClutterActor.
16322 * Return value: the bottom margin
16327 clutter_actor_get_margin_bottom (ClutterActor *self)
16329 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16331 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16335 * clutter_actor_set_margin_left:
16336 * @self: a #ClutterActor
16337 * @margin: the left margin
16339 * Sets the margin from the left of a #ClutterActor.
16344 clutter_actor_set_margin_left (ClutterActor *self,
16347 ClutterLayoutInfo *info;
16349 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16350 g_return_if_fail (margin >= 0.f);
16352 info = _clutter_actor_get_layout_info (self);
16354 if (info->margin.left == margin)
16357 info->margin.left = margin;
16359 clutter_actor_queue_relayout (self);
16361 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16365 * clutter_actor_get_margin_left:
16366 * @self: a #ClutterActor
16368 * Retrieves the left margin of a #ClutterActor.
16370 * Return value: the left margin
16375 clutter_actor_get_margin_left (ClutterActor *self)
16377 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16379 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16383 * clutter_actor_set_margin_right:
16384 * @self: a #ClutterActor
16385 * @margin: the right margin
16387 * Sets the margin from the right of a #ClutterActor.
16392 clutter_actor_set_margin_right (ClutterActor *self,
16395 ClutterLayoutInfo *info;
16397 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16398 g_return_if_fail (margin >= 0.f);
16400 info = _clutter_actor_get_layout_info (self);
16402 if (info->margin.right == margin)
16405 info->margin.right = margin;
16407 clutter_actor_queue_relayout (self);
16409 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16413 * clutter_actor_get_margin_right:
16414 * @self: a #ClutterActor
16416 * Retrieves the right margin of a #ClutterActor.
16418 * Return value: the right margin
16423 clutter_actor_get_margin_right (ClutterActor *self)
16425 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16427 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16431 clutter_actor_set_background_color_internal (ClutterActor *self,
16432 const ClutterColor *color)
16434 ClutterActorPrivate *priv = self->priv;
16437 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16440 obj = G_OBJECT (self);
16442 priv->bg_color = *color;
16443 priv->bg_color_set = TRUE;
16445 clutter_actor_queue_redraw (self);
16447 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16448 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16452 * clutter_actor_set_background_color:
16453 * @self: a #ClutterActor
16454 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16457 * Sets the background color of a #ClutterActor.
16459 * The background color will be used to cover the whole allocation of the
16460 * actor. The default background color of an actor is transparent.
16462 * To check whether an actor has a background color, you can use the
16463 * #ClutterActor:background-color-set actor property.
16465 * The #ClutterActor:background-color property is animatable.
16470 clutter_actor_set_background_color (ClutterActor *self,
16471 const ClutterColor *color)
16473 ClutterActorPrivate *priv;
16475 GParamSpec *bg_color_pspec;
16477 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16479 obj = G_OBJECT (self);
16485 priv->bg_color_set = FALSE;
16486 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16487 clutter_actor_queue_redraw (self);
16491 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16492 if (clutter_actor_get_easing_duration (self) != 0)
16494 ClutterTransition *transition;
16496 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16497 if (transition == NULL)
16499 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16502 clutter_timeline_start (CLUTTER_TIMELINE (transition));
16505 _clutter_actor_update_transition (self, bg_color_pspec, color);
16507 clutter_actor_queue_redraw (self);
16510 clutter_actor_set_background_color_internal (self, color);
16514 * clutter_actor_get_background_color:
16515 * @self: a #ClutterActor
16516 * @color: (out caller-allocates): return location for a #ClutterColor
16518 * Retrieves the color set using clutter_actor_set_background_color().
16523 clutter_actor_get_background_color (ClutterActor *self,
16524 ClutterColor *color)
16526 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16527 g_return_if_fail (color != NULL);
16529 *color = self->priv->bg_color;
16533 * clutter_actor_get_previous_sibling:
16534 * @self: a #ClutterActor
16536 * Retrieves the sibling of @self that comes before it in the list
16537 * of children of @self's parent.
16539 * The returned pointer is only valid until the scene graph changes; it
16540 * is not safe to modify the list of children of @self while iterating
16543 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16548 clutter_actor_get_previous_sibling (ClutterActor *self)
16550 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16552 return self->priv->prev_sibling;
16556 * clutter_actor_get_next_sibling:
16557 * @self: a #ClutterActor
16559 * Retrieves the sibling of @self that comes after it in the list
16560 * of children of @self's parent.
16562 * The returned pointer is only valid until the scene graph changes; it
16563 * is not safe to modify the list of children of @self while iterating
16566 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16571 clutter_actor_get_next_sibling (ClutterActor *self)
16573 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16575 return self->priv->next_sibling;
16579 * clutter_actor_get_first_child:
16580 * @self: a #ClutterActor
16582 * Retrieves the first child of @self.
16584 * The returned pointer is only valid until the scene graph changes; it
16585 * is not safe to modify the list of children of @self while iterating
16588 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16593 clutter_actor_get_first_child (ClutterActor *self)
16595 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16597 return self->priv->first_child;
16601 * clutter_actor_get_last_child:
16602 * @self: a #ClutterActor
16604 * Retrieves the last child of @self.
16606 * The returned pointer is only valid until the scene graph changes; it
16607 * is not safe to modify the list of children of @self while iterating
16610 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16615 clutter_actor_get_last_child (ClutterActor *self)
16617 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16619 return self->priv->last_child;
16622 /* easy way to have properly named fields instead of the dummy ones
16623 * we use in the public structure
16625 typedef struct _RealActorIter
16627 ClutterActor *root; /* dummy1 */
16628 ClutterActor *current; /* dummy2 */
16629 gpointer padding_1; /* dummy3 */
16630 gint age; /* dummy4 */
16631 gpointer padding_2; /* dummy5 */
16635 * clutter_actor_iter_init:
16636 * @iter: a #ClutterActorIter
16637 * @root: a #ClutterActor
16639 * Initializes a #ClutterActorIter, which can then be used to iterate
16640 * efficiently over a section of the scene graph, and associates it
16643 * Modifying the scene graph section that contains @root will invalidate
16647 * ClutterActorIter iter;
16648 * ClutterActor *child;
16650 * clutter_actor_iter_init (&iter, container);
16651 * while (clutter_actor_iter_next (&iter, &child))
16653 * /* do something with child */
16660 clutter_actor_iter_init (ClutterActorIter *iter,
16661 ClutterActor *root)
16663 RealActorIter *ri = (RealActorIter *) iter;
16665 g_return_if_fail (iter != NULL);
16666 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16669 ri->current = NULL;
16670 ri->age = root->priv->age;
16674 * clutter_actor_iter_next:
16675 * @iter: a #ClutterActorIter
16676 * @child: (out): return location for a #ClutterActor
16678 * Advances the @iter and retrieves the next child of the root #ClutterActor
16679 * that was used to initialize the #ClutterActorIterator.
16681 * If the iterator can advance, this function returns %TRUE and sets the
16684 * If the iterator cannot advance, this function returns %FALSE, and
16685 * the contents of @child are undefined.
16687 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16692 clutter_actor_iter_next (ClutterActorIter *iter,
16693 ClutterActor **child)
16695 RealActorIter *ri = (RealActorIter *) iter;
16697 g_return_val_if_fail (iter != NULL, FALSE);
16698 g_return_val_if_fail (ri->root != NULL, FALSE);
16699 #ifndef G_DISABLE_ASSERT
16700 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16703 if (ri->current == NULL)
16704 ri->current = ri->root->priv->first_child;
16706 ri->current = ri->current->priv->next_sibling;
16709 *child = ri->current;
16711 return ri->current != NULL;
16715 * clutter_actor_iter_prev:
16716 * @iter: a #ClutterActorIter
16717 * @child: (out): return location for a #ClutterActor
16719 * Advances the @iter and retrieves the previous child of the root
16720 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16722 * If the iterator can advance, this function returns %TRUE and sets the
16725 * If the iterator cannot advance, this function returns %FALSE, and
16726 * the contents of @child are undefined.
16728 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16733 clutter_actor_iter_prev (ClutterActorIter *iter,
16734 ClutterActor **child)
16736 RealActorIter *ri = (RealActorIter *) iter;
16738 g_return_val_if_fail (iter != NULL, FALSE);
16739 g_return_val_if_fail (ri->root != NULL, FALSE);
16740 #ifndef G_DISABLE_ASSERT
16741 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16744 if (ri->current == NULL)
16745 ri->current = ri->root->priv->last_child;
16747 ri->current = ri->current->priv->prev_sibling;
16750 *child = ri->current;
16752 return ri->current != NULL;
16756 * clutter_actor_iter_remove:
16757 * @iter: a #ClutterActorIter
16759 * Safely removes the #ClutterActor currently pointer to by the iterator
16762 * This function can only be called after clutter_actor_iter_next() or
16763 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16764 * than once for the same actor.
16766 * This function will call clutter_actor_remove_child() internally.
16771 clutter_actor_iter_remove (ClutterActorIter *iter)
16773 RealActorIter *ri = (RealActorIter *) iter;
16776 g_return_if_fail (iter != NULL);
16777 g_return_if_fail (ri->root != NULL);
16778 #ifndef G_DISABLE_ASSERT
16779 g_return_if_fail (ri->age == ri->root->priv->age);
16781 g_return_if_fail (ri->current != NULL);
16787 ri->current = cur->priv->prev_sibling;
16789 clutter_actor_remove_child_internal (ri->root, cur,
16790 REMOVE_CHILD_DEFAULT_FLAGS);
16797 * clutter_actor_iter_destroy:
16798 * @iter: a #ClutterActorIter
16800 * Safely destroys the #ClutterActor currently pointer to by the iterator
16803 * This function can only be called after clutter_actor_iter_next() or
16804 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16805 * than once for the same actor.
16807 * This function will call clutter_actor_destroy() internally.
16812 clutter_actor_iter_destroy (ClutterActorIter *iter)
16814 RealActorIter *ri = (RealActorIter *) iter;
16817 g_return_if_fail (iter != NULL);
16818 g_return_if_fail (ri->root != NULL);
16819 #ifndef G_DISABLE_ASSERT
16820 g_return_if_fail (ri->age == ri->root->priv->age);
16822 g_return_if_fail (ri->current != NULL);
16828 ri->current = cur->priv->prev_sibling;
16830 clutter_actor_destroy (cur);
16836 static const ClutterAnimationInfo default_animation_info = {
16837 NULL, /* transitions */
16839 NULL, /* cur_state */
16843 clutter_animation_info_free (gpointer data)
16847 ClutterAnimationInfo *info = data;
16849 if (info->transitions != NULL)
16850 g_hash_table_unref (info->transitions);
16852 if (info->states != NULL)
16853 g_array_unref (info->states);
16855 g_slice_free (ClutterAnimationInfo, info);
16859 const ClutterAnimationInfo *
16860 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16862 const ClutterAnimationInfo *res;
16863 GObject *obj = G_OBJECT (self);
16865 res = g_object_get_qdata (obj, quark_actor_animation_info);
16869 return &default_animation_info;
16872 ClutterAnimationInfo *
16873 _clutter_actor_get_animation_info (ClutterActor *self)
16875 GObject *obj = G_OBJECT (self);
16876 ClutterAnimationInfo *res;
16878 res = g_object_get_qdata (obj, quark_actor_animation_info);
16881 res = g_slice_new (ClutterAnimationInfo);
16883 *res = default_animation_info;
16885 g_object_set_qdata_full (obj, quark_actor_animation_info,
16887 clutter_animation_info_free);
16893 ClutterTransition *
16894 _clutter_actor_get_transition (ClutterActor *actor,
16897 const ClutterAnimationInfo *info;
16899 info = _clutter_actor_get_animation_info_or_defaults (actor);
16901 if (info->transitions == NULL)
16904 return g_hash_table_lookup (info->transitions, pspec->name);
16907 typedef struct _TransitionClosure
16909 ClutterActor *actor;
16910 ClutterTransition *transition;
16912 gulong completed_id;
16913 } TransitionClosure;
16916 transition_closure_free (gpointer data)
16918 if (G_LIKELY (data != NULL))
16920 TransitionClosure *clos = data;
16922 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16923 g_free (clos->name);
16925 g_slice_free (TransitionClosure, clos);
16930 on_transition_completed (ClutterTransition *transition,
16931 TransitionClosure *clos)
16933 ClutterAnimationInfo *info;
16935 info = _clutter_actor_get_animation_info (clos->actor);
16937 /* this will take care of cleaning clos for us */
16938 g_hash_table_remove (info->transitions, clos->name);
16942 _clutter_actor_update_transition (ClutterActor *actor,
16946 TransitionClosure *clos;
16947 ClutterInterval *interval;
16948 const ClutterAnimationInfo *info;
16951 GValue initial = G_VALUE_INIT;
16952 GValue final = G_VALUE_INIT;
16953 char *error = NULL;
16955 info = _clutter_actor_get_animation_info_or_defaults (actor);
16957 if (info->transitions == NULL)
16960 clos = g_hash_table_lookup (info->transitions, pspec->name);
16964 va_start (var_args, pspec);
16966 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16968 g_value_init (&initial, ptype);
16969 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16973 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16976 g_critical ("%s: %s", G_STRLOC, error);
16981 interval = clutter_transition_get_interval (clos->transition);
16982 clutter_interval_set_initial_value (interval, &initial);
16983 clutter_interval_set_final_value (interval, &final);
16985 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16988 g_value_unset (&initial);
16989 g_value_unset (&final);
16995 * _clutter_actor_create_transition:
16996 * @actor: a #ClutterActor
16997 * @pspec: the property used for the transition
16998 * @...: initial and final state
17000 * Creates a #ClutterTransition for the property represented by @pspec.
17002 * Return value: a #ClutterTransition
17004 ClutterTransition *
17005 _clutter_actor_create_transition (ClutterActor *actor,
17009 ClutterAnimationInfo *info;
17010 ClutterTransition *res = NULL;
17011 gboolean call_restore = FALSE;
17012 TransitionClosure *clos;
17015 info = _clutter_actor_get_animation_info (actor);
17017 if (info->states == NULL)
17019 clutter_actor_save_easing_state (actor);
17020 call_restore = TRUE;
17023 if (info->transitions == NULL)
17024 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17026 transition_closure_free);
17028 va_start (var_args, pspec);
17030 clos = g_hash_table_lookup (info->transitions, pspec->name);
17033 ClutterInterval *interval;
17034 GValue initial = G_VALUE_INIT;
17035 GValue final = G_VALUE_INIT;
17039 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17041 G_VALUE_COLLECT_INIT (&initial, ptype,
17046 g_critical ("%s: %s", G_STRLOC, error);
17051 G_VALUE_COLLECT_INIT (&final, ptype,
17057 g_critical ("%s: %s", G_STRLOC, error);
17058 g_value_unset (&initial);
17063 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17065 g_value_unset (&initial);
17066 g_value_unset (&final);
17068 res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17071 clutter_transition_set_interval (res, interval);
17072 clutter_transition_set_remove_on_complete (res, TRUE);
17074 clutter_actor_add_transition (actor, pspec->name, res);
17077 res = clos->transition;
17081 clutter_actor_restore_easing_state (actor);
17089 * clutter_actor_add_transition:
17090 * @self: a #ClutterActor
17091 * @name: the name of the transition to add
17092 * @transition: the #ClutterTransition to add
17094 * Adds a @transition to the #ClutterActor's list of animations.
17096 * The @name string is a per-actor unique identifier of the @transition: only
17097 * one #ClutterTransition can be associated to the specified @name.
17099 * The @transition will be given the easing duration, mode, and delay
17100 * associated to the actor's current easing state; it is possible to modify
17101 * these values after calling clutter_actor_add_transition().
17103 * This function is usually called implicitly when modifying an animatable
17109 clutter_actor_add_transition (ClutterActor *self,
17111 ClutterTransition *transition)
17113 ClutterTimeline *timeline;
17114 TransitionClosure *clos;
17115 ClutterAnimationInfo *info;
17117 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17118 g_return_if_fail (name != NULL);
17119 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17121 info = _clutter_actor_get_animation_info (self);
17123 if (info->cur_state == NULL)
17125 g_warning ("No easing state is defined for the actor '%s'; you "
17126 "must call clutter_actor_save_easing_state() before "
17127 "calling clutter_actor_add_transition().",
17128 _clutter_actor_get_debug_name (self));
17132 if (info->transitions == NULL)
17133 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17135 transition_closure_free);
17137 if (g_hash_table_lookup (info->transitions, name) != NULL)
17139 g_warning ("A transition with name '%s' already exists for "
17142 _clutter_actor_get_debug_name (self));
17146 timeline = CLUTTER_TIMELINE (transition);
17148 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17149 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17150 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17152 clos = g_slice_new (TransitionClosure);
17153 clos->actor = self;
17154 clos->transition = transition;
17155 clos->name = g_strdup (name);
17156 clos->completed_id = g_signal_connect (timeline, "completed",
17157 G_CALLBACK (on_transition_completed),
17160 g_hash_table_insert (info->transitions, clos->name, clos);
17164 * clutter_actor_remove_transition:
17165 * @self: a #ClutterActor
17166 * @name: the name of the transition to remove
17168 * Removes the transition stored inside a #ClutterActor using @name
17174 clutter_actor_remove_transition (ClutterActor *self,
17177 const ClutterAnimationInfo *info;
17179 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17180 g_return_if_fail (name != NULL);
17182 info = _clutter_actor_get_animation_info_or_defaults (self);
17184 if (info->transitions == NULL)
17187 g_hash_table_remove (info->transitions, name);
17191 * clutter_actor_remove_all_transitions:
17192 * @self: a #ClutterActor
17194 * Removes all transitions associated to @self.
17199 clutter_actor_remove_all_transitions (ClutterActor *self)
17201 const ClutterAnimationInfo *info;
17203 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17205 info = _clutter_actor_get_animation_info_or_defaults (self);
17206 if (info->transitions == NULL)
17209 g_hash_table_remove_all (info->transitions);
17213 * clutter_actor_set_easing_duration:
17214 * @self: a #ClutterActor
17215 * @msecs: the duration of the easing, or %NULL
17217 * Sets the duration of the tweening for animatable properties
17218 * of @self for the current easing state.
17220 * Calling this function will implicitly call
17221 * clutter_actor_save_easing_state() if no previous call to
17222 * that function was made.
17227 clutter_actor_set_easing_duration (ClutterActor *self,
17230 ClutterAnimationInfo *info;
17232 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17234 info = _clutter_actor_get_animation_info (self);
17236 if (info->states == NULL)
17237 clutter_actor_save_easing_state (self);
17239 if (info->cur_state->easing_duration != msecs)
17240 info->cur_state->easing_duration = msecs;
17244 * clutter_actor_get_easing_duration:
17245 * @self: a #ClutterActor
17247 * Retrieves the duration of the tweening for animatable
17248 * properties of @self for the current easing state.
17250 * Return value: the duration of the tweening, in milliseconds
17255 clutter_actor_get_easing_duration (ClutterActor *self)
17257 const ClutterAnimationInfo *info;
17259 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17261 info = _clutter_actor_get_animation_info_or_defaults (self);
17263 if (info->cur_state != NULL)
17264 return info->cur_state->easing_duration;
17270 * clutter_actor_set_easing_mode:
17271 * @self: a #ClutterActor
17272 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17274 * Sets the easing mode for the tweening of animatable properties
17277 * Calling this function will implicitly call
17278 * clutter_actor_save_easing_state() if no previous calls to
17279 * that function were made.
17284 clutter_actor_set_easing_mode (ClutterActor *self,
17285 ClutterAnimationMode mode)
17287 ClutterAnimationInfo *info;
17289 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17290 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17291 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17293 info = _clutter_actor_get_animation_info (self);
17295 if (info->states == NULL)
17296 clutter_actor_save_easing_state (self);
17298 if (info->cur_state->easing_mode != mode)
17299 info->cur_state->easing_mode = mode;
17303 * clutter_actor_get_easing_mode:
17304 * @self: a #ClutterActor
17306 * Retrieves the easing mode for the tweening of animatable properties
17307 * of @self for the current easing state.
17309 * Return value: an easing mode
17313 ClutterAnimationMode
17314 clutter_actor_get_easing_mode (ClutterActor *self)
17316 const ClutterAnimationInfo *info;
17318 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17320 info = _clutter_actor_get_animation_info_or_defaults (self);
17322 if (info->cur_state != NULL)
17323 return info->cur_state->easing_mode;
17325 return CLUTTER_EASE_OUT_CUBIC;
17329 * clutter_actor_set_easing_delay:
17330 * @self: a #ClutterActor
17331 * @msecs: the delay before the start of the tweening, in milliseconds
17333 * Sets the delay that should be applied before tweening animatable
17336 * Calling this function will implicitly call
17337 * clutter_actor_save_easing_state() if no previous calls to
17338 * that function were made.
17343 clutter_actor_set_easing_delay (ClutterActor *self,
17346 ClutterAnimationInfo *info;
17348 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17350 info = _clutter_actor_get_animation_info (self);
17352 if (info->states == NULL)
17353 clutter_actor_save_easing_state (self);
17355 if (info->cur_state->easing_delay != msecs)
17356 info->cur_state->easing_delay = msecs;
17360 * clutter_actor_get_easing_delay:
17361 * @self: a #ClutterActor
17363 * Retrieves the delay that should be applied when tweening animatable
17366 * Return value: a delay, in milliseconds
17371 clutter_actor_get_easing_delay (ClutterActor *self)
17373 const ClutterAnimationInfo *info;
17375 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17377 info = _clutter_actor_get_animation_info_or_defaults (self);
17379 if (info->cur_state != NULL)
17380 return info->cur_state->easing_delay;
17386 * clutter_actor_get_transition:
17387 * @self: a #ClutterActor
17388 * @name: the name of the transition
17390 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17391 * transition @name.
17393 * Transitions created for animatable properties use the name of the
17394 * property itself, for instance the code below:
17397 * clutter_actor_set_easing_duration (actor, 1000);
17398 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17400 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17401 * g_signal_connect (transition, "completed",
17402 * G_CALLBACK (on_transition_complete),
17406 * will call the <function>on_transition_complete</function> callback when
17407 * the transition is complete.
17409 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17410 * was found to match the passed name; the returned instance is owned
17411 * by Clutter and it should not be freed
17415 ClutterTransition *
17416 clutter_actor_get_transition (ClutterActor *self,
17419 TransitionClosure *clos;
17420 const ClutterAnimationInfo *info;
17422 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17423 g_return_val_if_fail (name != NULL, NULL);
17425 info = _clutter_actor_get_animation_info_or_defaults (self);
17427 if (info->transitions == NULL)
17430 clos = g_hash_table_lookup (info->transitions, name);
17434 return clos->transition;
17438 * clutter_actor_save_easing_state:
17439 * @self: a #ClutterActor
17441 * Saves the current easing state for animatable properties, and creates
17442 * a new state with the default values for easing mode and duration.
17447 clutter_actor_save_easing_state (ClutterActor *self)
17449 ClutterAnimationInfo *info;
17452 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17454 info = _clutter_actor_get_animation_info (self);
17456 if (info->states == NULL)
17457 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17459 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17460 new_state.easing_duration = 250;
17461 new_state.easing_delay = 0;
17463 g_array_append_val (info->states, new_state);
17465 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17469 * clutter_actor_restore_easing_state:
17470 * @self: a #ClutterActor
17472 * Restores the easing state as it was prior to a call to
17473 * clutter_actor_save_easing_state().
17478 clutter_actor_restore_easing_state (ClutterActor *self)
17480 ClutterAnimationInfo *info;
17482 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17484 info = _clutter_actor_get_animation_info (self);
17486 if (info->states == NULL)
17488 g_critical ("The function clutter_actor_restore_easing_state() has "
17489 "called without a previous call to "
17490 "clutter_actor_save_easing_state().");
17494 g_array_remove_index (info->states, info->states->len - 1);
17495 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17499 * clutter_actor_set_content:
17500 * @self: a #ClutterActor
17501 * @content: (allow-none): a #ClutterContent, or %NULL
17503 * Sets the contents of a #ClutterActor.
17508 clutter_actor_set_content (ClutterActor *self,
17509 ClutterContent *content)
17511 ClutterActorPrivate *priv;
17513 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17514 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17518 if (priv->content != NULL)
17520 _clutter_content_detached (priv->content, self);
17521 g_object_unref (priv->content);
17524 priv->content = content;
17526 if (priv->content != NULL)
17528 g_object_ref (priv->content);
17529 _clutter_content_attached (priv->content, self);
17532 /* given that the content is always painted within the allocation,
17533 * we only need to queue a redraw here
17535 clutter_actor_queue_redraw (self);
17537 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17539 /* if the content gravity is not resize-fill, and the new content has a
17540 * different preferred size than the previous one, then the content box
17541 * may have been changed. since we compute that lazily, we just notify
17542 * here, and let whomever watches :content-box do whatever they need to
17545 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17546 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17550 * clutter_actor_get_content:
17551 * @self: a #ClutterActor
17553 * Retrieves the contents of @self.
17555 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17556 * or %NULL if none was set
17561 clutter_actor_get_content (ClutterActor *self)
17563 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17565 return self->priv->content;
17569 * clutter_actor_set_content_gravity:
17570 * @self: a #ClutterActor
17571 * @gravity: the #ClutterContentGravity
17573 * Sets the gravity of the #ClutterContent used by @self.
17575 * See the description of the #ClutterActor:content-gravity property for
17576 * more information.
17581 clutter_actor_set_content_gravity (ClutterActor *self,
17582 ClutterContentGravity gravity)
17584 ClutterActorPrivate *priv;
17586 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17590 if (priv->content_gravity == gravity)
17593 priv->content_gravity = gravity;
17595 clutter_actor_queue_redraw (self);
17597 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17598 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17602 * clutter_actor_get_content_gravity:
17603 * @self: a #ClutterActor
17605 * Retrieves the content gravity as set using
17606 * clutter_actor_get_content_gravity().
17608 * Return value: the content gravity
17612 ClutterContentGravity
17613 clutter_actor_get_content_gravity (ClutterActor *self)
17615 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17616 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17618 return self->priv->content_gravity;
17622 * clutter_actor_get_content_box:
17623 * @self: a #ClutterActor
17624 * @box: (out caller-allocates): the return location for the bounding
17625 * box for the #ClutterContent
17627 * Retrieves the bounding box for the #ClutterContent of @self.
17629 * The bounding box is relative to the actor's allocation.
17631 * If no #ClutterContent is set for @self, or if @self has not been
17632 * allocated yet, then the result is undefined.
17634 * The content box is guaranteed to be, at most, as big as the allocation
17635 * of the #ClutterActor.
17637 * If the #ClutterContent used by the actor has a preferred size, then
17638 * it is possible to modify the content box by using the
17639 * #ClutterActor:content-gravity property.
17644 clutter_actor_get_content_box (ClutterActor *self,
17645 ClutterActorBox *box)
17647 ClutterActorPrivate *priv;
17648 gfloat content_w, content_h;
17649 gfloat alloc_w, alloc_h;
17651 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17652 g_return_if_fail (box != NULL);
17656 if (!clutter_actor_has_allocation (self))
17661 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17662 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17664 if (priv->content == NULL)
17667 /* no need to do any more work */
17668 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17671 /* if the content does not have a preferred size then there is
17672 * no point in computing the content box
17674 if (!clutter_content_get_preferred_size (priv->content,
17682 switch (priv->content_gravity)
17684 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17685 box->x2 = box->x1 + MIN (content_w, alloc_w);
17686 box->y2 = box->y1 + MIN (content_h, alloc_h);
17689 case CLUTTER_CONTENT_GRAVITY_TOP:
17690 if (alloc_w > content_w)
17692 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17693 box->x2 = box->x1 + content_w;
17695 box->y2 = box->y1 + MIN (content_h, alloc_h);
17698 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17699 if (alloc_w > content_w)
17701 box->x1 += (alloc_w - content_w);
17702 box->x2 = box->x1 + content_w;
17704 box->y2 = box->y1 + MIN (content_h, alloc_h);
17707 case CLUTTER_CONTENT_GRAVITY_LEFT:
17708 box->x2 = box->x1 + MIN (content_w, alloc_w);
17709 if (alloc_h > content_h)
17711 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17712 box->y2 = box->y1 + content_h;
17716 case CLUTTER_CONTENT_GRAVITY_CENTER:
17717 if (alloc_w > content_w)
17719 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17720 box->x2 = box->x1 + content_w;
17722 if (alloc_h > content_h)
17724 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17725 box->y2 = box->y1 + content_h;
17729 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17730 if (alloc_w > content_w)
17732 box->x1 += (alloc_w - content_w);
17733 box->x2 = box->x1 + content_w;
17735 if (alloc_h > content_h)
17737 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17738 box->y2 = box->y1 + content_h;
17742 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17743 box->x2 = box->x1 + MIN (content_w, alloc_w);
17744 if (alloc_h > content_h)
17746 box->y1 += (alloc_h - content_h);
17747 box->y2 = box->y1 + content_h;
17751 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17752 if (alloc_w > content_w)
17754 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17755 box->x2 = box->x1 + content_w;
17757 if (alloc_h > content_h)
17759 box->y1 += (alloc_h - content_h);
17760 box->y2 = box->y1 + content_h;
17764 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17765 if (alloc_w > content_w)
17767 box->x1 += (alloc_w - content_w);
17768 box->x2 = box->x1 + content_w;
17770 if (alloc_h > content_h)
17772 box->y1 += (alloc_h - content_h);
17773 box->y2 = box->y1 + content_h;
17777 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17778 g_assert_not_reached ();
17781 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17783 double r_c = content_w / content_h;
17784 double r_a = alloc_w / alloc_h;
17793 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17794 box->y2 = box->y1 + (alloc_w * r_c);
17801 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17802 box->x2 = box->x1 + (alloc_h * r_c);
17812 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17813 box->x2 = box->x1 + (alloc_h * r_c);
17820 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17821 box->y2 = box->y1 + (alloc_w * r_c);
17830 * clutter_actor_set_content_scaling_filters:
17831 * @self: a #ClutterActor
17832 * @min_filter: the minification filter for the content
17833 * @mag_filter: the magnification filter for the content
17835 * Sets the minification and magnification filter to be applied when
17836 * scaling the #ClutterActor:content of a #ClutterActor.
17838 * The #ClutterActor:minification-filter will be used when reducing
17839 * the size of the content; the #ClutterActor:magnification-filter
17840 * will be used when increasing the size of the content.
17845 clutter_actor_set_content_scaling_filters (ClutterActor *self,
17846 ClutterScalingFilter min_filter,
17847 ClutterScalingFilter mag_filter)
17849 ClutterActorPrivate *priv;
17853 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17856 obj = G_OBJECT (self);
17858 g_object_freeze_notify (obj);
17862 if (priv->min_filter != min_filter)
17864 priv->min_filter = min_filter;
17867 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17870 if (priv->mag_filter != mag_filter)
17872 priv->mag_filter = mag_filter;
17875 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17879 clutter_actor_queue_redraw (self);
17881 g_object_thaw_notify (obj);
17885 * clutter_actor_get_content_scaling_filters:
17886 * @self: a #ClutterActor
17887 * @min_filter: (out) (allow-none): return location for the minification
17889 * @mag_filter: (out) (allow-none): return location for the magnification
17892 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17897 clutter_actor_get_content_scaling_filters (ClutterActor *self,
17898 ClutterScalingFilter *min_filter,
17899 ClutterScalingFilter *mag_filter)
17901 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17903 if (min_filter != NULL)
17904 *min_filter = self->priv->min_filter;
17906 if (mag_filter != NULL)
17907 *mag_filter = self->priv->mag_filter;