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);
3260 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3266 * clutter_actor_paint:
3267 * @self: A #ClutterActor
3269 * Renders the actor to display.
3271 * This function should not be called directly by applications.
3272 * Call clutter_actor_queue_redraw() to queue paints, instead.
3274 * This function is context-aware, and will either cause a
3275 * regular paint or a pick paint.
3277 * This function will emit the #ClutterActor::paint signal or
3278 * the #ClutterActor::pick signal, depending on the context.
3280 * This function does not paint the actor if the actor is set to 0,
3281 * unless it is performing a pick paint.
3284 clutter_actor_paint (ClutterActor *self)
3286 ClutterActorPrivate *priv;
3287 ClutterPickMode pick_mode;
3288 gboolean clip_set = FALSE;
3289 gboolean shader_applied = FALSE;
3291 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3292 "Actor real-paint counter",
3293 "Increments each time any actor is painted",
3294 0 /* no application private data */);
3295 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3296 "Actor pick-paint counter",
3297 "Increments each time any actor is painted "
3299 0 /* no application private data */);
3301 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3303 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3308 pick_mode = _clutter_context_get_pick_mode ();
3310 if (pick_mode == CLUTTER_PICK_NONE)
3311 priv->propagated_one_redraw = FALSE;
3313 /* It's an important optimization that we consider painting of
3314 * actors with 0 opacity to be a NOP... */
3315 if (pick_mode == CLUTTER_PICK_NONE &&
3316 /* ignore top-levels, since they might be transparent */
3317 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3318 /* Use the override opacity if its been set */
3319 ((priv->opacity_override >= 0) ?
3320 priv->opacity_override : priv->opacity) == 0)
3323 /* if we aren't paintable (not in a toplevel with all
3324 * parents paintable) then do nothing.
3326 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3329 /* mark that we are in the paint process */
3330 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3334 if (priv->enable_model_view_transform)
3338 /* XXX: It could be better to cache the modelview with the actor
3339 * instead of progressively building up the transformations on
3340 * the matrix stack every time we paint. */
3341 cogl_get_modelview_matrix (&matrix);
3342 _clutter_actor_apply_modelview_transform (self, &matrix);
3344 #ifdef CLUTTER_ENABLE_DEBUG
3345 /* Catch when out-of-band transforms have been made by actors not as part
3346 * of an apply_transform vfunc... */
3347 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3349 CoglMatrix expected_matrix;
3351 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3354 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3356 GString *buf = g_string_sized_new (1024);
3357 ClutterActor *parent;
3360 while (parent != NULL)
3362 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3364 if (parent->priv->parent != NULL)
3365 g_string_append (buf, "->");
3367 parent = parent->priv->parent;
3370 g_warning ("Unexpected transform found when painting actor "
3371 "\"%s\". This will be caused by one of the actor's "
3372 "ancestors (%s) using the Cogl API directly to transform "
3373 "children instead of using ::apply_transform().",
3374 _clutter_actor_get_debug_name (self),
3377 g_string_free (buf, TRUE);
3380 #endif /* CLUTTER_ENABLE_DEBUG */
3382 cogl_set_modelview_matrix (&matrix);
3387 cogl_clip_push_rectangle (priv->clip.x,
3389 priv->clip.x + priv->clip.width,
3390 priv->clip.y + priv->clip.height);
3393 else if (priv->clip_to_allocation)
3395 gfloat width, height;
3397 width = priv->allocation.x2 - priv->allocation.x1;
3398 height = priv->allocation.y2 - priv->allocation.y1;
3400 cogl_clip_push_rectangle (0, 0, width, height);
3404 if (pick_mode == CLUTTER_PICK_NONE)
3406 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3408 /* We check whether we need to add the flatten effect before
3409 each paint so that we can avoid having a mechanism for
3410 applications to notify when the value of the
3411 has_overlaps virtual changes. */
3412 add_or_remove_flatten_effect (self);
3415 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3417 /* We save the current paint volume so that the next time the
3418 * actor queues a redraw we can constrain the redraw to just
3419 * cover the union of the new bounding box and the old.
3421 * We also fetch the current paint volume to perform culling so
3422 * we can avoid painting actors outside the current clip region.
3424 * If we are painting inside a clone, we should neither update
3425 * the paint volume or use it to cull painting, since the paint
3426 * box represents the location of the source actor on the
3429 * XXX: We are starting to do a lot of vertex transforms on
3430 * the CPU in a typical paint, so at some point we should
3431 * audit these and consider caching some things.
3433 * NB: We don't perform culling while picking at this point because
3434 * clutter-stage.c doesn't setup the clipping planes appropriately.
3436 * NB: We don't want to update the last-paint-volume during picking
3437 * because the last-paint-volume is used to determine the old screen
3438 * space location of an actor that has moved so we can know the
3439 * minimal region to redraw to clear an old view of the actor. If we
3440 * update this during picking then by the time we come around to
3441 * paint then the last-paint-volume would likely represent the new
3442 * actor position not the old.
3444 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3447 /* annoyingly gcc warns if uninitialized even though
3448 * the initialization is redundant :-( */
3449 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3451 if (G_LIKELY ((clutter_paint_debug_flags &
3452 (CLUTTER_DEBUG_DISABLE_CULLING |
3453 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3454 (CLUTTER_DEBUG_DISABLE_CULLING |
3455 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3456 _clutter_actor_update_last_paint_volume (self);
3458 success = cull_actor (self, &result);
3460 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3461 _clutter_actor_paint_cull_result (self, success, result);
3462 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3466 if (priv->effects == NULL)
3468 if (pick_mode == CLUTTER_PICK_NONE &&
3469 actor_has_shader_data (self))
3471 _clutter_actor_shader_pre_paint (self, FALSE);
3472 shader_applied = TRUE;
3475 priv->next_effect_to_paint = NULL;
3478 priv->next_effect_to_paint =
3479 _clutter_meta_group_peek_metas (priv->effects);
3481 clutter_actor_continue_paint (self);
3484 _clutter_actor_shader_post_paint (self);
3486 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3487 pick_mode == CLUTTER_PICK_NONE))
3488 _clutter_actor_draw_paint_volume (self);
3491 /* If we make it here then the actor has run through a complete
3492 paint run including all the effects so it's no longer dirty */
3493 if (pick_mode == CLUTTER_PICK_NONE)
3494 priv->is_dirty = FALSE;
3501 /* paint sequence complete */
3502 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3506 * clutter_actor_continue_paint:
3507 * @self: A #ClutterActor
3509 * Run the next stage of the paint sequence. This function should only
3510 * be called within the implementation of the ‘run’ virtual of a
3511 * #ClutterEffect. It will cause the run method of the next effect to
3512 * be applied, or it will paint the actual actor if the current effect
3513 * is the last effect in the chain.
3518 clutter_actor_continue_paint (ClutterActor *self)
3520 ClutterActorPrivate *priv;
3522 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3523 /* This should only be called from with in the ‘run’ implementation
3524 of a ClutterEffect */
3525 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3529 /* Skip any effects that are disabled */
3530 while (priv->next_effect_to_paint &&
3531 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3532 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3534 /* If this has come from the last effect then we'll just paint the
3536 if (priv->next_effect_to_paint == NULL)
3538 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3540 ClutterPaintNode *dummy;
3541 gboolean emit_paint;
3543 /* XXX - this will go away in 2.0, when we can get rid of this
3544 * stuff and switch to a pure retained render tree of PaintNodes
3545 * for the entire frame, starting from the Stage.
3547 dummy = _clutter_dummy_node_new ();
3548 clutter_paint_node_set_name (dummy, "Root");
3549 emit_paint = !clutter_actor_paint_node (self, dummy);
3550 clutter_paint_node_unref (dummy);
3552 if (emit_paint || CLUTTER_ACTOR_IS_TOPLEVEL (self))
3553 g_signal_emit (self, actor_signals[PAINT], 0);
3556 CLUTTER_NOTE (PAINT, "The actor '%s' painted using PaintNodes, "
3557 "skipping the emission of the paint signal.",
3558 _clutter_actor_get_debug_name (self));
3563 ClutterColor col = { 0, };
3565 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3567 /* Actor will then paint silhouette of itself in supplied
3568 * color. See clutter_stage_get_actor_at_pos() for where
3569 * picking is enabled.
3571 g_signal_emit (self, actor_signals[PICK], 0, &col);
3576 ClutterEffect *old_current_effect;
3577 ClutterEffectPaintFlags run_flags = 0;
3579 /* Cache the current effect so that we can put it back before
3581 old_current_effect = priv->current_effect;
3583 priv->current_effect = priv->next_effect_to_paint->data;
3584 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3586 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3590 /* If there's an effect queued with this redraw then all
3591 effects up to that one will be considered dirty. It
3592 is expected the queued effect will paint the cached
3593 image and not call clutter_actor_continue_paint again
3594 (although it should work ok if it does) */
3595 if (priv->effect_to_redraw == NULL ||
3596 priv->current_effect != priv->effect_to_redraw)
3597 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3600 _clutter_effect_paint (priv->current_effect, run_flags);
3604 /* We can't determine when an actor has been modified since
3605 its last pick so lets just assume it has always been
3607 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3609 _clutter_effect_pick (priv->current_effect, run_flags);
3612 priv->current_effect = old_current_effect;
3616 static ClutterActorTraverseVisitFlags
3617 invalidate_queue_redraw_entry (ClutterActor *self,
3621 ClutterActorPrivate *priv = self->priv;
3623 if (priv->queue_redraw_entry != NULL)
3625 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3626 priv->queue_redraw_entry = NULL;
3629 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3633 remove_child (ClutterActor *self,
3634 ClutterActor *child)
3636 ClutterActor *prev_sibling, *next_sibling;
3638 prev_sibling = child->priv->prev_sibling;
3639 next_sibling = child->priv->next_sibling;
3641 if (prev_sibling != NULL)
3642 prev_sibling->priv->next_sibling = next_sibling;
3644 if (next_sibling != NULL)
3645 next_sibling->priv->prev_sibling = prev_sibling;
3647 if (self->priv->first_child == child)
3648 self->priv->first_child = next_sibling;
3650 if (self->priv->last_child == child)
3651 self->priv->last_child = prev_sibling;
3653 child->priv->parent = NULL;
3654 child->priv->prev_sibling = NULL;
3655 child->priv->next_sibling = NULL;
3659 REMOVE_CHILD_DESTROY_META = 1 << 0,
3660 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3661 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3662 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3663 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3664 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3666 /* default flags for public API */
3667 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3668 REMOVE_CHILD_EMIT_PARENT_SET |
3669 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3670 REMOVE_CHILD_CHECK_STATE |
3671 REMOVE_CHILD_FLUSH_QUEUE |
3672 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3674 /* flags for legacy/deprecated API */
3675 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3676 REMOVE_CHILD_FLUSH_QUEUE |
3677 REMOVE_CHILD_EMIT_PARENT_SET |
3678 REMOVE_CHILD_NOTIFY_FIRST_LAST
3679 } ClutterActorRemoveChildFlags;
3682 * clutter_actor_remove_child_internal:
3683 * @self: a #ClutterActor
3684 * @child: the child of @self that has to be removed
3685 * @flags: control the removal operations
3687 * Removes @child from the list of children of @self.
3690 clutter_actor_remove_child_internal (ClutterActor *self,
3691 ClutterActor *child,
3692 ClutterActorRemoveChildFlags flags)
3694 ClutterActor *old_first, *old_last;
3695 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3696 gboolean flush_queue;
3697 gboolean notify_first_last;
3698 gboolean was_mapped;
3700 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3701 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3702 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3703 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3704 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3705 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3707 g_object_freeze_notify (G_OBJECT (self));
3710 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3714 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3716 /* we need to unrealize *before* we set parent_actor to NULL,
3717 * because in an unrealize method actors are dissociating from the
3718 * stage, which means they need to be able to
3719 * clutter_actor_get_stage().
3721 * yhis should unmap and unrealize, unless we're reparenting.
3723 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3730 /* We take this opportunity to invalidate any queue redraw entry
3731 * associated with the actor and descendants since we won't be able to
3732 * determine the appropriate stage after this.
3734 * we do this after we updated the mapped state because actors might
3735 * end up queueing redraws inside their mapped/unmapped virtual
3736 * functions, and if we invalidate the redraw entry we could end up
3737 * with an inconsistent state and weird memory corruption. see
3740 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3741 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3743 _clutter_actor_traverse (child,
3745 invalidate_queue_redraw_entry,
3750 old_first = self->priv->first_child;
3751 old_last = self->priv->last_child;
3753 remove_child (self, child);
3755 self->priv->n_children -= 1;
3757 self->priv->age += 1;
3759 /* clutter_actor_reparent() will emit ::parent-set for us */
3760 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3761 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3763 /* if the child was mapped then we need to relayout ourselves to account
3764 * for the removed child
3767 clutter_actor_queue_relayout (self);
3769 /* we need to emit the signal before dropping the reference */
3770 if (emit_actor_removed)
3771 g_signal_emit_by_name (self, "actor-removed", child);
3773 if (notify_first_last)
3775 if (old_first != self->priv->first_child)
3776 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3778 if (old_last != self->priv->last_child)
3779 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3782 g_object_thaw_notify (G_OBJECT (self));
3784 /* remove the reference we acquired in clutter_actor_add_child() */
3785 g_object_unref (child);
3788 static const ClutterTransformInfo default_transform_info = {
3789 0.0, { 0, }, /* rotation-x */
3790 0.0, { 0, }, /* rotation-y */
3791 0.0, { 0, }, /* rotation-z */
3793 1.0, 1.0, { 0, }, /* scale */
3795 { 0, }, /* anchor */
3801 * _clutter_actor_get_transform_info_or_defaults:
3802 * @self: a #ClutterActor
3804 * Retrieves the ClutterTransformInfo structure associated to an actor.
3806 * If the actor does not have a ClutterTransformInfo structure associated
3807 * to it, then the default structure will be returned.
3809 * This function should only be used for getters.
3811 * Return value: a const pointer to the ClutterTransformInfo structure
3813 const ClutterTransformInfo *
3814 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3816 ClutterTransformInfo *info;
3818 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3822 return &default_transform_info;
3826 clutter_transform_info_free (gpointer data)
3829 g_slice_free (ClutterTransformInfo, data);
3833 * _clutter_actor_get_transform_info:
3834 * @self: a #ClutterActor
3836 * Retrieves a pointer to the ClutterTransformInfo structure.
3838 * If the actor does not have a ClutterTransformInfo associated to it, one
3839 * will be created and initialized to the default values.
3841 * This function should be used for setters.
3843 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3846 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3849 ClutterTransformInfo *
3850 _clutter_actor_get_transform_info (ClutterActor *self)
3852 ClutterTransformInfo *info;
3854 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3857 info = g_slice_new (ClutterTransformInfo);
3859 *info = default_transform_info;
3861 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3863 clutter_transform_info_free);
3870 * clutter_actor_set_rotation_angle_internal:
3871 * @self: a #ClutterActor
3872 * @axis: the axis of the angle to change
3873 * @angle: the angle of rotation
3875 * Sets the rotation angle on the given axis without affecting the
3876 * rotation center point.
3879 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3880 ClutterRotateAxis axis,
3883 GObject *obj = G_OBJECT (self);
3884 ClutterTransformInfo *info;
3886 info = _clutter_actor_get_transform_info (self);
3888 g_object_freeze_notify (obj);
3892 case CLUTTER_X_AXIS:
3893 info->rx_angle = angle;
3894 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3897 case CLUTTER_Y_AXIS:
3898 info->ry_angle = angle;
3899 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3902 case CLUTTER_Z_AXIS:
3903 info->rz_angle = angle;
3904 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3908 self->priv->transform_valid = FALSE;
3910 g_object_thaw_notify (obj);
3912 clutter_actor_queue_redraw (self);
3916 clutter_actor_set_rotation_angle (ClutterActor *self,
3917 ClutterRotateAxis axis,
3920 ClutterTransformInfo *info;
3922 info = _clutter_actor_get_transform_info (self);
3924 if (clutter_actor_get_easing_duration (self) != 0)
3926 ClutterTransition *transition;
3927 GParamSpec *pspec = NULL;
3928 double *cur_angle_p = NULL;
3932 case CLUTTER_X_AXIS:
3933 cur_angle_p = &info->rx_angle;
3934 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3937 case CLUTTER_Y_AXIS:
3938 cur_angle_p = &info->ry_angle;
3939 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3942 case CLUTTER_Z_AXIS:
3943 cur_angle_p = &info->rz_angle;
3944 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3948 g_assert (pspec != NULL);
3949 g_assert (cur_angle_p != NULL);
3951 transition = _clutter_actor_get_transition (self, pspec);
3952 if (transition == NULL)
3954 transition = _clutter_actor_create_transition (self, pspec,
3957 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3960 _clutter_actor_update_transition (self, pspec, angle);
3962 self->priv->transform_valid = FALSE;
3963 clutter_actor_queue_redraw (self);
3966 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3970 * clutter_actor_set_rotation_center_internal:
3971 * @self: a #ClutterActor
3972 * @axis: the axis of the center to change
3973 * @center: the coordinates of the rotation center
3975 * Sets the rotation center on the given axis without affecting the
3979 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3980 ClutterRotateAxis axis,
3981 const ClutterVertex *center)
3983 GObject *obj = G_OBJECT (self);
3984 ClutterTransformInfo *info;
3985 ClutterVertex v = { 0, 0, 0 };
3987 info = _clutter_actor_get_transform_info (self);
3992 g_object_freeze_notify (obj);
3996 case CLUTTER_X_AXIS:
3997 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
3998 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4001 case CLUTTER_Y_AXIS:
4002 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4003 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4006 case CLUTTER_Z_AXIS:
4007 /* if the previously set rotation center was fractional, then
4008 * setting explicit coordinates will have to notify the
4009 * :rotation-center-z-gravity property as well
4011 if (info->rz_center.is_fractional)
4012 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4014 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4015 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4019 self->priv->transform_valid = FALSE;
4021 g_object_thaw_notify (obj);
4023 clutter_actor_queue_redraw (self);
4027 clutter_actor_animate_scale_factor (ClutterActor *self,
4032 ClutterTransition *transition;
4034 transition = _clutter_actor_get_transition (self, pspec);
4035 if (transition == NULL)
4037 transition = _clutter_actor_create_transition (self, pspec,
4040 clutter_timeline_start (CLUTTER_TIMELINE (transition));
4043 _clutter_actor_update_transition (self, pspec, new_factor);
4046 self->priv->transform_valid = FALSE;
4047 clutter_actor_queue_redraw (self);
4051 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4055 GObject *obj = G_OBJECT (self);
4056 ClutterTransformInfo *info;
4058 info = _clutter_actor_get_transform_info (self);
4060 if (pspec == obj_props[PROP_SCALE_X])
4061 info->scale_x = factor;
4063 info->scale_y = factor;
4065 self->priv->transform_valid = FALSE;
4066 clutter_actor_queue_redraw (self);
4067 g_object_notify_by_pspec (obj, pspec);
4071 clutter_actor_set_scale_factor (ClutterActor *self,
4072 ClutterRotateAxis axis,
4075 GObject *obj = G_OBJECT (self);
4076 ClutterTransformInfo *info;
4079 info = _clutter_actor_get_transform_info (self);
4081 g_object_freeze_notify (obj);
4085 case CLUTTER_X_AXIS:
4086 pspec = obj_props[PROP_SCALE_X];
4088 if (clutter_actor_get_easing_duration (self) != 0)
4089 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4091 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4094 case CLUTTER_Y_AXIS:
4095 pspec = obj_props[PROP_SCALE_Y];
4097 if (clutter_actor_get_easing_duration (self) != 0)
4098 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4100 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4104 g_assert_not_reached ();
4107 g_object_thaw_notify (obj);
4111 clutter_actor_set_scale_center (ClutterActor *self,
4112 ClutterRotateAxis axis,
4115 GObject *obj = G_OBJECT (self);
4116 ClutterTransformInfo *info;
4117 gfloat center_x, center_y;
4119 info = _clutter_actor_get_transform_info (self);
4121 g_object_freeze_notify (obj);
4123 /* get the current scale center coordinates */
4124 clutter_anchor_coord_get_units (self, &info->scale_center,
4129 /* we need to notify this too, because setting explicit coordinates will
4130 * change the gravity as a side effect
4132 if (info->scale_center.is_fractional)
4133 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4137 case CLUTTER_X_AXIS:
4138 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4139 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4142 case CLUTTER_Y_AXIS:
4143 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4144 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4148 g_assert_not_reached ();
4151 self->priv->transform_valid = FALSE;
4153 clutter_actor_queue_redraw (self);
4155 g_object_thaw_notify (obj);
4159 clutter_actor_set_anchor_coord (ClutterActor *self,
4160 ClutterRotateAxis axis,
4163 GObject *obj = G_OBJECT (self);
4164 ClutterTransformInfo *info;
4165 gfloat anchor_x, anchor_y;
4167 info = _clutter_actor_get_transform_info (self);
4169 g_object_freeze_notify (obj);
4171 clutter_anchor_coord_get_units (self, &info->anchor,
4176 if (info->anchor.is_fractional)
4177 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4181 case CLUTTER_X_AXIS:
4182 clutter_anchor_coord_set_units (&info->anchor,
4186 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4189 case CLUTTER_Y_AXIS:
4190 clutter_anchor_coord_set_units (&info->anchor,
4194 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4198 g_assert_not_reached ();
4201 self->priv->transform_valid = FALSE;
4203 clutter_actor_queue_redraw (self);
4205 g_object_thaw_notify (obj);
4209 clutter_actor_set_property (GObject *object,
4211 const GValue *value,
4214 ClutterActor *actor = CLUTTER_ACTOR (object);
4215 ClutterActorPrivate *priv = actor->priv;
4220 clutter_actor_set_x (actor, g_value_get_float (value));
4224 clutter_actor_set_y (actor, g_value_get_float (value));
4228 clutter_actor_set_width (actor, g_value_get_float (value));
4232 clutter_actor_set_height (actor, g_value_get_float (value));
4236 clutter_actor_set_x (actor, g_value_get_float (value));
4240 clutter_actor_set_y (actor, g_value_get_float (value));
4243 case PROP_FIXED_POSITION_SET:
4244 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4247 case PROP_MIN_WIDTH:
4248 clutter_actor_set_min_width (actor, g_value_get_float (value));
4251 case PROP_MIN_HEIGHT:
4252 clutter_actor_set_min_height (actor, g_value_get_float (value));
4255 case PROP_NATURAL_WIDTH:
4256 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4259 case PROP_NATURAL_HEIGHT:
4260 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4263 case PROP_MIN_WIDTH_SET:
4264 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4267 case PROP_MIN_HEIGHT_SET:
4268 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4271 case PROP_NATURAL_WIDTH_SET:
4272 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4275 case PROP_NATURAL_HEIGHT_SET:
4276 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4279 case PROP_REQUEST_MODE:
4280 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4284 clutter_actor_set_depth (actor, g_value_get_float (value));
4288 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4291 case PROP_OFFSCREEN_REDIRECT:
4292 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4296 clutter_actor_set_name (actor, g_value_get_string (value));
4300 if (g_value_get_boolean (value) == TRUE)
4301 clutter_actor_show (actor);
4303 clutter_actor_hide (actor);
4307 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4308 g_value_get_double (value));
4312 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4313 g_value_get_double (value));
4316 case PROP_SCALE_CENTER_X:
4317 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4318 g_value_get_float (value));
4321 case PROP_SCALE_CENTER_Y:
4322 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4323 g_value_get_float (value));
4326 case PROP_SCALE_GRAVITY:
4328 const ClutterTransformInfo *info;
4329 ClutterGravity gravity;
4331 info = _clutter_actor_get_transform_info_or_defaults (actor);
4332 gravity = g_value_get_enum (value);
4334 clutter_actor_set_scale_with_gravity (actor,
4343 const ClutterGeometry *geom = g_value_get_boxed (value);
4345 clutter_actor_set_clip (actor,
4347 geom->width, geom->height);
4351 case PROP_CLIP_TO_ALLOCATION:
4352 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4356 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4359 case PROP_ROTATION_ANGLE_X:
4360 clutter_actor_set_rotation_angle (actor,
4362 g_value_get_double (value));
4365 case PROP_ROTATION_ANGLE_Y:
4366 clutter_actor_set_rotation_angle (actor,
4368 g_value_get_double (value));
4371 case PROP_ROTATION_ANGLE_Z:
4372 clutter_actor_set_rotation_angle (actor,
4374 g_value_get_double (value));
4377 case PROP_ROTATION_CENTER_X:
4378 clutter_actor_set_rotation_center_internal (actor,
4380 g_value_get_boxed (value));
4383 case PROP_ROTATION_CENTER_Y:
4384 clutter_actor_set_rotation_center_internal (actor,
4386 g_value_get_boxed (value));
4389 case PROP_ROTATION_CENTER_Z:
4390 clutter_actor_set_rotation_center_internal (actor,
4392 g_value_get_boxed (value));
4395 case PROP_ROTATION_CENTER_Z_GRAVITY:
4397 const ClutterTransformInfo *info;
4399 info = _clutter_actor_get_transform_info_or_defaults (actor);
4400 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4401 g_value_get_enum (value));
4406 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4407 g_value_get_float (value));
4411 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4412 g_value_get_float (value));
4415 case PROP_ANCHOR_GRAVITY:
4416 clutter_actor_set_anchor_point_from_gravity (actor,
4417 g_value_get_enum (value));
4420 case PROP_SHOW_ON_SET_PARENT:
4421 priv->show_on_set_parent = g_value_get_boolean (value);
4424 case PROP_TEXT_DIRECTION:
4425 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4429 clutter_actor_add_action (actor, g_value_get_object (value));
4432 case PROP_CONSTRAINTS:
4433 clutter_actor_add_constraint (actor, g_value_get_object (value));
4437 clutter_actor_add_effect (actor, g_value_get_object (value));
4440 case PROP_LAYOUT_MANAGER:
4441 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4445 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4449 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4452 case PROP_MARGIN_TOP:
4453 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4456 case PROP_MARGIN_BOTTOM:
4457 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4460 case PROP_MARGIN_LEFT:
4461 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4464 case PROP_MARGIN_RIGHT:
4465 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4468 case PROP_BACKGROUND_COLOR:
4469 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4473 clutter_actor_set_content (actor, g_value_get_object (value));
4476 case PROP_CONTENT_GRAVITY:
4477 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4480 case PROP_MINIFICATION_FILTER:
4481 clutter_actor_set_content_scaling_filters (actor,
4482 g_value_get_enum (value),
4483 actor->priv->mag_filter);
4486 case PROP_MAGNIFICATION_FILTER:
4487 clutter_actor_set_content_scaling_filters (actor,
4488 actor->priv->min_filter,
4489 g_value_get_enum (value));
4493 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4499 clutter_actor_get_property (GObject *object,
4504 ClutterActor *actor = CLUTTER_ACTOR (object);
4505 ClutterActorPrivate *priv = actor->priv;
4510 g_value_set_float (value, clutter_actor_get_x (actor));
4514 g_value_set_float (value, clutter_actor_get_y (actor));
4518 g_value_set_float (value, clutter_actor_get_width (actor));
4522 g_value_set_float (value, clutter_actor_get_height (actor));
4527 const ClutterLayoutInfo *info;
4529 info = _clutter_actor_get_layout_info_or_defaults (actor);
4530 g_value_set_float (value, info->fixed_x);
4536 const ClutterLayoutInfo *info;
4538 info = _clutter_actor_get_layout_info_or_defaults (actor);
4539 g_value_set_float (value, info->fixed_y);
4543 case PROP_FIXED_POSITION_SET:
4544 g_value_set_boolean (value, priv->position_set);
4547 case PROP_MIN_WIDTH:
4549 const ClutterLayoutInfo *info;
4551 info = _clutter_actor_get_layout_info_or_defaults (actor);
4552 g_value_set_float (value, info->min_width);
4556 case PROP_MIN_HEIGHT:
4558 const ClutterLayoutInfo *info;
4560 info = _clutter_actor_get_layout_info_or_defaults (actor);
4561 g_value_set_float (value, info->min_height);
4565 case PROP_NATURAL_WIDTH:
4567 const ClutterLayoutInfo *info;
4569 info = _clutter_actor_get_layout_info_or_defaults (actor);
4570 g_value_set_float (value, info->natural_width);
4574 case PROP_NATURAL_HEIGHT:
4576 const ClutterLayoutInfo *info;
4578 info = _clutter_actor_get_layout_info_or_defaults (actor);
4579 g_value_set_float (value, info->natural_height);
4583 case PROP_MIN_WIDTH_SET:
4584 g_value_set_boolean (value, priv->min_width_set);
4587 case PROP_MIN_HEIGHT_SET:
4588 g_value_set_boolean (value, priv->min_height_set);
4591 case PROP_NATURAL_WIDTH_SET:
4592 g_value_set_boolean (value, priv->natural_width_set);
4595 case PROP_NATURAL_HEIGHT_SET:
4596 g_value_set_boolean (value, priv->natural_height_set);
4599 case PROP_REQUEST_MODE:
4600 g_value_set_enum (value, priv->request_mode);
4603 case PROP_ALLOCATION:
4604 g_value_set_boxed (value, &priv->allocation);
4608 g_value_set_float (value, clutter_actor_get_depth (actor));
4612 g_value_set_uint (value, priv->opacity);
4615 case PROP_OFFSCREEN_REDIRECT:
4616 g_value_set_enum (value, priv->offscreen_redirect);
4620 g_value_set_string (value, priv->name);
4624 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4628 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4632 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4636 g_value_set_boolean (value, priv->has_clip);
4641 ClutterGeometry clip;
4643 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4644 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4645 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4646 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4648 g_value_set_boxed (value, &clip);
4652 case PROP_CLIP_TO_ALLOCATION:
4653 g_value_set_boolean (value, priv->clip_to_allocation);
4658 const ClutterTransformInfo *info;
4660 info = _clutter_actor_get_transform_info_or_defaults (actor);
4661 g_value_set_double (value, info->scale_x);
4667 const ClutterTransformInfo *info;
4669 info = _clutter_actor_get_transform_info_or_defaults (actor);
4670 g_value_set_double (value, info->scale_y);
4674 case PROP_SCALE_CENTER_X:
4678 clutter_actor_get_scale_center (actor, ¢er, NULL);
4680 g_value_set_float (value, center);
4684 case PROP_SCALE_CENTER_Y:
4688 clutter_actor_get_scale_center (actor, NULL, ¢er);
4690 g_value_set_float (value, center);
4694 case PROP_SCALE_GRAVITY:
4695 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4699 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4702 case PROP_ROTATION_ANGLE_X:
4704 const ClutterTransformInfo *info;
4706 info = _clutter_actor_get_transform_info_or_defaults (actor);
4707 g_value_set_double (value, info->rx_angle);
4711 case PROP_ROTATION_ANGLE_Y:
4713 const ClutterTransformInfo *info;
4715 info = _clutter_actor_get_transform_info_or_defaults (actor);
4716 g_value_set_double (value, info->ry_angle);
4720 case PROP_ROTATION_ANGLE_Z:
4722 const ClutterTransformInfo *info;
4724 info = _clutter_actor_get_transform_info_or_defaults (actor);
4725 g_value_set_double (value, info->rz_angle);
4729 case PROP_ROTATION_CENTER_X:
4731 ClutterVertex center;
4733 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4738 g_value_set_boxed (value, ¢er);
4742 case PROP_ROTATION_CENTER_Y:
4744 ClutterVertex center;
4746 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4751 g_value_set_boxed (value, ¢er);
4755 case PROP_ROTATION_CENTER_Z:
4757 ClutterVertex center;
4759 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4764 g_value_set_boxed (value, ¢er);
4768 case PROP_ROTATION_CENTER_Z_GRAVITY:
4769 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4774 const ClutterTransformInfo *info;
4777 info = _clutter_actor_get_transform_info_or_defaults (actor);
4778 clutter_anchor_coord_get_units (actor, &info->anchor,
4782 g_value_set_float (value, anchor_x);
4788 const ClutterTransformInfo *info;
4791 info = _clutter_actor_get_transform_info_or_defaults (actor);
4792 clutter_anchor_coord_get_units (actor, &info->anchor,
4796 g_value_set_float (value, anchor_y);
4800 case PROP_ANCHOR_GRAVITY:
4801 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4804 case PROP_SHOW_ON_SET_PARENT:
4805 g_value_set_boolean (value, priv->show_on_set_parent);
4808 case PROP_TEXT_DIRECTION:
4809 g_value_set_enum (value, priv->text_direction);
4812 case PROP_HAS_POINTER:
4813 g_value_set_boolean (value, priv->has_pointer);
4816 case PROP_LAYOUT_MANAGER:
4817 g_value_set_object (value, priv->layout_manager);
4822 const ClutterLayoutInfo *info;
4824 info = _clutter_actor_get_layout_info_or_defaults (actor);
4825 g_value_set_enum (value, info->x_align);
4831 const ClutterLayoutInfo *info;
4833 info = _clutter_actor_get_layout_info_or_defaults (actor);
4834 g_value_set_enum (value, info->y_align);
4838 case PROP_MARGIN_TOP:
4840 const ClutterLayoutInfo *info;
4842 info = _clutter_actor_get_layout_info_or_defaults (actor);
4843 g_value_set_float (value, info->margin.top);
4847 case PROP_MARGIN_BOTTOM:
4849 const ClutterLayoutInfo *info;
4851 info = _clutter_actor_get_layout_info_or_defaults (actor);
4852 g_value_set_float (value, info->margin.bottom);
4856 case PROP_MARGIN_LEFT:
4858 const ClutterLayoutInfo *info;
4860 info = _clutter_actor_get_layout_info_or_defaults (actor);
4861 g_value_set_float (value, info->margin.left);
4865 case PROP_MARGIN_RIGHT:
4867 const ClutterLayoutInfo *info;
4869 info = _clutter_actor_get_layout_info_or_defaults (actor);
4870 g_value_set_float (value, info->margin.right);
4874 case PROP_BACKGROUND_COLOR_SET:
4875 g_value_set_boolean (value, priv->bg_color_set);
4878 case PROP_BACKGROUND_COLOR:
4879 g_value_set_boxed (value, &priv->bg_color);
4882 case PROP_FIRST_CHILD:
4883 g_value_set_object (value, priv->first_child);
4886 case PROP_LAST_CHILD:
4887 g_value_set_object (value, priv->last_child);
4891 g_value_set_object (value, priv->content);
4894 case PROP_CONTENT_GRAVITY:
4895 g_value_set_enum (value, priv->content_gravity);
4898 case PROP_CONTENT_BOX:
4900 ClutterActorBox box = { 0, };
4902 clutter_actor_get_content_box (actor, &box);
4903 g_value_set_boxed (value, &box);
4907 case PROP_MINIFICATION_FILTER:
4908 g_value_set_enum (value, priv->min_filter);
4911 case PROP_MAGNIFICATION_FILTER:
4912 g_value_set_enum (value, priv->mag_filter);
4916 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4922 clutter_actor_dispose (GObject *object)
4924 ClutterActor *self = CLUTTER_ACTOR (object);
4925 ClutterActorPrivate *priv = self->priv;
4927 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4929 g_type_name (G_OBJECT_TYPE (self)),
4932 g_signal_emit (self, actor_signals[DESTROY], 0);
4934 /* avoid recursing when called from clutter_actor_destroy() */
4935 if (priv->parent != NULL)
4937 ClutterActor *parent = priv->parent;
4939 /* go through the Container implementation unless this
4940 * is an internal child and has been marked as such.
4942 * removing the actor from its parent will reset the
4943 * realized and mapped states.
4945 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4946 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4948 clutter_actor_remove_child_internal (parent, self,
4949 REMOVE_CHILD_LEGACY_FLAGS);
4952 /* parent must be gone at this point */
4953 g_assert (priv->parent == NULL);
4955 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4957 /* can't be mapped or realized with no parent */
4958 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4959 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4962 g_clear_object (&priv->pango_context);
4963 g_clear_object (&priv->actions);
4964 g_clear_object (&priv->constraints);
4965 g_clear_object (&priv->effects);
4966 g_clear_object (&priv->flatten_effect);
4968 if (priv->layout_manager != NULL)
4970 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4971 g_clear_object (&priv->layout_manager);
4974 if (priv->content != NULL)
4976 _clutter_content_detached (priv->content, self);
4977 g_clear_object (&priv->content);
4980 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4984 clutter_actor_finalize (GObject *object)
4986 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4988 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4989 priv->name != NULL ? priv->name : "<none>",
4991 g_type_name (G_OBJECT_TYPE (object)));
4993 _clutter_context_release_id (priv->id);
4995 g_free (priv->name);
4997 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5002 * clutter_actor_get_accessible:
5003 * @self: a #ClutterActor
5005 * Returns the accessible object that describes the actor to an
5006 * assistive technology.
5008 * If no class-specific #AtkObject implementation is available for the
5009 * actor instance in question, it will inherit an #AtkObject
5010 * implementation from the first ancestor class for which such an
5011 * implementation is defined.
5013 * The documentation of the <ulink
5014 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5015 * library contains more information about accessible objects and
5018 * Returns: (transfer none): the #AtkObject associated with @actor
5021 clutter_actor_get_accessible (ClutterActor *self)
5023 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5025 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5029 clutter_actor_real_get_accessible (ClutterActor *actor)
5031 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5035 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5037 AtkObject *accessible;
5039 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5040 if (accessible != NULL)
5041 g_object_ref (accessible);
5047 atk_implementor_iface_init (AtkImplementorIface *iface)
5049 iface->ref_accessible = _clutter_actor_ref_accessible;
5053 clutter_actor_update_default_paint_volume (ClutterActor *self,
5054 ClutterPaintVolume *volume)
5056 ClutterActorPrivate *priv = self->priv;
5057 gboolean res = FALSE;
5059 /* we start from the allocation */
5060 clutter_paint_volume_set_width (volume,
5061 priv->allocation.x2 - priv->allocation.x1);
5062 clutter_paint_volume_set_height (volume,
5063 priv->allocation.y2 - priv->allocation.y1);
5065 /* if the actor has a clip set then we have a pretty definite
5066 * size for the paint volume: the actor cannot possibly paint
5067 * outside the clip region.
5069 if (priv->clip_to_allocation)
5071 /* the allocation has already been set, so we just flip the
5078 ClutterActor *child;
5080 if (priv->has_clip &&
5081 priv->clip.width >= 0 &&
5082 priv->clip.height >= 0)
5084 ClutterVertex origin;
5086 origin.x = priv->clip.x;
5087 origin.y = priv->clip.y;
5090 clutter_paint_volume_set_origin (volume, &origin);
5091 clutter_paint_volume_set_width (volume, priv->clip.width);
5092 clutter_paint_volume_set_height (volume, priv->clip.height);
5097 /* if we don't have children we just bail out here... */
5098 if (priv->n_children == 0)
5101 /* ...but if we have children then we ask for their paint volume in
5102 * our coordinates. if any of our children replies that it doesn't
5103 * have a paint volume, we bail out
5105 for (child = priv->first_child;
5107 child = child->priv->next_sibling)
5109 const ClutterPaintVolume *child_volume;
5111 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5112 if (child_volume == NULL)
5118 clutter_paint_volume_union (volume, child_volume);
5128 clutter_actor_real_get_paint_volume (ClutterActor *self,
5129 ClutterPaintVolume *volume)
5131 ClutterActorClass *klass;
5134 klass = CLUTTER_ACTOR_GET_CLASS (self);
5136 /* XXX - this thoroughly sucks, but we don't want to penalize users
5137 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5138 * redraw. This should go away in 2.0.
5140 if (klass->paint == clutter_actor_real_paint &&
5141 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5147 /* this is the default return value: we cannot know if a class
5148 * is going to paint outside its allocation, so we take the
5149 * conservative approach.
5154 if (clutter_actor_update_default_paint_volume (self, volume))
5161 * clutter_actor_get_default_paint_volume:
5162 * @self: a #ClutterActor
5164 * Retrieves the default paint volume for @self.
5166 * This function provides the same #ClutterPaintVolume that would be
5167 * computed by the default implementation inside #ClutterActor of the
5168 * #ClutterActorClass.get_paint_volume() virtual function.
5170 * This function should only be used by #ClutterActor subclasses that
5171 * cannot chain up to the parent implementation when computing their
5174 * Return value: (transfer none): a pointer to the default
5175 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5176 * the actor could not compute a valid paint volume. The returned value
5177 * is not guaranteed to be stable across multiple frames, so if you
5178 * want to retain it, you will need to copy it using
5179 * clutter_paint_volume_copy().
5183 const ClutterPaintVolume *
5184 clutter_actor_get_default_paint_volume (ClutterActor *self)
5186 ClutterPaintVolume volume;
5187 ClutterPaintVolume *res;
5189 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5192 _clutter_paint_volume_init_static (&volume, self);
5193 if (clutter_actor_update_default_paint_volume (self, &volume))
5195 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5199 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5200 _clutter_paint_volume_copy_static (&volume, res);
5204 clutter_paint_volume_free (&volume);
5210 clutter_actor_real_has_overlaps (ClutterActor *self)
5212 /* By default we'll assume that all actors need an offscreen redirect to get
5213 * the correct opacity. Actors such as ClutterTexture that would never need
5214 * an offscreen redirect can override this to return FALSE. */
5219 clutter_actor_real_destroy (ClutterActor *actor)
5221 ClutterActorIter iter;
5223 clutter_actor_iter_init (&iter, actor);
5224 while (clutter_actor_iter_next (&iter, NULL))
5225 clutter_actor_iter_destroy (&iter);
5229 clutter_actor_constructor (GType gtype,
5231 GObjectConstructParam *props)
5233 GObjectClass *gobject_class;
5237 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5238 retval = gobject_class->constructor (gtype, n_props, props);
5239 self = CLUTTER_ACTOR (retval);
5241 if (self->priv->layout_manager == NULL)
5243 ClutterLayoutManager *default_layout;
5245 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5247 default_layout = clutter_fixed_layout_new ();
5248 clutter_actor_set_layout_manager (self, default_layout);
5255 clutter_actor_class_init (ClutterActorClass *klass)
5257 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5259 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5260 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5261 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5262 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5264 object_class->constructor = clutter_actor_constructor;
5265 object_class->set_property = clutter_actor_set_property;
5266 object_class->get_property = clutter_actor_get_property;
5267 object_class->dispose = clutter_actor_dispose;
5268 object_class->finalize = clutter_actor_finalize;
5270 klass->show = clutter_actor_real_show;
5271 klass->show_all = clutter_actor_show;
5272 klass->hide = clutter_actor_real_hide;
5273 klass->hide_all = clutter_actor_hide;
5274 klass->map = clutter_actor_real_map;
5275 klass->unmap = clutter_actor_real_unmap;
5276 klass->unrealize = clutter_actor_real_unrealize;
5277 klass->pick = clutter_actor_real_pick;
5278 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5279 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5280 klass->allocate = clutter_actor_real_allocate;
5281 klass->queue_redraw = clutter_actor_real_queue_redraw;
5282 klass->queue_relayout = clutter_actor_real_queue_relayout;
5283 klass->apply_transform = clutter_actor_real_apply_transform;
5284 klass->get_accessible = clutter_actor_real_get_accessible;
5285 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5286 klass->has_overlaps = clutter_actor_real_has_overlaps;
5287 klass->paint = clutter_actor_real_paint;
5288 klass->destroy = clutter_actor_real_destroy;
5290 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5295 * X coordinate of the actor in pixels. If written, forces a fixed
5296 * position for the actor. If read, returns the fixed position if any,
5297 * otherwise the allocation if available, otherwise 0.
5299 * The #ClutterActor:x property is animatable.
5302 g_param_spec_float ("x",
5304 P_("X coordinate of the actor"),
5305 -G_MAXFLOAT, G_MAXFLOAT,
5308 G_PARAM_STATIC_STRINGS |
5309 CLUTTER_PARAM_ANIMATABLE);
5314 * Y coordinate of the actor in pixels. If written, forces a fixed
5315 * position for the actor. If read, returns the fixed position if
5316 * any, otherwise the allocation if available, otherwise 0.
5318 * The #ClutterActor:y property is animatable.
5321 g_param_spec_float ("y",
5323 P_("Y coordinate of the actor"),
5324 -G_MAXFLOAT, G_MAXFLOAT,
5327 G_PARAM_STATIC_STRINGS |
5328 CLUTTER_PARAM_ANIMATABLE);
5331 * ClutterActor:width:
5333 * Width of the actor (in pixels). If written, forces the minimum and
5334 * natural size request of the actor to the given width. If read, returns
5335 * the allocated width if available, otherwise the width request.
5337 * The #ClutterActor:width property is animatable.
5339 obj_props[PROP_WIDTH] =
5340 g_param_spec_float ("width",
5342 P_("Width of the actor"),
5346 G_PARAM_STATIC_STRINGS |
5347 CLUTTER_PARAM_ANIMATABLE);
5350 * ClutterActor:height:
5352 * Height of the actor (in pixels). If written, forces the minimum and
5353 * natural size request of the actor to the given height. If read, returns
5354 * the allocated height if available, otherwise the height request.
5356 * The #ClutterActor:height property is animatable.
5358 obj_props[PROP_HEIGHT] =
5359 g_param_spec_float ("height",
5361 P_("Height of the actor"),
5365 G_PARAM_STATIC_STRINGS |
5366 CLUTTER_PARAM_ANIMATABLE);
5369 * ClutterActor:fixed-x:
5371 * The fixed X position of the actor in pixels.
5373 * Writing this property sets #ClutterActor:fixed-position-set
5374 * property as well, as a side effect
5378 obj_props[PROP_FIXED_X] =
5379 g_param_spec_float ("fixed-x",
5381 P_("Forced X position of the actor"),
5382 -G_MAXFLOAT, G_MAXFLOAT,
5384 CLUTTER_PARAM_READWRITE);
5387 * ClutterActor:fixed-y:
5389 * The fixed Y position of the actor in pixels.
5391 * Writing this property sets the #ClutterActor:fixed-position-set
5392 * property as well, as a side effect
5396 obj_props[PROP_FIXED_Y] =
5397 g_param_spec_float ("fixed-y",
5399 P_("Forced Y position of the actor"),
5400 -G_MAXFLOAT, G_MAXFLOAT,
5402 CLUTTER_PARAM_READWRITE);
5405 * ClutterActor:fixed-position-set:
5407 * This flag controls whether the #ClutterActor:fixed-x and
5408 * #ClutterActor:fixed-y properties are used
5412 obj_props[PROP_FIXED_POSITION_SET] =
5413 g_param_spec_boolean ("fixed-position-set",
5414 P_("Fixed position set"),
5415 P_("Whether to use fixed positioning for the actor"),
5417 CLUTTER_PARAM_READWRITE);
5420 * ClutterActor:min-width:
5422 * A forced minimum width request for the actor, in pixels
5424 * Writing this property sets the #ClutterActor:min-width-set property
5425 * as well, as a side effect.
5427 *This property overrides the usual width request of the actor.
5431 obj_props[PROP_MIN_WIDTH] =
5432 g_param_spec_float ("min-width",
5434 P_("Forced minimum width request for the actor"),
5437 CLUTTER_PARAM_READWRITE);
5440 * ClutterActor:min-height:
5442 * A forced minimum height request for the actor, in pixels
5444 * Writing this property sets the #ClutterActor:min-height-set property
5445 * as well, as a side effect. This property overrides the usual height
5446 * request of the actor.
5450 obj_props[PROP_MIN_HEIGHT] =
5451 g_param_spec_float ("min-height",
5453 P_("Forced minimum height request for the actor"),
5456 CLUTTER_PARAM_READWRITE);
5459 * ClutterActor:natural-width:
5461 * A forced natural width request for the actor, in pixels
5463 * Writing this property sets the #ClutterActor:natural-width-set
5464 * property as well, as a side effect. This property overrides the
5465 * usual width request of the actor
5469 obj_props[PROP_NATURAL_WIDTH] =
5470 g_param_spec_float ("natural-width",
5471 P_("Natural Width"),
5472 P_("Forced natural width request for the actor"),
5475 CLUTTER_PARAM_READWRITE);
5478 * ClutterActor:natural-height:
5480 * A forced natural height request for the actor, in pixels
5482 * Writing this property sets the #ClutterActor:natural-height-set
5483 * property as well, as a side effect. This property overrides the
5484 * usual height request of the actor
5488 obj_props[PROP_NATURAL_HEIGHT] =
5489 g_param_spec_float ("natural-height",
5490 P_("Natural Height"),
5491 P_("Forced natural height request for the actor"),
5494 CLUTTER_PARAM_READWRITE);
5497 * ClutterActor:min-width-set:
5499 * This flag controls whether the #ClutterActor:min-width property
5504 obj_props[PROP_MIN_WIDTH_SET] =
5505 g_param_spec_boolean ("min-width-set",
5506 P_("Minimum width set"),
5507 P_("Whether to use the min-width property"),
5509 CLUTTER_PARAM_READWRITE);
5512 * ClutterActor:min-height-set:
5514 * This flag controls whether the #ClutterActor:min-height property
5519 obj_props[PROP_MIN_HEIGHT_SET] =
5520 g_param_spec_boolean ("min-height-set",
5521 P_("Minimum height set"),
5522 P_("Whether to use the min-height property"),
5524 CLUTTER_PARAM_READWRITE);
5527 * ClutterActor:natural-width-set:
5529 * This flag controls whether the #ClutterActor:natural-width property
5534 obj_props[PROP_NATURAL_WIDTH_SET] =
5535 g_param_spec_boolean ("natural-width-set",
5536 P_("Natural width set"),
5537 P_("Whether to use the natural-width property"),
5539 CLUTTER_PARAM_READWRITE);
5542 * ClutterActor:natural-height-set:
5544 * This flag controls whether the #ClutterActor:natural-height property
5549 obj_props[PROP_NATURAL_HEIGHT_SET] =
5550 g_param_spec_boolean ("natural-height-set",
5551 P_("Natural height set"),
5552 P_("Whether to use the natural-height property"),
5554 CLUTTER_PARAM_READWRITE);
5557 * ClutterActor:allocation:
5559 * The allocation for the actor, in pixels
5561 * This is property is read-only, but you might monitor it to know when an
5562 * actor moves or resizes
5566 obj_props[PROP_ALLOCATION] =
5567 g_param_spec_boxed ("allocation",
5569 P_("The actor's allocation"),
5570 CLUTTER_TYPE_ACTOR_BOX,
5571 CLUTTER_PARAM_READABLE);
5574 * ClutterActor:request-mode:
5576 * Request mode for the #ClutterActor. The request mode determines the
5577 * type of geometry management used by the actor, either height for width
5578 * (the default) or width for height.
5580 * For actors implementing height for width, the parent container should get
5581 * the preferred width first, and then the preferred height for that width.
5583 * For actors implementing width for height, the parent container should get
5584 * the preferred height first, and then the preferred width for that height.
5589 * ClutterRequestMode mode;
5590 * gfloat natural_width, min_width;
5591 * gfloat natural_height, min_height;
5593 * mode = clutter_actor_get_request_mode (child);
5594 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5596 * clutter_actor_get_preferred_width (child, -1,
5598 * &natural_width);
5599 * clutter_actor_get_preferred_height (child, natural_width,
5601 * &natural_height);
5605 * clutter_actor_get_preferred_height (child, -1,
5607 * &natural_height);
5608 * clutter_actor_get_preferred_width (child, natural_height,
5610 * &natural_width);
5614 * will retrieve the minimum and natural width and height depending on the
5615 * preferred request mode of the #ClutterActor "child".
5617 * The clutter_actor_get_preferred_size() function will implement this
5622 obj_props[PROP_REQUEST_MODE] =
5623 g_param_spec_enum ("request-mode",
5625 P_("The actor's request mode"),
5626 CLUTTER_TYPE_REQUEST_MODE,
5627 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5628 CLUTTER_PARAM_READWRITE);
5631 * ClutterActor:depth:
5633 * The position of the actor on the Z axis.
5635 * The #ClutterActor:depth property is relative to the parent's
5638 * The #ClutterActor:depth property is animatable.
5642 obj_props[PROP_DEPTH] =
5643 g_param_spec_float ("depth",
5645 P_("Position on the Z axis"),
5646 -G_MAXFLOAT, G_MAXFLOAT,
5649 G_PARAM_STATIC_STRINGS |
5650 CLUTTER_PARAM_ANIMATABLE);
5653 * ClutterActor:opacity:
5655 * Opacity of an actor, between 0 (fully transparent) and
5656 * 255 (fully opaque)
5658 * The #ClutterActor:opacity property is animatable.
5660 obj_props[PROP_OPACITY] =
5661 g_param_spec_uint ("opacity",
5663 P_("Opacity of an actor"),
5667 G_PARAM_STATIC_STRINGS |
5668 CLUTTER_PARAM_ANIMATABLE);
5671 * ClutterActor:offscreen-redirect:
5673 * Determines the conditions in which the actor will be redirected
5674 * to an offscreen framebuffer while being painted. For example this
5675 * can be used to cache an actor in a framebuffer or for improved
5676 * handling of transparent actors. See
5677 * clutter_actor_set_offscreen_redirect() for details.
5681 obj_props[PROP_OFFSCREEN_REDIRECT] =
5682 g_param_spec_flags ("offscreen-redirect",
5683 P_("Offscreen redirect"),
5684 P_("Flags controlling when to flatten the actor into a single image"),
5685 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5687 CLUTTER_PARAM_READWRITE);
5690 * ClutterActor:visible:
5692 * Whether the actor is set to be visible or not
5694 * See also #ClutterActor:mapped
5696 obj_props[PROP_VISIBLE] =
5697 g_param_spec_boolean ("visible",
5699 P_("Whether the actor is visible or not"),
5701 CLUTTER_PARAM_READWRITE);
5704 * ClutterActor:mapped:
5706 * Whether the actor is mapped (will be painted when the stage
5707 * to which it belongs is mapped)
5711 obj_props[PROP_MAPPED] =
5712 g_param_spec_boolean ("mapped",
5714 P_("Whether the actor will be painted"),
5716 CLUTTER_PARAM_READABLE);
5719 * ClutterActor:realized:
5721 * Whether the actor has been realized
5725 obj_props[PROP_REALIZED] =
5726 g_param_spec_boolean ("realized",
5728 P_("Whether the actor has been realized"),
5730 CLUTTER_PARAM_READABLE);
5733 * ClutterActor:reactive:
5735 * Whether the actor is reactive to events or not
5737 * Only reactive actors will emit event-related signals
5741 obj_props[PROP_REACTIVE] =
5742 g_param_spec_boolean ("reactive",
5744 P_("Whether the actor is reactive to events"),
5746 CLUTTER_PARAM_READWRITE);
5749 * ClutterActor:has-clip:
5751 * Whether the actor has the #ClutterActor:clip property set or not
5753 obj_props[PROP_HAS_CLIP] =
5754 g_param_spec_boolean ("has-clip",
5756 P_("Whether the actor has a clip set"),
5758 CLUTTER_PARAM_READABLE);
5761 * ClutterActor:clip:
5763 * The clip region for the actor, in actor-relative coordinates
5765 * Every part of the actor outside the clip region will not be
5768 obj_props[PROP_CLIP] =
5769 g_param_spec_boxed ("clip",
5771 P_("The clip region for the actor"),
5772 CLUTTER_TYPE_GEOMETRY,
5773 CLUTTER_PARAM_READWRITE);
5776 * ClutterActor:name:
5778 * The name of the actor
5782 obj_props[PROP_NAME] =
5783 g_param_spec_string ("name",
5785 P_("Name of the actor"),
5787 CLUTTER_PARAM_READWRITE);
5790 * ClutterActor:scale-x:
5792 * The horizontal scale of the actor.
5794 * The #ClutterActor:scale-x property is animatable.
5798 obj_props[PROP_SCALE_X] =
5799 g_param_spec_double ("scale-x",
5801 P_("Scale factor on the X axis"),
5805 G_PARAM_STATIC_STRINGS |
5806 CLUTTER_PARAM_ANIMATABLE);
5809 * ClutterActor:scale-y:
5811 * The vertical scale of the actor.
5813 * The #ClutterActor:scale-y property is animatable.
5817 obj_props[PROP_SCALE_Y] =
5818 g_param_spec_double ("scale-y",
5820 P_("Scale factor on the Y axis"),
5824 G_PARAM_STATIC_STRINGS |
5825 CLUTTER_PARAM_ANIMATABLE);
5828 * ClutterActor:scale-center-x:
5830 * The horizontal center point for scaling
5834 obj_props[PROP_SCALE_CENTER_X] =
5835 g_param_spec_float ("scale-center-x",
5836 P_("Scale Center X"),
5837 P_("Horizontal scale center"),
5838 -G_MAXFLOAT, G_MAXFLOAT,
5840 CLUTTER_PARAM_READWRITE);
5843 * ClutterActor:scale-center-y:
5845 * The vertical center point for scaling
5849 obj_props[PROP_SCALE_CENTER_Y] =
5850 g_param_spec_float ("scale-center-y",
5851 P_("Scale Center Y"),
5852 P_("Vertical scale center"),
5853 -G_MAXFLOAT, G_MAXFLOAT,
5855 CLUTTER_PARAM_READWRITE);
5858 * ClutterActor:scale-gravity:
5860 * The center point for scaling expressed as a #ClutterGravity
5864 obj_props[PROP_SCALE_GRAVITY] =
5865 g_param_spec_enum ("scale-gravity",
5866 P_("Scale Gravity"),
5867 P_("The center of scaling"),
5868 CLUTTER_TYPE_GRAVITY,
5869 CLUTTER_GRAVITY_NONE,
5870 CLUTTER_PARAM_READWRITE);
5873 * ClutterActor:rotation-angle-x:
5875 * The rotation angle on the X axis.
5877 * The #ClutterActor:rotation-angle-x property is animatable.
5881 obj_props[PROP_ROTATION_ANGLE_X] =
5882 g_param_spec_double ("rotation-angle-x",
5883 P_("Rotation Angle X"),
5884 P_("The rotation angle on the X axis"),
5885 -G_MAXDOUBLE, G_MAXDOUBLE,
5888 G_PARAM_STATIC_STRINGS |
5889 CLUTTER_PARAM_ANIMATABLE);
5892 * ClutterActor:rotation-angle-y:
5894 * The rotation angle on the Y axis
5896 * The #ClutterActor:rotation-angle-y property is animatable.
5900 obj_props[PROP_ROTATION_ANGLE_Y] =
5901 g_param_spec_double ("rotation-angle-y",
5902 P_("Rotation Angle Y"),
5903 P_("The rotation angle on the Y axis"),
5904 -G_MAXDOUBLE, G_MAXDOUBLE,
5907 G_PARAM_STATIC_STRINGS |
5908 CLUTTER_PARAM_ANIMATABLE);
5911 * ClutterActor:rotation-angle-z:
5913 * The rotation angle on the Z axis
5915 * The #ClutterActor:rotation-angle-z property is animatable.
5919 obj_props[PROP_ROTATION_ANGLE_Z] =
5920 g_param_spec_double ("rotation-angle-z",
5921 P_("Rotation Angle Z"),
5922 P_("The rotation angle on the Z axis"),
5923 -G_MAXDOUBLE, G_MAXDOUBLE,
5926 G_PARAM_STATIC_STRINGS |
5927 CLUTTER_PARAM_ANIMATABLE);
5930 * ClutterActor:rotation-center-x:
5932 * The rotation center on the X axis.
5936 obj_props[PROP_ROTATION_CENTER_X] =
5937 g_param_spec_boxed ("rotation-center-x",
5938 P_("Rotation Center X"),
5939 P_("The rotation center on the X axis"),
5940 CLUTTER_TYPE_VERTEX,
5941 CLUTTER_PARAM_READWRITE);
5944 * ClutterActor:rotation-center-y:
5946 * The rotation center on the Y axis.
5950 obj_props[PROP_ROTATION_CENTER_Y] =
5951 g_param_spec_boxed ("rotation-center-y",
5952 P_("Rotation Center Y"),
5953 P_("The rotation center on the Y axis"),
5954 CLUTTER_TYPE_VERTEX,
5955 CLUTTER_PARAM_READWRITE);
5958 * ClutterActor:rotation-center-z:
5960 * The rotation center on the Z axis.
5964 obj_props[PROP_ROTATION_CENTER_Z] =
5965 g_param_spec_boxed ("rotation-center-z",
5966 P_("Rotation Center Z"),
5967 P_("The rotation center on the Z axis"),
5968 CLUTTER_TYPE_VERTEX,
5969 CLUTTER_PARAM_READWRITE);
5972 * ClutterActor:rotation-center-z-gravity:
5974 * The rotation center on the Z axis expressed as a #ClutterGravity.
5978 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5979 g_param_spec_enum ("rotation-center-z-gravity",
5980 P_("Rotation Center Z Gravity"),
5981 P_("Center point for rotation around the Z axis"),
5982 CLUTTER_TYPE_GRAVITY,
5983 CLUTTER_GRAVITY_NONE,
5984 CLUTTER_PARAM_READWRITE);
5987 * ClutterActor:anchor-x:
5989 * The X coordinate of an actor's anchor point, relative to
5990 * the actor coordinate space, in pixels
5994 obj_props[PROP_ANCHOR_X] =
5995 g_param_spec_float ("anchor-x",
5997 P_("X coordinate of the anchor point"),
5998 -G_MAXFLOAT, G_MAXFLOAT,
6000 CLUTTER_PARAM_READWRITE);
6003 * ClutterActor:anchor-y:
6005 * The Y coordinate of an actor's anchor point, relative to
6006 * the actor coordinate space, in pixels
6010 obj_props[PROP_ANCHOR_Y] =
6011 g_param_spec_float ("anchor-y",
6013 P_("Y coordinate of the anchor point"),
6014 -G_MAXFLOAT, G_MAXFLOAT,
6016 CLUTTER_PARAM_READWRITE);
6019 * ClutterActor:anchor-gravity:
6021 * The anchor point expressed as a #ClutterGravity
6025 obj_props[PROP_ANCHOR_GRAVITY] =
6026 g_param_spec_enum ("anchor-gravity",
6027 P_("Anchor Gravity"),
6028 P_("The anchor point as a ClutterGravity"),
6029 CLUTTER_TYPE_GRAVITY,
6030 CLUTTER_GRAVITY_NONE,
6031 CLUTTER_PARAM_READWRITE);
6034 * ClutterActor:show-on-set-parent:
6036 * If %TRUE, the actor is automatically shown when parented.
6038 * Calling clutter_actor_hide() on an actor which has not been
6039 * parented will set this property to %FALSE as a side effect.
6043 obj_props[PROP_SHOW_ON_SET_PARENT] =
6044 g_param_spec_boolean ("show-on-set-parent",
6045 P_("Show on set parent"),
6046 P_("Whether the actor is shown when parented"),
6048 CLUTTER_PARAM_READWRITE);
6051 * ClutterActor:clip-to-allocation:
6053 * Whether the clip region should track the allocated area
6056 * This property is ignored if a clip area has been explicitly
6057 * set using clutter_actor_set_clip().
6061 obj_props[PROP_CLIP_TO_ALLOCATION] =
6062 g_param_spec_boolean ("clip-to-allocation",
6063 P_("Clip to Allocation"),
6064 P_("Sets the clip region to track the actor's allocation"),
6066 CLUTTER_PARAM_READWRITE);
6069 * ClutterActor:text-direction:
6071 * The direction of the text inside a #ClutterActor.
6075 obj_props[PROP_TEXT_DIRECTION] =
6076 g_param_spec_enum ("text-direction",
6077 P_("Text Direction"),
6078 P_("Direction of the text"),
6079 CLUTTER_TYPE_TEXT_DIRECTION,
6080 CLUTTER_TEXT_DIRECTION_LTR,
6081 CLUTTER_PARAM_READWRITE);
6084 * ClutterActor:has-pointer:
6086 * Whether the actor contains the pointer of a #ClutterInputDevice
6091 obj_props[PROP_HAS_POINTER] =
6092 g_param_spec_boolean ("has-pointer",
6094 P_("Whether the actor contains the pointer of an input device"),
6096 CLUTTER_PARAM_READABLE);
6099 * ClutterActor:actions:
6101 * Adds a #ClutterAction to the actor
6105 obj_props[PROP_ACTIONS] =
6106 g_param_spec_object ("actions",
6108 P_("Adds an action to the actor"),
6109 CLUTTER_TYPE_ACTION,
6110 CLUTTER_PARAM_WRITABLE);
6113 * ClutterActor:constraints:
6115 * Adds a #ClutterConstraint to the actor
6119 obj_props[PROP_CONSTRAINTS] =
6120 g_param_spec_object ("constraints",
6122 P_("Adds a constraint to the actor"),
6123 CLUTTER_TYPE_CONSTRAINT,
6124 CLUTTER_PARAM_WRITABLE);
6127 * ClutterActor:effect:
6129 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6133 obj_props[PROP_EFFECT] =
6134 g_param_spec_object ("effect",
6136 P_("Add an effect to be applied on the actor"),
6137 CLUTTER_TYPE_EFFECT,
6138 CLUTTER_PARAM_WRITABLE);
6141 * ClutterActor:layout-manager:
6143 * A delegate object for controlling the layout of the children of
6148 obj_props[PROP_LAYOUT_MANAGER] =
6149 g_param_spec_object ("layout-manager",
6150 P_("Layout Manager"),
6151 P_("The object controlling the layout of an actor's children"),
6152 CLUTTER_TYPE_LAYOUT_MANAGER,
6153 CLUTTER_PARAM_READWRITE);
6157 * ClutterActor:x-align:
6159 * The alignment of an actor on the X axis, if the actor has been given
6160 * extra space for its allocation.
6164 obj_props[PROP_X_ALIGN] =
6165 g_param_spec_enum ("x-align",
6167 P_("The alignment of the actor on the X axis within its allocation"),
6168 CLUTTER_TYPE_ACTOR_ALIGN,
6169 CLUTTER_ACTOR_ALIGN_FILL,
6170 CLUTTER_PARAM_READWRITE);
6173 * ClutterActor:y-align:
6175 * The alignment of an actor on the Y axis, if the actor has been given
6176 * extra space for its allocation.
6180 obj_props[PROP_Y_ALIGN] =
6181 g_param_spec_enum ("y-align",
6183 P_("The alignment of the actor on the Y axis within its allocation"),
6184 CLUTTER_TYPE_ACTOR_ALIGN,
6185 CLUTTER_ACTOR_ALIGN_FILL,
6186 CLUTTER_PARAM_READWRITE);
6189 * ClutterActor:margin-top:
6191 * The margin (in pixels) from the top of the actor.
6193 * This property adds a margin to the actor's preferred size; the margin
6194 * will be automatically taken into account when allocating the actor.
6198 obj_props[PROP_MARGIN_TOP] =
6199 g_param_spec_float ("margin-top",
6201 P_("Extra space at the top"),
6204 CLUTTER_PARAM_READWRITE);
6207 * ClutterActor:margin-bottom:
6209 * The margin (in pixels) from the bottom of the actor.
6211 * This property adds a margin to the actor's preferred size; the margin
6212 * will be automatically taken into account when allocating the actor.
6216 obj_props[PROP_MARGIN_BOTTOM] =
6217 g_param_spec_float ("margin-bottom",
6218 P_("Margin Bottom"),
6219 P_("Extra space at the bottom"),
6222 CLUTTER_PARAM_READWRITE);
6225 * ClutterActor:margin-left:
6227 * The margin (in pixels) from the left of the actor.
6229 * This property adds a margin to the actor's preferred size; the margin
6230 * will be automatically taken into account when allocating the actor.
6234 obj_props[PROP_MARGIN_LEFT] =
6235 g_param_spec_float ("margin-left",
6237 P_("Extra space at the left"),
6240 CLUTTER_PARAM_READWRITE);
6243 * ClutterActor:margin-right:
6245 * The margin (in pixels) from the right of the actor.
6247 * This property adds a margin to the actor's preferred size; the margin
6248 * will be automatically taken into account when allocating the actor.
6252 obj_props[PROP_MARGIN_RIGHT] =
6253 g_param_spec_float ("margin-right",
6255 P_("Extra space at the right"),
6258 CLUTTER_PARAM_READWRITE);
6261 * ClutterActor:background-color-set:
6263 * Whether the #ClutterActor:background-color property has been set.
6267 obj_props[PROP_BACKGROUND_COLOR_SET] =
6268 g_param_spec_boolean ("background-color-set",
6269 P_("Background Color Set"),
6270 P_("Whether the background color is set"),
6272 CLUTTER_PARAM_READABLE);
6275 * ClutterActor:background-color:
6277 * Paints a solid fill of the actor's allocation using the specified
6280 * The #ClutterActor:background-color property is animatable.
6284 obj_props[PROP_BACKGROUND_COLOR] =
6285 clutter_param_spec_color ("background-color",
6286 P_("Background color"),
6287 P_("The actor's background color"),
6288 CLUTTER_COLOR_Transparent,
6290 G_PARAM_STATIC_STRINGS |
6291 CLUTTER_PARAM_ANIMATABLE);
6294 * ClutterActor:first-child:
6296 * The actor's first child.
6300 obj_props[PROP_FIRST_CHILD] =
6301 g_param_spec_object ("first-child",
6303 P_("The actor's first child"),
6305 CLUTTER_PARAM_READABLE);
6308 * ClutterActor:last-child:
6310 * The actor's last child.
6314 obj_props[PROP_LAST_CHILD] =
6315 g_param_spec_object ("last-child",
6317 P_("The actor's last child"),
6319 CLUTTER_PARAM_READABLE);
6322 * ClutterActor:content:
6324 * The #ClutterContent implementation that controls the content
6329 obj_props[PROP_CONTENT] =
6330 g_param_spec_object ("content",
6332 P_("Delegate object for painting the actor's content"),
6333 CLUTTER_TYPE_CONTENT,
6334 CLUTTER_PARAM_READWRITE);
6337 * ClutterActor:content-gravity:
6339 * The alignment that should be honoured by the #ClutterContent
6340 * set with the #ClutterActor:content property.
6342 * Changing the value of this property will change the bounding box of
6343 * the content; you can use the #ClutterActor:content-box property to
6344 * get the position and size of the content within the actor's
6347 * This property is meaningful only for #ClutterContent implementations
6348 * that have a preferred size, and if the preferred size is smaller than
6349 * the actor's allocation.
6353 obj_props[PROP_CONTENT_GRAVITY] =
6354 g_param_spec_enum ("content-gravity",
6355 P_("Content Gravity"),
6356 P_("Alignment of the actor's content"),
6357 CLUTTER_TYPE_CONTENT_GRAVITY,
6358 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6359 CLUTTER_PARAM_READWRITE);
6362 * ClutterActor:content-box:
6364 * The bounding box for the #ClutterContent used by the actor.
6366 * The value of this property is controlled by the #ClutterActor:allocation
6367 * and #ClutterActor:content-gravity properties of #ClutterActor.
6369 * The bounding box for the content is guaranteed to never exceed the
6370 * allocation's of the actor.
6374 obj_props[PROP_CONTENT_BOX] =
6375 g_param_spec_boxed ("content-box",
6377 P_("The bounding box of the actor's content"),
6378 CLUTTER_TYPE_ACTOR_BOX,
6379 CLUTTER_PARAM_READABLE);
6381 obj_props[PROP_MINIFICATION_FILTER] =
6382 g_param_spec_enum ("minification-filter",
6383 P_("Minification Filter"),
6384 P_("The filter used when reducing the size of the content"),
6385 CLUTTER_TYPE_SCALING_FILTER,
6386 CLUTTER_SCALING_FILTER_LINEAR,
6387 CLUTTER_PARAM_READWRITE);
6389 obj_props[PROP_MAGNIFICATION_FILTER] =
6390 g_param_spec_enum ("magnification-filter",
6391 P_("Magnification Filter"),
6392 P_("The filter used when increasing the size of the content"),
6393 CLUTTER_TYPE_SCALING_FILTER,
6394 CLUTTER_SCALING_FILTER_LINEAR,
6395 CLUTTER_PARAM_READWRITE);
6397 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6400 * ClutterActor::destroy:
6401 * @actor: the #ClutterActor which emitted the signal
6403 * The ::destroy signal notifies that all references held on the
6404 * actor which emitted it should be released.
6406 * The ::destroy signal should be used by all holders of a reference
6409 * This signal might result in the finalization of the #ClutterActor
6410 * if all references are released.
6412 * Composite actors and actors implementing the #ClutterContainer
6413 * interface should override the default implementation of the
6414 * class handler of this signal and call clutter_actor_destroy() on
6415 * their children. When overriding the default class handler, it is
6416 * required to chain up to the parent's implementation.
6420 actor_signals[DESTROY] =
6421 g_signal_new (I_("destroy"),
6422 G_TYPE_FROM_CLASS (object_class),
6423 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6424 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6426 _clutter_marshal_VOID__VOID,
6429 * ClutterActor::show:
6430 * @actor: the object which received the signal
6432 * The ::show signal is emitted when an actor is visible and
6433 * rendered on the stage.
6437 actor_signals[SHOW] =
6438 g_signal_new (I_("show"),
6439 G_TYPE_FROM_CLASS (object_class),
6441 G_STRUCT_OFFSET (ClutterActorClass, show),
6443 _clutter_marshal_VOID__VOID,
6446 * ClutterActor::hide:
6447 * @actor: the object which received the signal
6449 * The ::hide signal is emitted when an actor is no longer rendered
6454 actor_signals[HIDE] =
6455 g_signal_new (I_("hide"),
6456 G_TYPE_FROM_CLASS (object_class),
6458 G_STRUCT_OFFSET (ClutterActorClass, hide),
6460 _clutter_marshal_VOID__VOID,
6463 * ClutterActor::parent-set:
6464 * @actor: the object which received the signal
6465 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6467 * This signal is emitted when the parent of the actor changes.
6471 actor_signals[PARENT_SET] =
6472 g_signal_new (I_("parent-set"),
6473 G_TYPE_FROM_CLASS (object_class),
6475 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6477 _clutter_marshal_VOID__OBJECT,
6479 CLUTTER_TYPE_ACTOR);
6482 * ClutterActor::queue-redraw:
6483 * @actor: the actor we're bubbling the redraw request through
6484 * @origin: the actor which initiated the redraw request
6486 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6487 * is called on @origin.
6489 * The default implementation for #ClutterActor chains up to the
6490 * parent actor and queues a redraw on the parent, thus "bubbling"
6491 * the redraw queue up through the actor graph. The default
6492 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6493 * in a main loop idle handler.
6495 * Note that the @origin actor may be the stage, or a container; it
6496 * does not have to be a leaf node in the actor graph.
6498 * Toolkits embedding a #ClutterStage which require a redraw and
6499 * relayout cycle can stop the emission of this signal using the
6500 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6505 * on_redraw_complete (gpointer data)
6507 * ClutterStage *stage = data;
6509 * /* execute the Clutter drawing pipeline */
6510 * clutter_stage_ensure_redraw (stage);
6514 * on_stage_queue_redraw (ClutterStage *stage)
6516 * /* this prevents the default handler to run */
6517 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6519 * /* queue a redraw with the host toolkit and call
6520 * * a function when the redraw has been completed
6522 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6526 * <note><para>This signal is emitted before the Clutter paint
6527 * pipeline is executed. If you want to know when the pipeline has
6528 * been completed you should connect to the ::paint signal on the
6529 * Stage with g_signal_connect_after().</para></note>
6533 actor_signals[QUEUE_REDRAW] =
6534 g_signal_new (I_("queue-redraw"),
6535 G_TYPE_FROM_CLASS (object_class),
6538 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6540 _clutter_marshal_VOID__OBJECT,
6542 CLUTTER_TYPE_ACTOR);
6545 * ClutterActor::queue-relayout
6546 * @actor: the actor being queued for relayout
6548 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6549 * is called on an actor.
6551 * The default implementation for #ClutterActor chains up to the
6552 * parent actor and queues a relayout on the parent, thus "bubbling"
6553 * the relayout queue up through the actor graph.
6555 * The main purpose of this signal is to allow relayout to be propagated
6556 * properly in the procense of #ClutterClone actors. Applications will
6557 * not normally need to connect to this signal.
6561 actor_signals[QUEUE_RELAYOUT] =
6562 g_signal_new (I_("queue-relayout"),
6563 G_TYPE_FROM_CLASS (object_class),
6566 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6568 _clutter_marshal_VOID__VOID,
6572 * ClutterActor::event:
6573 * @actor: the actor which received the event
6574 * @event: a #ClutterEvent
6576 * The ::event signal is emitted each time an event is received
6577 * by the @actor. This signal will be emitted on every actor,
6578 * following the hierarchy chain, until it reaches the top-level
6579 * container (the #ClutterStage).
6581 * Return value: %TRUE if the event has been handled by the actor,
6582 * or %FALSE to continue the emission.
6586 actor_signals[EVENT] =
6587 g_signal_new (I_("event"),
6588 G_TYPE_FROM_CLASS (object_class),
6590 G_STRUCT_OFFSET (ClutterActorClass, event),
6591 _clutter_boolean_handled_accumulator, NULL,
6592 _clutter_marshal_BOOLEAN__BOXED,
6594 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6596 * ClutterActor::button-press-event:
6597 * @actor: the actor which received the event
6598 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6600 * The ::button-press-event signal is emitted each time a mouse button
6601 * is pressed on @actor.
6603 * Return value: %TRUE if the event has been handled by the actor,
6604 * or %FALSE to continue the emission.
6608 actor_signals[BUTTON_PRESS_EVENT] =
6609 g_signal_new (I_("button-press-event"),
6610 G_TYPE_FROM_CLASS (object_class),
6612 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6613 _clutter_boolean_handled_accumulator, NULL,
6614 _clutter_marshal_BOOLEAN__BOXED,
6616 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6618 * ClutterActor::button-release-event:
6619 * @actor: the actor which received the event
6620 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6622 * The ::button-release-event signal is emitted each time a mouse button
6623 * is released on @actor.
6625 * Return value: %TRUE if the event has been handled by the actor,
6626 * or %FALSE to continue the emission.
6630 actor_signals[BUTTON_RELEASE_EVENT] =
6631 g_signal_new (I_("button-release-event"),
6632 G_TYPE_FROM_CLASS (object_class),
6634 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6635 _clutter_boolean_handled_accumulator, NULL,
6636 _clutter_marshal_BOOLEAN__BOXED,
6638 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6640 * ClutterActor::scroll-event:
6641 * @actor: the actor which received the event
6642 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6644 * The ::scroll-event signal is emitted each time the mouse is
6645 * scrolled on @actor
6647 * Return value: %TRUE if the event has been handled by the actor,
6648 * or %FALSE to continue the emission.
6652 actor_signals[SCROLL_EVENT] =
6653 g_signal_new (I_("scroll-event"),
6654 G_TYPE_FROM_CLASS (object_class),
6656 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6657 _clutter_boolean_handled_accumulator, NULL,
6658 _clutter_marshal_BOOLEAN__BOXED,
6660 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6662 * ClutterActor::key-press-event:
6663 * @actor: the actor which received the event
6664 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6666 * The ::key-press-event signal is emitted each time a keyboard button
6667 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6669 * Return value: %TRUE if the event has been handled by the actor,
6670 * or %FALSE to continue the emission.
6674 actor_signals[KEY_PRESS_EVENT] =
6675 g_signal_new (I_("key-press-event"),
6676 G_TYPE_FROM_CLASS (object_class),
6678 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6679 _clutter_boolean_handled_accumulator, NULL,
6680 _clutter_marshal_BOOLEAN__BOXED,
6682 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6684 * ClutterActor::key-release-event:
6685 * @actor: the actor which received the event
6686 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6688 * The ::key-release-event signal is emitted each time a keyboard button
6689 * is released while @actor has key focus (see
6690 * clutter_stage_set_key_focus()).
6692 * Return value: %TRUE if the event has been handled by the actor,
6693 * or %FALSE to continue the emission.
6697 actor_signals[KEY_RELEASE_EVENT] =
6698 g_signal_new (I_("key-release-event"),
6699 G_TYPE_FROM_CLASS (object_class),
6701 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6702 _clutter_boolean_handled_accumulator, NULL,
6703 _clutter_marshal_BOOLEAN__BOXED,
6705 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6707 * ClutterActor::motion-event:
6708 * @actor: the actor which received the event
6709 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6711 * The ::motion-event signal is emitted each time the mouse pointer is
6712 * moved over @actor.
6714 * Return value: %TRUE if the event has been handled by the actor,
6715 * or %FALSE to continue the emission.
6719 actor_signals[MOTION_EVENT] =
6720 g_signal_new (I_("motion-event"),
6721 G_TYPE_FROM_CLASS (object_class),
6723 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6724 _clutter_boolean_handled_accumulator, NULL,
6725 _clutter_marshal_BOOLEAN__BOXED,
6727 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6730 * ClutterActor::key-focus-in:
6731 * @actor: the actor which now has key focus
6733 * The ::key-focus-in signal is emitted when @actor receives key focus.
6737 actor_signals[KEY_FOCUS_IN] =
6738 g_signal_new (I_("key-focus-in"),
6739 G_TYPE_FROM_CLASS (object_class),
6741 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6743 _clutter_marshal_VOID__VOID,
6747 * ClutterActor::key-focus-out:
6748 * @actor: the actor which now has key focus
6750 * The ::key-focus-out signal is emitted when @actor loses key focus.
6754 actor_signals[KEY_FOCUS_OUT] =
6755 g_signal_new (I_("key-focus-out"),
6756 G_TYPE_FROM_CLASS (object_class),
6758 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6760 _clutter_marshal_VOID__VOID,
6764 * ClutterActor::enter-event:
6765 * @actor: the actor which the pointer has entered.
6766 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6768 * The ::enter-event signal is emitted when the pointer enters the @actor
6770 * Return value: %TRUE if the event has been handled by the actor,
6771 * or %FALSE to continue the emission.
6775 actor_signals[ENTER_EVENT] =
6776 g_signal_new (I_("enter-event"),
6777 G_TYPE_FROM_CLASS (object_class),
6779 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6780 _clutter_boolean_handled_accumulator, NULL,
6781 _clutter_marshal_BOOLEAN__BOXED,
6783 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6786 * ClutterActor::leave-event:
6787 * @actor: the actor which the pointer has left
6788 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6790 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6792 * Return value: %TRUE if the event has been handled by the actor,
6793 * or %FALSE to continue the emission.
6797 actor_signals[LEAVE_EVENT] =
6798 g_signal_new (I_("leave-event"),
6799 G_TYPE_FROM_CLASS (object_class),
6801 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6802 _clutter_boolean_handled_accumulator, NULL,
6803 _clutter_marshal_BOOLEAN__BOXED,
6805 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6808 * ClutterActor::captured-event:
6809 * @actor: the actor which received the signal
6810 * @event: a #ClutterEvent
6812 * The ::captured-event signal is emitted when an event is captured
6813 * by Clutter. This signal will be emitted starting from the top-level
6814 * container (the #ClutterStage) to the actor which received the event
6815 * going down the hierarchy. This signal can be used to intercept every
6816 * event before the specialized events (like
6817 * ClutterActor::button-press-event or ::key-released-event) are
6820 * Return value: %TRUE if the event has been handled by the actor,
6821 * or %FALSE to continue the emission.
6825 actor_signals[CAPTURED_EVENT] =
6826 g_signal_new (I_("captured-event"),
6827 G_TYPE_FROM_CLASS (object_class),
6829 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6830 _clutter_boolean_handled_accumulator, NULL,
6831 _clutter_marshal_BOOLEAN__BOXED,
6833 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6836 * ClutterActor::paint:
6837 * @actor: the #ClutterActor that received the signal
6839 * The ::paint signal is emitted each time an actor is being painted.
6841 * Subclasses of #ClutterActor should override the class signal handler
6842 * and paint themselves in that function.
6844 * It is possible to connect a handler to the ::paint signal in order
6845 * to set up some custom aspect of a paint.
6849 actor_signals[PAINT] =
6850 g_signal_new (I_("paint"),
6851 G_TYPE_FROM_CLASS (object_class),
6854 G_STRUCT_OFFSET (ClutterActorClass, paint),
6856 _clutter_marshal_VOID__VOID,
6859 * ClutterActor::realize:
6860 * @actor: the #ClutterActor that received the signal
6862 * The ::realize signal is emitted each time an actor is being
6867 actor_signals[REALIZE] =
6868 g_signal_new (I_("realize"),
6869 G_TYPE_FROM_CLASS (object_class),
6871 G_STRUCT_OFFSET (ClutterActorClass, realize),
6873 _clutter_marshal_VOID__VOID,
6876 * ClutterActor::unrealize:
6877 * @actor: the #ClutterActor that received the signal
6879 * The ::unrealize signal is emitted each time an actor is being
6884 actor_signals[UNREALIZE] =
6885 g_signal_new (I_("unrealize"),
6886 G_TYPE_FROM_CLASS (object_class),
6888 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6890 _clutter_marshal_VOID__VOID,
6894 * ClutterActor::pick:
6895 * @actor: the #ClutterActor that received the signal
6896 * @color: the #ClutterColor to be used when picking
6898 * The ::pick signal is emitted each time an actor is being painted
6899 * in "pick mode". The pick mode is used to identify the actor during
6900 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6901 * The actor should paint its shape using the passed @pick_color.
6903 * Subclasses of #ClutterActor should override the class signal handler
6904 * and paint themselves in that function.
6906 * It is possible to connect a handler to the ::pick signal in order
6907 * to set up some custom aspect of a paint in pick mode.
6911 actor_signals[PICK] =
6912 g_signal_new (I_("pick"),
6913 G_TYPE_FROM_CLASS (object_class),
6915 G_STRUCT_OFFSET (ClutterActorClass, pick),
6917 _clutter_marshal_VOID__BOXED,
6919 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6922 * ClutterActor::allocation-changed:
6923 * @actor: the #ClutterActor that emitted the signal
6924 * @box: a #ClutterActorBox with the new allocation
6925 * @flags: #ClutterAllocationFlags for the allocation
6927 * The ::allocation-changed signal is emitted when the
6928 * #ClutterActor:allocation property changes. Usually, application
6929 * code should just use the notifications for the :allocation property
6930 * but if you want to track the allocation flags as well, for instance
6931 * to know whether the absolute origin of @actor changed, then you might
6932 * want use this signal instead.
6936 actor_signals[ALLOCATION_CHANGED] =
6937 g_signal_new (I_("allocation-changed"),
6938 G_TYPE_FROM_CLASS (object_class),
6942 _clutter_marshal_VOID__BOXED_FLAGS,
6944 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6945 CLUTTER_TYPE_ALLOCATION_FLAGS);
6949 clutter_actor_init (ClutterActor *self)
6951 ClutterActorPrivate *priv;
6953 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6955 priv->id = _clutter_context_acquire_id (self);
6958 priv->opacity = 0xff;
6959 priv->show_on_set_parent = TRUE;
6961 priv->needs_width_request = TRUE;
6962 priv->needs_height_request = TRUE;
6963 priv->needs_allocation = TRUE;
6965 priv->cached_width_age = 1;
6966 priv->cached_height_age = 1;
6968 priv->opacity_override = -1;
6969 priv->enable_model_view_transform = TRUE;
6971 /* Initialize an empty paint volume to start with */
6972 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6973 priv->last_paint_volume_valid = TRUE;
6975 priv->transform_valid = FALSE;
6977 /* the default is to stretch the content, to match the
6978 * current behaviour of basically all actors. also, it's
6979 * the easiest thing to compute.
6981 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6982 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
6983 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
6987 * clutter_actor_new:
6989 * Creates a new #ClutterActor.
6991 * A newly created actor has a floating reference, which will be sunk
6992 * when it is added to another actor.
6994 * Return value: (transfer full): the newly created #ClutterActor
6999 clutter_actor_new (void)
7001 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7005 * clutter_actor_destroy:
7006 * @self: a #ClutterActor
7008 * Destroys an actor. When an actor is destroyed, it will break any
7009 * references it holds to other objects. If the actor is inside a
7010 * container, the actor will be removed.
7012 * When you destroy a container, its children will be destroyed as well.
7014 * Note: you cannot destroy the #ClutterStage returned by
7015 * clutter_stage_get_default().
7018 clutter_actor_destroy (ClutterActor *self)
7020 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7022 g_object_ref (self);
7024 /* avoid recursion while destroying */
7025 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7027 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7029 g_object_run_dispose (G_OBJECT (self));
7031 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7034 g_object_unref (self);
7038 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7039 ClutterPaintVolume *clip)
7041 ClutterActorPrivate *priv = self->priv;
7042 ClutterPaintVolume *pv;
7045 /* Remove queue entry early in the process, otherwise a new
7046 queue_redraw() during signal handling could put back this
7047 object in the stage redraw list (but the entry is freed as
7048 soon as we return from this function, causing a segfault
7051 priv->queue_redraw_entry = NULL;
7053 /* If we've been explicitly passed a clip volume then there's
7054 * nothing more to calculate, but otherwise the only thing we know
7055 * is that the change is constrained to the given actor.
7057 * The idea is that if we know the paint volume for where the actor
7058 * was last drawn (in eye coordinates) and we also have the paint
7059 * volume for where it will be drawn next (in actor coordinates)
7060 * then if we queue a redraw for both these volumes that will cover
7061 * everything that needs to be redrawn to clear the old view and
7062 * show the latest view of the actor.
7064 * Don't clip this redraw if we don't know what position we had for
7065 * the previous redraw since we don't know where to set the clip so
7066 * it will clear the actor as it is currently.
7070 _clutter_actor_set_queue_redraw_clip (self, clip);
7073 else if (G_LIKELY (priv->last_paint_volume_valid))
7075 pv = _clutter_actor_get_paint_volume_mutable (self);
7078 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7080 /* make sure we redraw the actors old position... */
7081 _clutter_actor_set_queue_redraw_clip (stage,
7082 &priv->last_paint_volume);
7083 _clutter_actor_signal_queue_redraw (stage, stage);
7084 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7086 /* XXX: Ideally the redraw signal would take a clip volume
7087 * argument, but that would be an ABI break. Until we can
7088 * break the ABI we pass the argument out-of-band
7091 /* setup the clip for the actors new position... */
7092 _clutter_actor_set_queue_redraw_clip (self, pv);
7101 _clutter_actor_signal_queue_redraw (self, self);
7103 /* Just in case anyone is manually firing redraw signals without
7104 * using the public queue_redraw() API we are careful to ensure that
7105 * our out-of-band clip member is cleared before returning...
7107 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7109 if (G_LIKELY (clipped))
7110 _clutter_actor_set_queue_redraw_clip (self, NULL);
7114 _clutter_actor_get_allocation_clip (ClutterActor *self,
7115 ClutterActorBox *clip)
7117 ClutterActorBox allocation;
7119 /* XXX: we don't care if we get an out of date allocation here
7120 * because clutter_actor_queue_redraw_with_clip knows to ignore
7121 * the clip if the actor's allocation is invalid.
7123 * This is noted because clutter_actor_get_allocation_box does some
7124 * unnecessary work to support buggy code with a comment suggesting
7125 * that it could be changed later which would be good for this use
7128 clutter_actor_get_allocation_box (self, &allocation);
7130 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7131 * actor's own coordinate space but the allocation is in parent
7135 clip->x2 = allocation.x2 - allocation.x1;
7136 clip->y2 = allocation.y2 - allocation.y1;
7140 _clutter_actor_queue_redraw_full (ClutterActor *self,
7141 ClutterRedrawFlags flags,
7142 ClutterPaintVolume *volume,
7143 ClutterEffect *effect)
7145 ClutterActorPrivate *priv = self->priv;
7146 ClutterPaintVolume allocation_pv;
7147 ClutterPaintVolume *pv;
7148 gboolean should_free_pv;
7149 ClutterActor *stage;
7151 /* Here's an outline of the actor queue redraw mechanism:
7153 * The process starts in one of the following two functions which
7154 * are wrappers for this function:
7155 * clutter_actor_queue_redraw
7156 * _clutter_actor_queue_redraw_with_clip
7158 * additionally, an effect can queue a redraw by wrapping this
7159 * function in clutter_effect_queue_rerun
7161 * This functions queues an entry in a list associated with the
7162 * stage which is a list of actors that queued a redraw while
7163 * updating the timelines, performing layouting and processing other
7164 * mainloop sources before the next paint starts.
7166 * We aim to minimize the processing done at this point because
7167 * there is a good chance other events will happen while updating
7168 * the scenegraph that would invalidate any expensive work we might
7169 * otherwise try to do here. For example we don't try and resolve
7170 * the screen space bounding box of an actor at this stage so as to
7171 * minimize how much of the screen redraw because it's possible
7172 * something else will happen which will force a full redraw anyway.
7174 * When all updates are complete and we come to paint the stage then
7175 * we iterate this list and actually emit the "queue-redraw" signals
7176 * for each of the listed actors which will bubble up to the stage
7177 * for each actor and at that point we will transform the actors
7178 * paint volume into screen coordinates to determine the clip region
7179 * for what needs to be redrawn in the next paint.
7181 * Besides minimizing redundant work another reason for this
7182 * deferred design is that it's more likely we will be able to
7183 * determine the paint volume of an actor once we've finished
7184 * updating the scenegraph because its allocation should be up to
7185 * date. NB: If we can't determine an actors paint volume then we
7186 * can't automatically queue a clipped redraw which can make a big
7187 * difference to performance.
7189 * So the control flow goes like this:
7190 * One of clutter_actor_queue_redraw,
7191 * _clutter_actor_queue_redraw_with_clip
7192 * or clutter_effect_queue_rerun
7194 * then control moves to:
7195 * _clutter_stage_queue_actor_redraw
7197 * later during _clutter_stage_do_update, once relayouting is done
7198 * and the scenegraph has been updated we will call:
7199 * _clutter_stage_finish_queue_redraws
7201 * _clutter_stage_finish_queue_redraws will call
7202 * _clutter_actor_finish_queue_redraw for each listed actor.
7203 * Note: actors *are* allowed to queue further redraws during this
7204 * process (considering clone actors or texture_new_from_actor which
7205 * respond to their source queueing a redraw by queuing a redraw
7206 * themselves). We repeat the process until the list is empty.
7208 * This will result in the "queue-redraw" signal being fired for
7209 * each actor which will pass control to the default signal handler:
7210 * clutter_actor_real_queue_redraw
7212 * This will bubble up to the stages handler:
7213 * clutter_stage_real_queue_redraw
7215 * clutter_stage_real_queue_redraw will transform the actors paint
7216 * volume into screen space and add it as a clip region for the next
7220 /* ignore queueing a redraw for actors being destroyed */
7221 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7224 stage = _clutter_actor_get_stage_internal (self);
7226 /* Ignore queueing a redraw for actors not descended from a stage */
7230 /* ignore queueing a redraw on stages that are being destroyed */
7231 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7234 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7236 ClutterActorBox allocation_clip;
7237 ClutterVertex origin;
7239 /* If the actor doesn't have a valid allocation then we will
7240 * queue a full stage redraw. */
7241 if (priv->needs_allocation)
7243 /* NB: NULL denotes an undefined clip which will result in a
7245 _clutter_actor_set_queue_redraw_clip (self, NULL);
7246 _clutter_actor_signal_queue_redraw (self, self);
7250 _clutter_paint_volume_init_static (&allocation_pv, self);
7251 pv = &allocation_pv;
7253 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7255 origin.x = allocation_clip.x1;
7256 origin.y = allocation_clip.y1;
7258 clutter_paint_volume_set_origin (pv, &origin);
7259 clutter_paint_volume_set_width (pv,
7260 allocation_clip.x2 - allocation_clip.x1);
7261 clutter_paint_volume_set_height (pv,
7262 allocation_clip.y2 -
7263 allocation_clip.y1);
7264 should_free_pv = TRUE;
7269 should_free_pv = FALSE;
7272 self->priv->queue_redraw_entry =
7273 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7274 priv->queue_redraw_entry,
7279 clutter_paint_volume_free (pv);
7281 /* If this is the first redraw queued then we can directly use the
7283 if (!priv->is_dirty)
7284 priv->effect_to_redraw = effect;
7285 /* Otherwise we need to merge it with the existing effect parameter */
7286 else if (effect != NULL)
7288 /* If there's already an effect then we need to use whichever is
7289 later in the chain of actors. Otherwise a full redraw has
7290 already been queued on the actor so we need to ignore the
7292 if (priv->effect_to_redraw != NULL)
7294 if (priv->effects == NULL)
7295 g_warning ("Redraw queued with an effect that is "
7296 "not applied to the actor");
7301 for (l = _clutter_meta_group_peek_metas (priv->effects);
7305 if (l->data == priv->effect_to_redraw ||
7307 priv->effect_to_redraw = l->data;
7314 /* If no effect is specified then we need to redraw the whole
7316 priv->effect_to_redraw = NULL;
7319 priv->is_dirty = TRUE;
7323 * clutter_actor_queue_redraw:
7324 * @self: A #ClutterActor
7326 * Queues up a redraw of an actor and any children. The redraw occurs
7327 * once the main loop becomes idle (after the current batch of events
7328 * has been processed, roughly).
7330 * Applications rarely need to call this, as redraws are handled
7331 * automatically by modification functions.
7333 * This function will not do anything if @self is not visible, or
7334 * if the actor is inside an invisible part of the scenegraph.
7336 * Also be aware that painting is a NOP for actors with an opacity of
7339 * When you are implementing a custom actor you must queue a redraw
7340 * whenever some private state changes that will affect painting or
7341 * picking of your actor.
7344 clutter_actor_queue_redraw (ClutterActor *self)
7346 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7348 _clutter_actor_queue_redraw_full (self,
7350 NULL, /* clip volume */
7355 * _clutter_actor_queue_redraw_with_clip:
7356 * @self: A #ClutterActor
7357 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7358 * this queue redraw.
7359 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7360 * redrawn or %NULL if you are just using a @flag to state your
7363 * Queues up a clipped redraw of an actor and any children. The redraw
7364 * occurs once the main loop becomes idle (after the current batch of
7365 * events has been processed, roughly).
7367 * If no flags are given the clip volume is defined by @volume
7368 * specified in actor coordinates and tells Clutter that only content
7369 * within this volume has been changed so Clutter can optionally
7370 * optimize the redraw.
7372 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7373 * should be %NULL and this tells Clutter to use the actor's current
7374 * allocation as a clip box. This flag can only be used for 2D actors,
7375 * because any actor with depth may be projected outside its
7378 * Applications rarely need to call this, as redraws are handled
7379 * automatically by modification functions.
7381 * This function will not do anything if @self is not visible, or if
7382 * the actor is inside an invisible part of the scenegraph.
7384 * Also be aware that painting is a NOP for actors with an opacity of
7387 * When you are implementing a custom actor you must queue a redraw
7388 * whenever some private state changes that will affect painting or
7389 * picking of your actor.
7392 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7393 ClutterRedrawFlags flags,
7394 ClutterPaintVolume *volume)
7396 _clutter_actor_queue_redraw_full (self,
7398 volume, /* clip volume */
7403 _clutter_actor_queue_only_relayout (ClutterActor *self)
7405 ClutterActorPrivate *priv = self->priv;
7407 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7410 if (priv->needs_width_request &&
7411 priv->needs_height_request &&
7412 priv->needs_allocation)
7413 return; /* save some cpu cycles */
7415 #if CLUTTER_ENABLE_DEBUG
7416 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7418 g_warning ("The actor '%s' is currently inside an allocation "
7419 "cycle; calling clutter_actor_queue_relayout() is "
7421 _clutter_actor_get_debug_name (self));
7423 #endif /* CLUTTER_ENABLE_DEBUG */
7425 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7429 * clutter_actor_queue_redraw_with_clip:
7430 * @self: a #ClutterActor
7431 * @clip: (allow-none): a rectangular clip region, or %NULL
7433 * Queues a redraw on @self limited to a specific, actor-relative
7436 * If @clip is %NULL this function is equivalent to
7437 * clutter_actor_queue_redraw().
7442 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7443 const cairo_rectangle_int_t *clip)
7445 ClutterPaintVolume volume;
7446 ClutterVertex origin;
7448 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7452 clutter_actor_queue_redraw (self);
7456 _clutter_paint_volume_init_static (&volume, self);
7462 clutter_paint_volume_set_origin (&volume, &origin);
7463 clutter_paint_volume_set_width (&volume, clip->width);
7464 clutter_paint_volume_set_height (&volume, clip->height);
7466 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7468 clutter_paint_volume_free (&volume);
7472 * clutter_actor_queue_relayout:
7473 * @self: A #ClutterActor
7475 * Indicates that the actor's size request or other layout-affecting
7476 * properties may have changed. This function is used inside #ClutterActor
7477 * subclass implementations, not by applications directly.
7479 * Queueing a new layout automatically queues a redraw as well.
7484 clutter_actor_queue_relayout (ClutterActor *self)
7486 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7488 _clutter_actor_queue_only_relayout (self);
7489 clutter_actor_queue_redraw (self);
7493 * clutter_actor_get_preferred_size:
7494 * @self: a #ClutterActor
7495 * @min_width_p: (out) (allow-none): return location for the minimum
7497 * @min_height_p: (out) (allow-none): return location for the minimum
7499 * @natural_width_p: (out) (allow-none): return location for the natural
7501 * @natural_height_p: (out) (allow-none): return location for the natural
7504 * Computes the preferred minimum and natural size of an actor, taking into
7505 * account the actor's geometry management (either height-for-width
7506 * or width-for-height).
7508 * The width and height used to compute the preferred height and preferred
7509 * width are the actor's natural ones.
7511 * If you need to control the height for the preferred width, or the width for
7512 * the preferred height, you should use clutter_actor_get_preferred_width()
7513 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7514 * geometry management using the #ClutterActor:request-mode property.
7519 clutter_actor_get_preferred_size (ClutterActor *self,
7520 gfloat *min_width_p,
7521 gfloat *min_height_p,
7522 gfloat *natural_width_p,
7523 gfloat *natural_height_p)
7525 ClutterActorPrivate *priv;
7526 gfloat min_width, min_height;
7527 gfloat natural_width, natural_height;
7529 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7533 min_width = min_height = 0;
7534 natural_width = natural_height = 0;
7536 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7538 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7539 clutter_actor_get_preferred_width (self, -1,
7542 clutter_actor_get_preferred_height (self, natural_width,
7548 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7549 clutter_actor_get_preferred_height (self, -1,
7552 clutter_actor_get_preferred_width (self, natural_height,
7558 *min_width_p = min_width;
7561 *min_height_p = min_height;
7563 if (natural_width_p)
7564 *natural_width_p = natural_width;
7566 if (natural_height_p)
7567 *natural_height_p = natural_height;
7572 * @align: a #ClutterActorAlign
7573 * @direction: a #ClutterTextDirection
7575 * Retrieves the correct alignment depending on the text direction
7577 * Return value: the effective alignment
7579 static ClutterActorAlign
7580 effective_align (ClutterActorAlign align,
7581 ClutterTextDirection direction)
7583 ClutterActorAlign res;
7587 case CLUTTER_ACTOR_ALIGN_START:
7588 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7589 ? CLUTTER_ACTOR_ALIGN_END
7590 : CLUTTER_ACTOR_ALIGN_START;
7593 case CLUTTER_ACTOR_ALIGN_END:
7594 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7595 ? CLUTTER_ACTOR_ALIGN_START
7596 : CLUTTER_ACTOR_ALIGN_END;
7608 adjust_for_margin (float margin_start,
7610 float *minimum_size,
7611 float *natural_size,
7612 float *allocated_start,
7613 float *allocated_end)
7615 *minimum_size -= (margin_start + margin_end);
7616 *natural_size -= (margin_start + margin_end);
7617 *allocated_start += margin_start;
7618 *allocated_end -= margin_end;
7622 adjust_for_alignment (ClutterActorAlign alignment,
7624 float *allocated_start,
7625 float *allocated_end)
7627 float allocated_size = *allocated_end - *allocated_start;
7631 case CLUTTER_ACTOR_ALIGN_FILL:
7635 case CLUTTER_ACTOR_ALIGN_START:
7637 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7640 case CLUTTER_ACTOR_ALIGN_END:
7641 if (allocated_size > natural_size)
7643 *allocated_start += (allocated_size - natural_size);
7644 *allocated_end = *allocated_start + natural_size;
7648 case CLUTTER_ACTOR_ALIGN_CENTER:
7649 if (allocated_size > natural_size)
7651 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7652 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7659 * clutter_actor_adjust_width:
7660 * @self: a #ClutterActor
7661 * @minimum_width: (inout): the actor's preferred minimum width, which
7662 * will be adjusted depending on the margin
7663 * @natural_width: (inout): the actor's preferred natural width, which
7664 * will be adjusted depending on the margin
7665 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7666 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7668 * Adjusts the preferred and allocated position and size of an actor,
7669 * depending on the margin and alignment properties.
7672 clutter_actor_adjust_width (ClutterActor *self,
7673 gfloat *minimum_width,
7674 gfloat *natural_width,
7675 gfloat *adjusted_x1,
7676 gfloat *adjusted_x2)
7678 ClutterTextDirection text_dir;
7679 const ClutterLayoutInfo *info;
7681 info = _clutter_actor_get_layout_info_or_defaults (self);
7682 text_dir = clutter_actor_get_text_direction (self);
7684 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7686 /* this will tweak natural_width to remove the margin, so that
7687 * adjust_for_alignment() will use the correct size
7689 adjust_for_margin (info->margin.left, info->margin.right,
7690 minimum_width, natural_width,
7691 adjusted_x1, adjusted_x2);
7693 adjust_for_alignment (effective_align (info->x_align, text_dir),
7695 adjusted_x1, adjusted_x2);
7699 * clutter_actor_adjust_height:
7700 * @self: a #ClutterActor
7701 * @minimum_height: (inout): the actor's preferred minimum height, which
7702 * will be adjusted depending on the margin
7703 * @natural_height: (inout): the actor's preferred natural height, which
7704 * will be adjusted depending on the margin
7705 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7706 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7708 * Adjusts the preferred and allocated position and size of an actor,
7709 * depending on the margin and alignment properties.
7712 clutter_actor_adjust_height (ClutterActor *self,
7713 gfloat *minimum_height,
7714 gfloat *natural_height,
7715 gfloat *adjusted_y1,
7716 gfloat *adjusted_y2)
7718 const ClutterLayoutInfo *info;
7720 info = _clutter_actor_get_layout_info_or_defaults (self);
7722 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7724 /* this will tweak natural_height to remove the margin, so that
7725 * adjust_for_alignment() will use the correct size
7727 adjust_for_margin (info->margin.top, info->margin.bottom,
7728 minimum_height, natural_height,
7732 /* we don't use effective_align() here, because text direction
7733 * only affects the horizontal axis
7735 adjust_for_alignment (info->y_align,
7742 /* looks for a cached size request for this for_size. If not
7743 * found, returns the oldest entry so it can be overwritten */
7745 _clutter_actor_get_cached_size_request (gfloat for_size,
7746 SizeRequest *cached_size_requests,
7747 SizeRequest **result)
7751 *result = &cached_size_requests[0];
7753 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7757 sr = &cached_size_requests[i];
7760 sr->for_size == for_size)
7762 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7766 else if (sr->age < (*result)->age)
7772 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7778 * clutter_actor_get_preferred_width:
7779 * @self: A #ClutterActor
7780 * @for_height: available height when computing the preferred width,
7781 * or a negative value to indicate that no height is defined
7782 * @min_width_p: (out) (allow-none): return location for minimum width,
7784 * @natural_width_p: (out) (allow-none): return location for the natural
7787 * Computes the requested minimum and natural widths for an actor,
7788 * optionally depending on the specified height, or if they are
7789 * already computed, returns the cached values.
7791 * An actor may not get its request - depending on the layout
7792 * manager that's in effect.
7794 * A request should not incorporate the actor's scale or anchor point;
7795 * those transformations do not affect layout, only rendering.
7800 clutter_actor_get_preferred_width (ClutterActor *self,
7802 gfloat *min_width_p,
7803 gfloat *natural_width_p)
7805 float request_min_width, request_natural_width;
7806 SizeRequest *cached_size_request;
7807 const ClutterLayoutInfo *info;
7808 ClutterActorPrivate *priv;
7809 gboolean found_in_cache;
7811 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7815 info = _clutter_actor_get_layout_info_or_defaults (self);
7817 /* we shortcircuit the case of a fixed size set using set_width() */
7818 if (priv->min_width_set && priv->natural_width_set)
7820 if (min_width_p != NULL)
7821 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7823 if (natural_width_p != NULL)
7824 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7829 /* the remaining cases are:
7831 * - either min_width or natural_width have been set
7832 * - neither min_width or natural_width have been set
7834 * in both cases, we go through the cache (and through the actor in case
7835 * of cache misses) and determine the authoritative value depending on
7839 if (!priv->needs_width_request)
7842 _clutter_actor_get_cached_size_request (for_height,
7843 priv->width_requests,
7844 &cached_size_request);
7848 /* if the actor needs a width request we use the first slot */
7849 found_in_cache = FALSE;
7850 cached_size_request = &priv->width_requests[0];
7853 if (!found_in_cache)
7855 gfloat minimum_width, natural_width;
7856 ClutterActorClass *klass;
7858 minimum_width = natural_width = 0;
7860 /* adjust for the margin */
7861 if (for_height >= 0)
7863 for_height -= (info->margin.top + info->margin.bottom);
7868 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7870 klass = CLUTTER_ACTOR_GET_CLASS (self);
7871 klass->get_preferred_width (self, for_height,
7875 /* adjust for the margin */
7876 minimum_width += (info->margin.left + info->margin.right);
7877 natural_width += (info->margin.left + info->margin.right);
7879 /* Due to accumulated float errors, it's better not to warn
7880 * on this, but just fix it.
7882 if (natural_width < minimum_width)
7883 natural_width = minimum_width;
7885 cached_size_request->min_size = minimum_width;
7886 cached_size_request->natural_size = natural_width;
7887 cached_size_request->for_size = for_height;
7888 cached_size_request->age = priv->cached_width_age;
7890 priv->cached_width_age += 1;
7891 priv->needs_width_request = FALSE;
7894 if (!priv->min_width_set)
7895 request_min_width = cached_size_request->min_size;
7897 request_min_width = info->min_width;
7899 if (!priv->natural_width_set)
7900 request_natural_width = cached_size_request->natural_size;
7902 request_natural_width = info->natural_width;
7905 *min_width_p = request_min_width;
7907 if (natural_width_p)
7908 *natural_width_p = request_natural_width;
7912 * clutter_actor_get_preferred_height:
7913 * @self: A #ClutterActor
7914 * @for_width: available width to assume in computing desired height,
7915 * or a negative value to indicate that no width is defined
7916 * @min_height_p: (out) (allow-none): return location for minimum height,
7918 * @natural_height_p: (out) (allow-none): return location for natural
7921 * Computes the requested minimum and natural heights for an actor,
7922 * or if they are already computed, returns the cached values.
7924 * An actor may not get its request - depending on the layout
7925 * manager that's in effect.
7927 * A request should not incorporate the actor's scale or anchor point;
7928 * those transformations do not affect layout, only rendering.
7933 clutter_actor_get_preferred_height (ClutterActor *self,
7935 gfloat *min_height_p,
7936 gfloat *natural_height_p)
7938 float request_min_height, request_natural_height;
7939 SizeRequest *cached_size_request;
7940 const ClutterLayoutInfo *info;
7941 ClutterActorPrivate *priv;
7942 gboolean found_in_cache;
7944 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7948 info = _clutter_actor_get_layout_info_or_defaults (self);
7950 /* we shortcircuit the case of a fixed size set using set_height() */
7951 if (priv->min_height_set && priv->natural_height_set)
7953 if (min_height_p != NULL)
7954 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7956 if (natural_height_p != NULL)
7957 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7962 /* the remaining cases are:
7964 * - either min_height or natural_height have been set
7965 * - neither min_height or natural_height have been set
7967 * in both cases, we go through the cache (and through the actor in case
7968 * of cache misses) and determine the authoritative value depending on
7972 if (!priv->needs_height_request)
7975 _clutter_actor_get_cached_size_request (for_width,
7976 priv->height_requests,
7977 &cached_size_request);
7981 found_in_cache = FALSE;
7982 cached_size_request = &priv->height_requests[0];
7985 if (!found_in_cache)
7987 gfloat minimum_height, natural_height;
7988 ClutterActorClass *klass;
7990 minimum_height = natural_height = 0;
7992 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7994 /* adjust for margin */
7997 for_width -= (info->margin.left + info->margin.right);
8002 klass = CLUTTER_ACTOR_GET_CLASS (self);
8003 klass->get_preferred_height (self, for_width,
8007 /* adjust for margin */
8008 minimum_height += (info->margin.top + info->margin.bottom);
8009 natural_height += (info->margin.top + info->margin.bottom);
8011 /* Due to accumulated float errors, it's better not to warn
8012 * on this, but just fix it.
8014 if (natural_height < minimum_height)
8015 natural_height = minimum_height;
8017 cached_size_request->min_size = minimum_height;
8018 cached_size_request->natural_size = natural_height;
8019 cached_size_request->for_size = for_width;
8020 cached_size_request->age = priv->cached_height_age;
8022 priv->cached_height_age += 1;
8023 priv->needs_height_request = FALSE;
8026 if (!priv->min_height_set)
8027 request_min_height = cached_size_request->min_size;
8029 request_min_height = info->min_height;
8031 if (!priv->natural_height_set)
8032 request_natural_height = cached_size_request->natural_size;
8034 request_natural_height = info->natural_height;
8037 *min_height_p = request_min_height;
8039 if (natural_height_p)
8040 *natural_height_p = request_natural_height;
8044 * clutter_actor_get_allocation_box:
8045 * @self: A #ClutterActor
8046 * @box: (out): the function fills this in with the actor's allocation
8048 * Gets the layout box an actor has been assigned. The allocation can
8049 * only be assumed valid inside a paint() method; anywhere else, it
8050 * may be out-of-date.
8052 * An allocation does not incorporate the actor's scale or anchor point;
8053 * those transformations do not affect layout, only rendering.
8055 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8056 * of functions inside the implementation of the get_preferred_width()
8057 * or get_preferred_height() virtual functions.</note>
8062 clutter_actor_get_allocation_box (ClutterActor *self,
8063 ClutterActorBox *box)
8065 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8067 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8068 * which limits calling get_allocation to inside paint() basically; or
8069 * we can 2) force a layout, which could be expensive if someone calls
8070 * get_allocation somewhere silly; or we can 3) just return the latest
8071 * value, allowing it to be out-of-date, and assume people know what
8074 * The least-surprises approach that keeps existing code working is
8075 * likely to be 2). People can end up doing some inefficient things,
8076 * though, and in general code that requires 2) is probably broken.
8079 /* this implements 2) */
8080 if (G_UNLIKELY (self->priv->needs_allocation))
8082 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8084 /* do not queue a relayout on an unparented actor */
8086 _clutter_stage_maybe_relayout (stage);
8089 /* commenting out the code above and just keeping this assigment
8092 *box = self->priv->allocation;
8096 * clutter_actor_get_allocation_geometry:
8097 * @self: A #ClutterActor
8098 * @geom: (out): allocation geometry in pixels
8100 * Gets the layout box an actor has been assigned. The allocation can
8101 * only be assumed valid inside a paint() method; anywhere else, it
8102 * may be out-of-date.
8104 * An allocation does not incorporate the actor's scale or anchor point;
8105 * those transformations do not affect layout, only rendering.
8107 * The returned rectangle is in pixels.
8112 clutter_actor_get_allocation_geometry (ClutterActor *self,
8113 ClutterGeometry *geom)
8115 ClutterActorBox box;
8117 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8118 g_return_if_fail (geom != NULL);
8120 clutter_actor_get_allocation_box (self, &box);
8122 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8123 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8124 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8125 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8129 clutter_actor_update_constraints (ClutterActor *self,
8130 ClutterActorBox *allocation)
8132 ClutterActorPrivate *priv = self->priv;
8133 const GList *constraints, *l;
8135 if (priv->constraints == NULL)
8138 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8139 for (l = constraints; l != NULL; l = l->next)
8141 ClutterConstraint *constraint = l->data;
8142 ClutterActorMeta *meta = l->data;
8144 if (clutter_actor_meta_get_enabled (meta))
8146 _clutter_constraint_update_allocation (constraint,
8154 * clutter_actor_adjust_allocation:
8155 * @self: a #ClutterActor
8156 * @allocation: (inout): the allocation to adjust
8158 * Adjusts the passed allocation box taking into account the actor's
8159 * layout information, like alignment, expansion, and margin.
8162 clutter_actor_adjust_allocation (ClutterActor *self,
8163 ClutterActorBox *allocation)
8165 ClutterActorBox adj_allocation;
8166 float alloc_width, alloc_height;
8167 float min_width, min_height;
8168 float nat_width, nat_height;
8169 ClutterRequestMode req_mode;
8171 adj_allocation = *allocation;
8173 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8175 /* we want to hit the cache, so we use the public API */
8176 req_mode = clutter_actor_get_request_mode (self);
8178 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8180 clutter_actor_get_preferred_width (self, -1,
8183 clutter_actor_get_preferred_height (self, alloc_width,
8187 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8189 clutter_actor_get_preferred_height (self, -1,
8192 clutter_actor_get_preferred_height (self, alloc_height,
8197 #ifdef CLUTTER_ENABLE_DEBUG
8198 /* warn about underallocations */
8199 if (_clutter_diagnostic_enabled () &&
8200 (floorf (min_width - alloc_width) > 0 ||
8201 floorf (min_height - alloc_height) > 0))
8203 ClutterActor *parent = clutter_actor_get_parent (self);
8205 /* the only actors that are allowed to be underallocated are the Stage,
8206 * as it doesn't have an implicit size, and Actors that specifically
8207 * told us that they want to opt-out from layout control mechanisms
8208 * through the NO_LAYOUT escape hatch.
8210 if (parent != NULL &&
8211 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8213 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8214 "of %.2f x %.2f from its parent actor '%s', but its "
8215 "requested minimum size is of %.2f x %.2f",
8216 _clutter_actor_get_debug_name (self),
8217 alloc_width, alloc_height,
8218 _clutter_actor_get_debug_name (parent),
8219 min_width, min_height);
8224 clutter_actor_adjust_width (self,
8228 &adj_allocation.x2);
8230 clutter_actor_adjust_height (self,
8234 &adj_allocation.y2);
8236 /* we maintain the invariant that an allocation cannot be adjusted
8237 * to be outside the parent-given box
8239 if (adj_allocation.x1 < allocation->x1 ||
8240 adj_allocation.y1 < allocation->y1 ||
8241 adj_allocation.x2 > allocation->x2 ||
8242 adj_allocation.y2 > allocation->y2)
8244 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8245 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8246 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8247 _clutter_actor_get_debug_name (self),
8248 adj_allocation.x1, adj_allocation.y1,
8249 adj_allocation.x2 - adj_allocation.x1,
8250 adj_allocation.y2 - adj_allocation.y1,
8251 allocation->x1, allocation->y1,
8252 allocation->x2 - allocation->x1,
8253 allocation->y2 - allocation->y1);
8257 *allocation = adj_allocation;
8261 * clutter_actor_allocate:
8262 * @self: A #ClutterActor
8263 * @box: new allocation of the actor, in parent-relative coordinates
8264 * @flags: flags that control the allocation
8266 * Called by the parent of an actor to assign the actor its size.
8267 * Should never be called by applications (except when implementing
8268 * a container or layout manager).
8270 * Actors can know from their allocation box whether they have moved
8271 * with respect to their parent actor. The @flags parameter describes
8272 * additional information about the allocation, for instance whether
8273 * the parent has moved with respect to the stage, for example because
8274 * a grandparent's origin has moved.
8279 clutter_actor_allocate (ClutterActor *self,
8280 const ClutterActorBox *box,
8281 ClutterAllocationFlags flags)
8283 ClutterActorPrivate *priv;
8284 ClutterActorClass *klass;
8285 ClutterActorBox old_allocation, real_allocation;
8286 gboolean origin_changed, child_moved, size_changed;
8287 gboolean stage_allocation_changed;
8289 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8290 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8292 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8293 "which isn't a descendent of the stage!\n",
8294 self, _clutter_actor_get_debug_name (self));
8300 old_allocation = priv->allocation;
8301 real_allocation = *box;
8303 /* constraints are allowed to modify the allocation only here; we do
8304 * this prior to all the other checks so that we can bail out if the
8305 * allocation did not change
8307 clutter_actor_update_constraints (self, &real_allocation);
8309 /* adjust the allocation depending on the align/margin properties */
8310 clutter_actor_adjust_allocation (self, &real_allocation);
8312 if (real_allocation.x2 < real_allocation.x1 ||
8313 real_allocation.y2 < real_allocation.y1)
8315 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8316 _clutter_actor_get_debug_name (self),
8317 real_allocation.x2 - real_allocation.x1,
8318 real_allocation.y2 - real_allocation.y1);
8321 /* we allow 0-sized actors, but not negative-sized ones */
8322 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8323 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8325 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8327 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8328 real_allocation.y1 != old_allocation.y1);
8330 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8331 real_allocation.y2 != old_allocation.y2);
8333 if (origin_changed || child_moved || size_changed)
8334 stage_allocation_changed = TRUE;
8336 stage_allocation_changed = FALSE;
8338 /* If we get an allocation "out of the blue"
8339 * (we did not queue relayout), then we want to
8340 * ignore it. But if we have needs_allocation set,
8341 * we want to guarantee that allocate() virtual
8342 * method is always called, i.e. that queue_relayout()
8343 * always results in an allocate() invocation on
8346 * The optimization here is to avoid re-allocating
8347 * actors that did not queue relayout and were
8350 if (!priv->needs_allocation && !stage_allocation_changed)
8352 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8356 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8357 * clutter_actor_allocate(), it indicates whether the parent has its
8358 * absolute origin moved; when passed in to ClutterActor::allocate()
8359 * virtual method though, it indicates whether the child has its
8360 * absolute origin moved. So we set it when child_moved is TRUE
8363 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8365 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8367 klass = CLUTTER_ACTOR_GET_CLASS (self);
8368 klass->allocate (self, &real_allocation, flags);
8370 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8372 if (stage_allocation_changed)
8373 clutter_actor_queue_redraw (self);
8377 * clutter_actor_set_allocation:
8378 * @self: a #ClutterActor
8379 * @box: a #ClutterActorBox
8380 * @flags: allocation flags
8382 * Stores the allocation of @self as defined by @box.
8384 * This function can only be called from within the implementation of
8385 * the #ClutterActorClass.allocate() virtual function.
8387 * The allocation should have been adjusted to take into account constraints,
8388 * alignment, and margin properties. If you are implementing a #ClutterActor
8389 * subclass that provides its own layout management policy for its children
8390 * instead of using a #ClutterLayoutManager delegate, you should not call
8391 * this function on the children of @self; instead, you should call
8392 * clutter_actor_allocate(), which will adjust the allocation box for
8395 * This function should only be used by subclasses of #ClutterActor
8396 * that wish to store their allocation but cannot chain up to the
8397 * parent's implementation; the default implementation of the
8398 * #ClutterActorClass.allocate() virtual function will call this
8401 * It is important to note that, while chaining up was the recommended
8402 * behaviour for #ClutterActor subclasses prior to the introduction of
8403 * this function, it is recommended to call clutter_actor_set_allocation()
8406 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8407 * to handle the allocation of its children, this function will call
8408 * the clutter_layout_manager_allocate() function only if the
8409 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8410 * expected that the subclass will call clutter_layout_manager_allocate()
8411 * by itself. For instance, the following code:
8415 * my_actor_allocate (ClutterActor *actor,
8416 * const ClutterActorBox *allocation,
8417 * ClutterAllocationFlags flags)
8419 * ClutterActorBox new_alloc;
8420 * ClutterAllocationFlags new_flags;
8422 * adjust_allocation (allocation, &new_alloc);
8424 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8426 * /* this will use the layout manager set on the actor */
8427 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8431 * is equivalent to this:
8435 * my_actor_allocate (ClutterActor *actor,
8436 * const ClutterActorBox *allocation,
8437 * ClutterAllocationFlags flags)
8439 * ClutterLayoutManager *layout;
8440 * ClutterActorBox new_alloc;
8442 * adjust_allocation (allocation, &new_alloc);
8444 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8446 * layout = clutter_actor_get_layout_manager (actor);
8447 * clutter_layout_manager_allocate (layout,
8448 * CLUTTER_CONTAINER (actor),
8457 clutter_actor_set_allocation (ClutterActor *self,
8458 const ClutterActorBox *box,
8459 ClutterAllocationFlags flags)
8461 ClutterActorPrivate *priv;
8464 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8465 g_return_if_fail (box != NULL);
8467 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8469 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8470 "can only be called from within the implementation of "
8471 "the ClutterActor::allocate() virtual function.");
8477 g_object_freeze_notify (G_OBJECT (self));
8479 changed = clutter_actor_set_allocation_internal (self, box, flags);
8481 /* we allocate our children before we notify changes in our geometry,
8482 * so that people connecting to properties will be able to get valid
8483 * data out of the sub-tree of the scene graph that has this actor at
8486 clutter_actor_maybe_layout_children (self, box, flags);
8490 ClutterActorBox signal_box = priv->allocation;
8491 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8493 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8498 g_object_thaw_notify (G_OBJECT (self));
8502 * clutter_actor_set_geometry:
8503 * @self: A #ClutterActor
8504 * @geometry: A #ClutterGeometry
8506 * Sets the actor's fixed position and forces its minimum and natural
8507 * size, in pixels. This means the untransformed actor will have the
8508 * given geometry. This is the same as calling clutter_actor_set_position()
8509 * and clutter_actor_set_size().
8511 * Deprecated: 1.10: Use clutter_actor_set_position() and
8512 * clutter_actor_set_size() instead.
8515 clutter_actor_set_geometry (ClutterActor *self,
8516 const ClutterGeometry *geometry)
8518 g_object_freeze_notify (G_OBJECT (self));
8520 clutter_actor_set_position (self, geometry->x, geometry->y);
8521 clutter_actor_set_size (self, geometry->width, geometry->height);
8523 g_object_thaw_notify (G_OBJECT (self));
8527 * clutter_actor_get_geometry:
8528 * @self: A #ClutterActor
8529 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8531 * Gets the size and position of an actor relative to its parent
8532 * actor. This is the same as calling clutter_actor_get_position() and
8533 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8534 * requested size and position if the actor's allocation is invalid.
8536 * Deprecated: 1.10: Use clutter_actor_get_position() and
8537 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8541 clutter_actor_get_geometry (ClutterActor *self,
8542 ClutterGeometry *geometry)
8544 gfloat x, y, width, height;
8546 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8547 g_return_if_fail (geometry != NULL);
8549 clutter_actor_get_position (self, &x, &y);
8550 clutter_actor_get_size (self, &width, &height);
8552 geometry->x = (int) x;
8553 geometry->y = (int) y;
8554 geometry->width = (int) width;
8555 geometry->height = (int) height;
8559 * clutter_actor_set_position:
8560 * @self: A #ClutterActor
8561 * @x: New left position of actor in pixels.
8562 * @y: New top position of actor in pixels.
8564 * Sets the actor's fixed position in pixels relative to any parent
8567 * If a layout manager is in use, this position will override the
8568 * layout manager and force a fixed position.
8571 clutter_actor_set_position (ClutterActor *self,
8575 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8577 g_object_freeze_notify (G_OBJECT (self));
8579 clutter_actor_set_x (self, x);
8580 clutter_actor_set_y (self, y);
8582 g_object_thaw_notify (G_OBJECT (self));
8586 * clutter_actor_get_fixed_position_set:
8587 * @self: A #ClutterActor
8589 * Checks whether an actor has a fixed position set (and will thus be
8590 * unaffected by any layout manager).
8592 * Return value: %TRUE if the fixed position is set on the actor
8597 clutter_actor_get_fixed_position_set (ClutterActor *self)
8599 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8601 return self->priv->position_set;
8605 * clutter_actor_set_fixed_position_set:
8606 * @self: A #ClutterActor
8607 * @is_set: whether to use fixed position
8609 * Sets whether an actor has a fixed position set (and will thus be
8610 * unaffected by any layout manager).
8615 clutter_actor_set_fixed_position_set (ClutterActor *self,
8618 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8620 if (self->priv->position_set == (is_set != FALSE))
8623 self->priv->position_set = is_set != FALSE;
8624 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8626 clutter_actor_queue_relayout (self);
8630 * clutter_actor_move_by:
8631 * @self: A #ClutterActor
8632 * @dx: Distance to move Actor on X axis.
8633 * @dy: Distance to move Actor on Y axis.
8635 * Moves an actor by the specified distance relative to its current
8636 * position in pixels.
8638 * This function modifies the fixed position of an actor and thus removes
8639 * it from any layout management. Another way to move an actor is with an
8640 * anchor point, see clutter_actor_set_anchor_point().
8645 clutter_actor_move_by (ClutterActor *self,
8649 const ClutterLayoutInfo *info;
8652 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8654 info = _clutter_actor_get_layout_info_or_defaults (self);
8658 clutter_actor_set_position (self, x + dx, y + dy);
8662 clutter_actor_set_min_width (ClutterActor *self,
8665 ClutterActorPrivate *priv = self->priv;
8666 ClutterActorBox old = { 0, };
8667 ClutterLayoutInfo *info;
8669 /* if we are setting the size on a top-level actor and the
8670 * backend only supports static top-levels (e.g. framebuffers)
8671 * then we ignore the passed value and we override it with
8672 * the stage implementation's preferred size.
8674 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8675 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8678 info = _clutter_actor_get_layout_info (self);
8680 if (priv->min_width_set && min_width == info->min_width)
8683 g_object_freeze_notify (G_OBJECT (self));
8685 clutter_actor_store_old_geometry (self, &old);
8687 info->min_width = min_width;
8688 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8689 clutter_actor_set_min_width_set (self, TRUE);
8691 clutter_actor_notify_if_geometry_changed (self, &old);
8693 g_object_thaw_notify (G_OBJECT (self));
8695 clutter_actor_queue_relayout (self);
8699 clutter_actor_set_min_height (ClutterActor *self,
8703 ClutterActorPrivate *priv = self->priv;
8704 ClutterActorBox old = { 0, };
8705 ClutterLayoutInfo *info;
8707 /* if we are setting the size on a top-level actor and the
8708 * backend only supports static top-levels (e.g. framebuffers)
8709 * then we ignore the passed value and we override it with
8710 * the stage implementation's preferred size.
8712 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8713 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8716 info = _clutter_actor_get_layout_info (self);
8718 if (priv->min_height_set && min_height == info->min_height)
8721 g_object_freeze_notify (G_OBJECT (self));
8723 clutter_actor_store_old_geometry (self, &old);
8725 info->min_height = min_height;
8726 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8727 clutter_actor_set_min_height_set (self, TRUE);
8729 clutter_actor_notify_if_geometry_changed (self, &old);
8731 g_object_thaw_notify (G_OBJECT (self));
8733 clutter_actor_queue_relayout (self);
8737 clutter_actor_set_natural_width (ClutterActor *self,
8738 gfloat natural_width)
8740 ClutterActorPrivate *priv = self->priv;
8741 ClutterActorBox old = { 0, };
8742 ClutterLayoutInfo *info;
8744 /* if we are setting the size on a top-level actor and the
8745 * backend only supports static top-levels (e.g. framebuffers)
8746 * then we ignore the passed value and we override it with
8747 * the stage implementation's preferred size.
8749 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8750 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8753 info = _clutter_actor_get_layout_info (self);
8755 if (priv->natural_width_set && natural_width == info->natural_width)
8758 g_object_freeze_notify (G_OBJECT (self));
8760 clutter_actor_store_old_geometry (self, &old);
8762 info->natural_width = natural_width;
8763 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8764 clutter_actor_set_natural_width_set (self, TRUE);
8766 clutter_actor_notify_if_geometry_changed (self, &old);
8768 g_object_thaw_notify (G_OBJECT (self));
8770 clutter_actor_queue_relayout (self);
8774 clutter_actor_set_natural_height (ClutterActor *self,
8775 gfloat natural_height)
8777 ClutterActorPrivate *priv = self->priv;
8778 ClutterActorBox old = { 0, };
8779 ClutterLayoutInfo *info;
8781 /* if we are setting the size on a top-level actor and the
8782 * backend only supports static top-levels (e.g. framebuffers)
8783 * then we ignore the passed value and we override it with
8784 * the stage implementation's preferred size.
8786 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8787 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8790 info = _clutter_actor_get_layout_info (self);
8792 if (priv->natural_height_set && natural_height == info->natural_height)
8795 g_object_freeze_notify (G_OBJECT (self));
8797 clutter_actor_store_old_geometry (self, &old);
8799 info->natural_height = natural_height;
8800 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8801 clutter_actor_set_natural_height_set (self, TRUE);
8803 clutter_actor_notify_if_geometry_changed (self, &old);
8805 g_object_thaw_notify (G_OBJECT (self));
8807 clutter_actor_queue_relayout (self);
8811 clutter_actor_set_min_width_set (ClutterActor *self,
8812 gboolean use_min_width)
8814 ClutterActorPrivate *priv = self->priv;
8815 ClutterActorBox old = { 0, };
8817 if (priv->min_width_set == (use_min_width != FALSE))
8820 clutter_actor_store_old_geometry (self, &old);
8822 priv->min_width_set = use_min_width != FALSE;
8823 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8825 clutter_actor_notify_if_geometry_changed (self, &old);
8827 clutter_actor_queue_relayout (self);
8831 clutter_actor_set_min_height_set (ClutterActor *self,
8832 gboolean use_min_height)
8834 ClutterActorPrivate *priv = self->priv;
8835 ClutterActorBox old = { 0, };
8837 if (priv->min_height_set == (use_min_height != FALSE))
8840 clutter_actor_store_old_geometry (self, &old);
8842 priv->min_height_set = use_min_height != FALSE;
8843 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8845 clutter_actor_notify_if_geometry_changed (self, &old);
8847 clutter_actor_queue_relayout (self);
8851 clutter_actor_set_natural_width_set (ClutterActor *self,
8852 gboolean use_natural_width)
8854 ClutterActorPrivate *priv = self->priv;
8855 ClutterActorBox old = { 0, };
8857 if (priv->natural_width_set == (use_natural_width != FALSE))
8860 clutter_actor_store_old_geometry (self, &old);
8862 priv->natural_width_set = use_natural_width != FALSE;
8863 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8865 clutter_actor_notify_if_geometry_changed (self, &old);
8867 clutter_actor_queue_relayout (self);
8871 clutter_actor_set_natural_height_set (ClutterActor *self,
8872 gboolean use_natural_height)
8874 ClutterActorPrivate *priv = self->priv;
8875 ClutterActorBox old = { 0, };
8877 if (priv->natural_height_set == (use_natural_height != FALSE))
8880 clutter_actor_store_old_geometry (self, &old);
8882 priv->natural_height_set = use_natural_height != FALSE;
8883 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8885 clutter_actor_notify_if_geometry_changed (self, &old);
8887 clutter_actor_queue_relayout (self);
8891 * clutter_actor_set_request_mode:
8892 * @self: a #ClutterActor
8893 * @mode: the request mode
8895 * Sets the geometry request mode of @self.
8897 * The @mode determines the order for invoking
8898 * clutter_actor_get_preferred_width() and
8899 * clutter_actor_get_preferred_height()
8904 clutter_actor_set_request_mode (ClutterActor *self,
8905 ClutterRequestMode mode)
8907 ClutterActorPrivate *priv;
8909 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8913 if (priv->request_mode == mode)
8916 priv->request_mode = mode;
8918 priv->needs_width_request = TRUE;
8919 priv->needs_height_request = TRUE;
8921 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8923 clutter_actor_queue_relayout (self);
8927 * clutter_actor_get_request_mode:
8928 * @self: a #ClutterActor
8930 * Retrieves the geometry request mode of @self
8932 * Return value: the request mode for the actor
8937 clutter_actor_get_request_mode (ClutterActor *self)
8939 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8940 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8942 return self->priv->request_mode;
8945 /* variant of set_width() without checks and without notification
8946 * freeze+thaw, for internal usage only
8949 clutter_actor_set_width_internal (ClutterActor *self,
8954 /* the Stage will use the :min-width to control the minimum
8955 * width to be resized to, so we should not be setting it
8956 * along with the :natural-width
8958 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8959 clutter_actor_set_min_width (self, width);
8961 clutter_actor_set_natural_width (self, width);
8965 /* we only unset the :natural-width for the Stage */
8966 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8967 clutter_actor_set_min_width_set (self, FALSE);
8969 clutter_actor_set_natural_width_set (self, FALSE);
8973 /* variant of set_height() without checks and without notification
8974 * freeze+thaw, for internal usage only
8977 clutter_actor_set_height_internal (ClutterActor *self,
8982 /* see the comment above in set_width_internal() */
8983 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8984 clutter_actor_set_min_height (self, height);
8986 clutter_actor_set_natural_height (self, height);
8990 /* see the comment above in set_width_internal() */
8991 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8992 clutter_actor_set_min_height_set (self, FALSE);
8994 clutter_actor_set_natural_height_set (self, FALSE);
8999 * clutter_actor_set_size:
9000 * @self: A #ClutterActor
9001 * @width: New width of actor in pixels, or -1
9002 * @height: New height of actor in pixels, or -1
9004 * Sets the actor's size request in pixels. This overrides any
9005 * "normal" size request the actor would have. For example
9006 * a text actor might normally request the size of the text;
9007 * this function would force a specific size instead.
9009 * If @width and/or @height are -1 the actor will use its
9010 * "normal" size request instead of overriding it, i.e.
9011 * you can "unset" the size with -1.
9013 * This function sets or unsets both the minimum and natural size.
9016 clutter_actor_set_size (ClutterActor *self,
9020 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9022 g_object_freeze_notify (G_OBJECT (self));
9024 clutter_actor_set_width (self, width);
9025 clutter_actor_set_height (self, height);
9027 g_object_thaw_notify (G_OBJECT (self));
9031 * clutter_actor_get_size:
9032 * @self: A #ClutterActor
9033 * @width: (out) (allow-none): return location for the width, or %NULL.
9034 * @height: (out) (allow-none): return location for the height, or %NULL.
9036 * This function tries to "do what you mean" and return
9037 * the size an actor will have. If the actor has a valid
9038 * allocation, the allocation will be returned; otherwise,
9039 * the actors natural size request will be returned.
9041 * If you care whether you get the request vs. the allocation, you
9042 * should probably call a different function like
9043 * clutter_actor_get_allocation_box() or
9044 * clutter_actor_get_preferred_width().
9049 clutter_actor_get_size (ClutterActor *self,
9053 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9056 *width = clutter_actor_get_width (self);
9059 *height = clutter_actor_get_height (self);
9063 * clutter_actor_get_position:
9064 * @self: a #ClutterActor
9065 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9066 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9068 * This function tries to "do what you mean" and tell you where the
9069 * actor is, prior to any transformations. Retrieves the fixed
9070 * position of an actor in pixels, if one has been set; otherwise, if
9071 * the allocation is valid, returns the actor's allocated position;
9072 * otherwise, returns 0,0.
9074 * The returned position is in pixels.
9079 clutter_actor_get_position (ClutterActor *self,
9083 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9086 *x = clutter_actor_get_x (self);
9089 *y = clutter_actor_get_y (self);
9093 * clutter_actor_get_transformed_position:
9094 * @self: A #ClutterActor
9095 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9096 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9098 * Gets the absolute position of an actor, in pixels relative to the stage.
9103 clutter_actor_get_transformed_position (ClutterActor *self,
9110 v1.x = v1.y = v1.z = 0;
9111 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9121 * clutter_actor_get_transformed_size:
9122 * @self: A #ClutterActor
9123 * @width: (out) (allow-none): return location for the width, or %NULL
9124 * @height: (out) (allow-none): return location for the height, or %NULL
9126 * Gets the absolute size of an actor in pixels, taking into account the
9129 * If the actor has a valid allocation, the allocated size will be used.
9130 * If the actor has not a valid allocation then the preferred size will
9131 * be transformed and returned.
9133 * If you want the transformed allocation, see
9134 * clutter_actor_get_abs_allocation_vertices() instead.
9136 * <note>When the actor (or one of its ancestors) is rotated around the
9137 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9138 * as a generic quadrangle; in that case this function returns the size
9139 * of the smallest rectangle that encapsulates the entire quad. Please
9140 * note that in this case no assumptions can be made about the relative
9141 * position of this envelope to the absolute position of the actor, as
9142 * returned by clutter_actor_get_transformed_position(); if you need this
9143 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9144 * to get the coords of the actual quadrangle.</note>
9149 clutter_actor_get_transformed_size (ClutterActor *self,
9153 ClutterActorPrivate *priv;
9155 gfloat x_min, x_max, y_min, y_max;
9158 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9162 /* if the actor hasn't been allocated yet, get the preferred
9163 * size and transform that
9165 if (priv->needs_allocation)
9167 gfloat natural_width, natural_height;
9168 ClutterActorBox box;
9170 /* Make a fake allocation to transform.
9172 * NB: _clutter_actor_transform_and_project_box expects a box in
9173 * the actor's coordinate space... */
9178 natural_width = natural_height = 0;
9179 clutter_actor_get_preferred_size (self, NULL, NULL,
9183 box.x2 = natural_width;
9184 box.y2 = natural_height;
9186 _clutter_actor_transform_and_project_box (self, &box, v);
9189 clutter_actor_get_abs_allocation_vertices (self, v);
9191 x_min = x_max = v[0].x;
9192 y_min = y_max = v[0].y;
9194 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9210 *width = x_max - x_min;
9213 *height = y_max - y_min;
9217 * clutter_actor_get_width:
9218 * @self: A #ClutterActor
9220 * Retrieves the width of a #ClutterActor.
9222 * If the actor has a valid allocation, this function will return the
9223 * width of the allocated area given to the actor.
9225 * If the actor does not have a valid allocation, this function will
9226 * return the actor's natural width, that is the preferred width of
9229 * If you care whether you get the preferred width or the width that
9230 * has been assigned to the actor, you should probably call a different
9231 * function like clutter_actor_get_allocation_box() to retrieve the
9232 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9235 * If an actor has a fixed width, for instance a width that has been
9236 * assigned using clutter_actor_set_width(), the width returned will
9237 * be the same value.
9239 * Return value: the width of the actor, in pixels
9242 clutter_actor_get_width (ClutterActor *self)
9244 ClutterActorPrivate *priv;
9246 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9250 if (priv->needs_allocation)
9252 gfloat natural_width = 0;
9254 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9255 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9258 gfloat natural_height = 0;
9260 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9261 clutter_actor_get_preferred_width (self, natural_height,
9266 return natural_width;
9269 return priv->allocation.x2 - priv->allocation.x1;
9273 * clutter_actor_get_height:
9274 * @self: A #ClutterActor
9276 * Retrieves the height of a #ClutterActor.
9278 * If the actor has a valid allocation, this function will return the
9279 * height of the allocated area given to the actor.
9281 * If the actor does not have a valid allocation, this function will
9282 * return the actor's natural height, that is the preferred height of
9285 * If you care whether you get the preferred height or the height that
9286 * has been assigned to the actor, you should probably call a different
9287 * function like clutter_actor_get_allocation_box() to retrieve the
9288 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9291 * If an actor has a fixed height, for instance a height that has been
9292 * assigned using clutter_actor_set_height(), the height returned will
9293 * be the same value.
9295 * Return value: the height of the actor, in pixels
9298 clutter_actor_get_height (ClutterActor *self)
9300 ClutterActorPrivate *priv;
9302 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9306 if (priv->needs_allocation)
9308 gfloat natural_height = 0;
9310 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9312 gfloat natural_width = 0;
9314 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9315 clutter_actor_get_preferred_height (self, natural_width,
9316 NULL, &natural_height);
9319 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9321 return natural_height;
9324 return priv->allocation.y2 - priv->allocation.y1;
9328 * clutter_actor_set_width:
9329 * @self: A #ClutterActor
9330 * @width: Requested new width for the actor, in pixels, or -1
9332 * Forces a width on an actor, causing the actor's preferred width
9333 * and height (if any) to be ignored.
9335 * If @width is -1 the actor will use its preferred width request
9336 * instead of overriding it, i.e. you can "unset" the width with -1.
9338 * This function sets both the minimum and natural size of the actor.
9343 clutter_actor_set_width (ClutterActor *self,
9346 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9348 if (clutter_actor_get_easing_duration (self) != 0)
9350 ClutterTransition *transition;
9352 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9353 if (transition == NULL)
9355 float old_width = clutter_actor_get_width (self);
9357 transition = _clutter_actor_create_transition (self,
9358 obj_props[PROP_WIDTH],
9361 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9364 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9366 clutter_actor_queue_relayout (self);
9370 g_object_freeze_notify (G_OBJECT (self));
9372 clutter_actor_set_width_internal (self, width);
9374 g_object_thaw_notify (G_OBJECT (self));
9379 * clutter_actor_set_height:
9380 * @self: A #ClutterActor
9381 * @height: Requested new height for the actor, in pixels, or -1
9383 * Forces a height on an actor, causing the actor's preferred width
9384 * and height (if any) to be ignored.
9386 * If @height is -1 the actor will use its preferred height instead of
9387 * overriding it, i.e. you can "unset" the height with -1.
9389 * This function sets both the minimum and natural size of the actor.
9394 clutter_actor_set_height (ClutterActor *self,
9397 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9399 if (clutter_actor_get_easing_duration (self) != 0)
9401 ClutterTransition *transition;
9403 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9404 if (transition == NULL)
9406 float old_height = clutter_actor_get_height (self);
9408 transition = _clutter_actor_create_transition (self,
9409 obj_props[PROP_HEIGHT],
9412 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9415 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9417 clutter_actor_queue_relayout (self);
9421 g_object_freeze_notify (G_OBJECT (self));
9423 clutter_actor_set_height_internal (self, height);
9425 g_object_thaw_notify (G_OBJECT (self));
9430 clutter_actor_set_x_internal (ClutterActor *self,
9433 ClutterActorPrivate *priv = self->priv;
9434 ClutterLayoutInfo *linfo;
9435 ClutterActorBox old = { 0, };
9437 linfo = _clutter_actor_get_layout_info (self);
9439 if (priv->position_set && linfo->fixed_x == x)
9442 clutter_actor_store_old_geometry (self, &old);
9445 clutter_actor_set_fixed_position_set (self, TRUE);
9447 clutter_actor_notify_if_geometry_changed (self, &old);
9449 clutter_actor_queue_relayout (self);
9453 clutter_actor_set_y_internal (ClutterActor *self,
9456 ClutterActorPrivate *priv = self->priv;
9457 ClutterLayoutInfo *linfo;
9458 ClutterActorBox old = { 0, };
9460 linfo = _clutter_actor_get_layout_info (self);
9462 if (priv->position_set && linfo->fixed_y == y)
9465 clutter_actor_store_old_geometry (self, &old);
9468 clutter_actor_set_fixed_position_set (self, TRUE);
9470 clutter_actor_notify_if_geometry_changed (self, &old);
9474 * clutter_actor_set_x:
9475 * @self: a #ClutterActor
9476 * @x: the actor's position on the X axis
9478 * Sets the actor's X coordinate, relative to its parent, in pixels.
9480 * Overrides any layout manager and forces a fixed position for
9483 * The #ClutterActor:x property is animatable.
9488 clutter_actor_set_x (ClutterActor *self,
9491 const ClutterLayoutInfo *linfo;
9493 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9495 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9497 if (clutter_actor_get_easing_duration (self) != 0)
9499 ClutterTransition *transition;
9501 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9502 if (transition == NULL)
9504 transition = _clutter_actor_create_transition (self,
9509 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9512 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9514 clutter_actor_queue_relayout (self);
9517 clutter_actor_set_x_internal (self, x);
9521 * clutter_actor_set_y:
9522 * @self: a #ClutterActor
9523 * @y: the actor's position on the Y axis
9525 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9527 * Overrides any layout manager and forces a fixed position for
9530 * The #ClutterActor:y property is animatable.
9535 clutter_actor_set_y (ClutterActor *self,
9538 const ClutterLayoutInfo *linfo;
9540 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9542 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9544 if (clutter_actor_get_easing_duration (self) != 0)
9546 ClutterTransition *transition;
9548 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9549 if (transition == NULL)
9551 transition = _clutter_actor_create_transition (self,
9556 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9559 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9561 clutter_actor_queue_relayout (self);
9564 clutter_actor_set_y_internal (self, y);
9566 clutter_actor_queue_relayout (self);
9570 * clutter_actor_get_x:
9571 * @self: A #ClutterActor
9573 * Retrieves the X coordinate of a #ClutterActor.
9575 * This function tries to "do what you mean", by returning the
9576 * correct value depending on the actor's state.
9578 * If the actor has a valid allocation, this function will return
9579 * the X coordinate of the origin of the allocation box.
9581 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9582 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9583 * function will return that coordinate.
9585 * If both the allocation and a fixed position are missing, this function
9588 * Return value: the X coordinate, in pixels, ignoring any
9589 * transformation (i.e. scaling, rotation)
9592 clutter_actor_get_x (ClutterActor *self)
9594 ClutterActorPrivate *priv;
9596 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9600 if (priv->needs_allocation)
9602 if (priv->position_set)
9604 const ClutterLayoutInfo *info;
9606 info = _clutter_actor_get_layout_info_or_defaults (self);
9608 return info->fixed_x;
9614 return priv->allocation.x1;
9618 * clutter_actor_get_y:
9619 * @self: A #ClutterActor
9621 * Retrieves the Y coordinate of a #ClutterActor.
9623 * This function tries to "do what you mean", by returning the
9624 * correct value depending on the actor's state.
9626 * If the actor has a valid allocation, this function will return
9627 * the Y coordinate of the origin of the allocation box.
9629 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9630 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9631 * function will return that coordinate.
9633 * If both the allocation and a fixed position are missing, this function
9636 * Return value: the Y coordinate, in pixels, ignoring any
9637 * transformation (i.e. scaling, rotation)
9640 clutter_actor_get_y (ClutterActor *self)
9642 ClutterActorPrivate *priv;
9644 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9648 if (priv->needs_allocation)
9650 if (priv->position_set)
9652 const ClutterLayoutInfo *info;
9654 info = _clutter_actor_get_layout_info_or_defaults (self);
9656 return info->fixed_y;
9662 return priv->allocation.y1;
9666 * clutter_actor_set_scale:
9667 * @self: A #ClutterActor
9668 * @scale_x: double factor to scale actor by horizontally.
9669 * @scale_y: double factor to scale actor by vertically.
9671 * Scales an actor with the given factors. The scaling is relative to
9672 * the scale center and the anchor point. The scale center is
9673 * unchanged by this function and defaults to 0,0.
9675 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9681 clutter_actor_set_scale (ClutterActor *self,
9685 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9687 g_object_freeze_notify (G_OBJECT (self));
9689 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9690 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9692 g_object_thaw_notify (G_OBJECT (self));
9696 * clutter_actor_set_scale_full:
9697 * @self: A #ClutterActor
9698 * @scale_x: double factor to scale actor by horizontally.
9699 * @scale_y: double factor to scale actor by vertically.
9700 * @center_x: X coordinate of the center of the scale.
9701 * @center_y: Y coordinate of the center of the scale
9703 * Scales an actor with the given factors around the given center
9704 * point. The center point is specified in pixels relative to the
9705 * anchor point (usually the top left corner of the actor).
9707 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9713 clutter_actor_set_scale_full (ClutterActor *self,
9719 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9721 g_object_freeze_notify (G_OBJECT (self));
9723 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9724 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9725 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9726 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9728 g_object_thaw_notify (G_OBJECT (self));
9732 * clutter_actor_set_scale_with_gravity:
9733 * @self: A #ClutterActor
9734 * @scale_x: double factor to scale actor by horizontally.
9735 * @scale_y: double factor to scale actor by vertically.
9736 * @gravity: the location of the scale center expressed as a compass
9739 * Scales an actor with the given factors around the given
9740 * center point. The center point is specified as one of the compass
9741 * directions in #ClutterGravity. For example, setting it to north
9742 * will cause the top of the actor to remain unchanged and the rest of
9743 * the actor to expand left, right and downwards.
9745 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9751 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9754 ClutterGravity gravity)
9756 ClutterTransformInfo *info;
9759 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9761 obj = G_OBJECT (self);
9763 g_object_freeze_notify (obj);
9765 info = _clutter_actor_get_transform_info (self);
9766 info->scale_x = scale_x;
9767 info->scale_y = scale_y;
9769 if (gravity == CLUTTER_GRAVITY_NONE)
9770 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9772 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9774 self->priv->transform_valid = FALSE;
9776 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9777 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9778 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9779 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9780 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9782 clutter_actor_queue_redraw (self);
9784 g_object_thaw_notify (obj);
9788 * clutter_actor_get_scale:
9789 * @self: A #ClutterActor
9790 * @scale_x: (out) (allow-none): Location to store horizonal
9791 * scale factor, or %NULL.
9792 * @scale_y: (out) (allow-none): Location to store vertical
9793 * scale factor, or %NULL.
9795 * Retrieves an actors scale factors.
9800 clutter_actor_get_scale (ClutterActor *self,
9804 const ClutterTransformInfo *info;
9806 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9808 info = _clutter_actor_get_transform_info_or_defaults (self);
9811 *scale_x = info->scale_x;
9814 *scale_y = info->scale_y;
9818 * clutter_actor_get_scale_center:
9819 * @self: A #ClutterActor
9820 * @center_x: (out) (allow-none): Location to store the X position
9821 * of the scale center, or %NULL.
9822 * @center_y: (out) (allow-none): Location to store the Y position
9823 * of the scale center, or %NULL.
9825 * Retrieves the scale center coordinate in pixels relative to the top
9826 * left corner of the actor. If the scale center was specified using a
9827 * #ClutterGravity this will calculate the pixel offset using the
9828 * current size of the actor.
9833 clutter_actor_get_scale_center (ClutterActor *self,
9837 const ClutterTransformInfo *info;
9839 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9841 info = _clutter_actor_get_transform_info_or_defaults (self);
9843 clutter_anchor_coord_get_units (self, &info->scale_center,
9850 * clutter_actor_get_scale_gravity:
9851 * @self: A #ClutterActor
9853 * Retrieves the scale center as a compass direction. If the scale
9854 * center was specified in pixels or units this will return
9855 * %CLUTTER_GRAVITY_NONE.
9857 * Return value: the scale gravity
9862 clutter_actor_get_scale_gravity (ClutterActor *self)
9864 const ClutterTransformInfo *info;
9866 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9868 info = _clutter_actor_get_transform_info_or_defaults (self);
9870 return clutter_anchor_coord_get_gravity (&info->scale_center);
9874 clutter_actor_set_opacity_internal (ClutterActor *self,
9877 ClutterActorPrivate *priv = self->priv;
9879 if (priv->opacity != opacity)
9881 priv->opacity = opacity;
9883 /* Queue a redraw from the flatten effect so that it can use
9884 its cached image if available instead of having to redraw the
9885 actual actor. If it doesn't end up using the FBO then the
9886 effect is still able to continue the paint anyway. If there
9887 is no flatten effect yet then this is equivalent to queueing
9889 _clutter_actor_queue_redraw_full (self,
9892 priv->flatten_effect);
9894 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9899 * clutter_actor_set_opacity:
9900 * @self: A #ClutterActor
9901 * @opacity: New opacity value for the actor.
9903 * Sets the actor's opacity, with zero being completely transparent and
9904 * 255 (0xff) being fully opaque.
9906 * The #ClutterActor:opacity property is animatable.
9909 clutter_actor_set_opacity (ClutterActor *self,
9912 ClutterActorPrivate *priv;
9914 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9918 if (clutter_actor_get_easing_duration (self) != 0)
9920 ClutterTransition *transition;
9922 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9923 if (transition == NULL)
9925 transition = _clutter_actor_create_transition (self,
9926 obj_props[PROP_OPACITY],
9929 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9932 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9934 clutter_actor_queue_redraw (self);
9937 clutter_actor_set_opacity_internal (self, opacity);
9941 * clutter_actor_get_paint_opacity_internal:
9942 * @self: a #ClutterActor
9944 * Retrieves the absolute opacity of the actor, as it appears on the stage
9946 * This function does not do type checks
9948 * Return value: the absolute opacity of the actor
9951 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9953 ClutterActorPrivate *priv = self->priv;
9954 ClutterActor *parent;
9956 /* override the top-level opacity to always be 255; even in
9957 * case of ClutterStage:use-alpha being TRUE we want the rest
9958 * of the scene to be painted
9960 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9963 if (priv->opacity_override >= 0)
9964 return priv->opacity_override;
9966 parent = priv->parent;
9968 /* Factor in the actual actors opacity with parents */
9971 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9973 if (opacity != 0xff)
9974 return (opacity * priv->opacity) / 0xff;
9977 return priv->opacity;
9982 * clutter_actor_get_paint_opacity:
9983 * @self: A #ClutterActor
9985 * Retrieves the absolute opacity of the actor, as it appears on the stage.
9987 * This function traverses the hierarchy chain and composites the opacity of
9988 * the actor with that of its parents.
9990 * This function is intended for subclasses to use in the paint virtual
9991 * function, to paint themselves with the correct opacity.
9993 * Return value: The actor opacity value.
9998 clutter_actor_get_paint_opacity (ClutterActor *self)
10000 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10002 return clutter_actor_get_paint_opacity_internal (self);
10006 * clutter_actor_get_opacity:
10007 * @self: a #ClutterActor
10009 * Retrieves the opacity value of an actor, as set by
10010 * clutter_actor_set_opacity().
10012 * For retrieving the absolute opacity of the actor inside a paint
10013 * virtual function, see clutter_actor_get_paint_opacity().
10015 * Return value: the opacity of the actor
10018 clutter_actor_get_opacity (ClutterActor *self)
10020 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10022 return self->priv->opacity;
10026 * clutter_actor_set_offscreen_redirect:
10027 * @self: A #ClutterActor
10028 * @redirect: New offscreen redirect flags for the actor.
10030 * Defines the circumstances where the actor should be redirected into
10031 * an offscreen image. The offscreen image is used to flatten the
10032 * actor into a single image while painting for two main reasons.
10033 * Firstly, when the actor is painted a second time without any of its
10034 * contents changing it can simply repaint the cached image without
10035 * descending further down the actor hierarchy. Secondly, it will make
10036 * the opacity look correct even if there are overlapping primitives
10039 * Caching the actor could in some cases be a performance win and in
10040 * some cases be a performance lose so it is important to determine
10041 * which value is right for an actor before modifying this value. For
10042 * example, there is never any reason to flatten an actor that is just
10043 * a single texture (such as a #ClutterTexture) because it is
10044 * effectively already cached in an image so the offscreen would be
10045 * redundant. Also if the actor contains primitives that are far apart
10046 * with a large transparent area in the middle (such as a large
10047 * CluterGroup with a small actor in the top left and a small actor in
10048 * the bottom right) then the cached image will contain the entire
10049 * image of the large area and the paint will waste time blending all
10050 * of the transparent pixels in the middle.
10052 * The default method of implementing opacity on a container simply
10053 * forwards on the opacity to all of the children. If the children are
10054 * overlapping then it will appear as if they are two separate glassy
10055 * objects and there will be a break in the color where they
10056 * overlap. By redirecting to an offscreen buffer it will be as if the
10057 * two opaque objects are combined into one and then made transparent
10058 * which is usually what is expected.
10060 * The image below demonstrates the difference between redirecting and
10061 * not. The image shows two Clutter groups, each containing a red and
10062 * a green rectangle which overlap. The opacity on the group is set to
10063 * 128 (which is 50%). When the offscreen redirect is not used, the
10064 * red rectangle can be seen through the blue rectangle as if the two
10065 * rectangles were separately transparent. When the redirect is used
10066 * the group as a whole is transparent instead so the red rectangle is
10067 * not visible where they overlap.
10069 * <figure id="offscreen-redirect">
10070 * <title>Sample of using an offscreen redirect for transparency</title>
10071 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10074 * The default value for this property is 0, so we effectively will
10075 * never redirect an actor offscreen by default. This means that there
10076 * are times that transparent actors may look glassy as described
10077 * above. The reason this is the default is because there is a
10078 * performance trade off between quality and performance here. In many
10079 * cases the default form of glassy opacity looks good enough, but if
10080 * it's not you will need to set the
10081 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10082 * redirection for opacity.
10084 * Custom actors that don't contain any overlapping primitives are
10085 * recommended to override the has_overlaps() virtual to return %FALSE
10086 * for maximum efficiency.
10091 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10092 ClutterOffscreenRedirect redirect)
10094 ClutterActorPrivate *priv;
10096 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10100 if (priv->offscreen_redirect != redirect)
10102 priv->offscreen_redirect = redirect;
10104 /* Queue a redraw from the effect so that it can use its cached
10105 image if available instead of having to redraw the actual
10106 actor. If it doesn't end up using the FBO then the effect is
10107 still able to continue the paint anyway. If there is no
10108 effect then this is equivalent to queuing a full redraw */
10109 _clutter_actor_queue_redraw_full (self,
10112 priv->flatten_effect);
10114 g_object_notify_by_pspec (G_OBJECT (self),
10115 obj_props[PROP_OFFSCREEN_REDIRECT]);
10120 * clutter_actor_get_offscreen_redirect:
10121 * @self: a #ClutterActor
10123 * Retrieves whether to redirect the actor to an offscreen buffer, as
10124 * set by clutter_actor_set_offscreen_redirect().
10126 * Return value: the value of the offscreen-redirect property of the actor
10130 ClutterOffscreenRedirect
10131 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10133 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10135 return self->priv->offscreen_redirect;
10139 * clutter_actor_set_name:
10140 * @self: A #ClutterActor
10141 * @name: Textual tag to apply to actor
10143 * Sets the given name to @self. The name can be used to identify
10147 clutter_actor_set_name (ClutterActor *self,
10150 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10152 g_free (self->priv->name);
10153 self->priv->name = g_strdup (name);
10155 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10159 * clutter_actor_get_name:
10160 * @self: A #ClutterActor
10162 * Retrieves the name of @self.
10164 * Return value: the name of the actor, or %NULL. The returned string is
10165 * owned by the actor and should not be modified or freed.
10168 clutter_actor_get_name (ClutterActor *self)
10170 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10172 return self->priv->name;
10176 * clutter_actor_get_gid:
10177 * @self: A #ClutterActor
10179 * Retrieves the unique id for @self.
10181 * Return value: Globally unique value for this object instance.
10185 * Deprecated: 1.8: The id is not used any longer.
10188 clutter_actor_get_gid (ClutterActor *self)
10190 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10192 return self->priv->id;
10196 clutter_actor_set_depth_internal (ClutterActor *self,
10199 ClutterTransformInfo *info;
10201 info = _clutter_actor_get_transform_info (self);
10203 if (info->depth != depth)
10205 /* Sets Z value - XXX 2.0: should we invert? */
10206 info->depth = depth;
10208 self->priv->transform_valid = FALSE;
10210 /* FIXME - remove this crap; sadly, there are still containers
10211 * in Clutter that depend on this utter brain damage
10213 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10215 clutter_actor_queue_redraw (self);
10217 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10222 * clutter_actor_set_depth:
10223 * @self: a #ClutterActor
10226 * Sets the Z coordinate of @self to @depth.
10228 * The unit used by @depth is dependant on the perspective setup. See
10229 * also clutter_stage_set_perspective().
10232 clutter_actor_set_depth (ClutterActor *self,
10235 const ClutterTransformInfo *tinfo;
10237 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10239 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10241 if (clutter_actor_get_easing_duration (self) != 0)
10243 ClutterTransition *transition;
10245 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10246 if (transition == NULL)
10248 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10251 clutter_timeline_start (CLUTTER_TIMELINE (transition));
10254 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10256 clutter_actor_queue_redraw (self);
10259 clutter_actor_set_depth_internal (self, depth);
10263 * clutter_actor_get_depth:
10264 * @self: a #ClutterActor
10266 * Retrieves the depth of @self.
10268 * Return value: the depth of the actor
10271 clutter_actor_get_depth (ClutterActor *self)
10273 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10275 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10279 * clutter_actor_set_rotation:
10280 * @self: a #ClutterActor
10281 * @axis: the axis of rotation
10282 * @angle: the angle of rotation
10283 * @x: X coordinate of the rotation center
10284 * @y: Y coordinate of the rotation center
10285 * @z: Z coordinate of the rotation center
10287 * Sets the rotation angle of @self around the given axis.
10289 * The rotation center coordinates used depend on the value of @axis:
10291 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10292 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10293 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10296 * The rotation coordinates are relative to the anchor point of the
10297 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10298 * point is set, the upper left corner is assumed as the origin.
10303 clutter_actor_set_rotation (ClutterActor *self,
10304 ClutterRotateAxis axis,
10312 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10318 g_object_freeze_notify (G_OBJECT (self));
10320 clutter_actor_set_rotation_angle (self, axis, angle);
10321 clutter_actor_set_rotation_center_internal (self, axis, &v);
10323 g_object_thaw_notify (G_OBJECT (self));
10327 * clutter_actor_set_z_rotation_from_gravity:
10328 * @self: a #ClutterActor
10329 * @angle: the angle of rotation
10330 * @gravity: the center point of the rotation
10332 * Sets the rotation angle of @self around the Z axis using the center
10333 * point specified as a compass point. For example to rotate such that
10334 * the center of the actor remains static you can use
10335 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10336 * will move accordingly.
10341 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10343 ClutterGravity gravity)
10345 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10347 if (gravity == CLUTTER_GRAVITY_NONE)
10348 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10351 GObject *obj = G_OBJECT (self);
10352 ClutterTransformInfo *info;
10354 info = _clutter_actor_get_transform_info (self);
10356 g_object_freeze_notify (obj);
10358 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10360 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10361 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10362 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10364 g_object_thaw_notify (obj);
10369 * clutter_actor_get_rotation:
10370 * @self: a #ClutterActor
10371 * @axis: the axis of rotation
10372 * @x: (out): return value for the X coordinate of the center of rotation
10373 * @y: (out): return value for the Y coordinate of the center of rotation
10374 * @z: (out): return value for the Z coordinate of the center of rotation
10376 * Retrieves the angle and center of rotation on the given axis,
10377 * set using clutter_actor_set_rotation().
10379 * Return value: the angle of rotation
10384 clutter_actor_get_rotation (ClutterActor *self,
10385 ClutterRotateAxis axis,
10390 const ClutterTransformInfo *info;
10391 const AnchorCoord *anchor_coord;
10392 gdouble retval = 0;
10394 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10396 info = _clutter_actor_get_transform_info_or_defaults (self);
10400 case CLUTTER_X_AXIS:
10401 anchor_coord = &info->rx_center;
10402 retval = info->rx_angle;
10405 case CLUTTER_Y_AXIS:
10406 anchor_coord = &info->ry_center;
10407 retval = info->ry_angle;
10410 case CLUTTER_Z_AXIS:
10411 anchor_coord = &info->rz_center;
10412 retval = info->rz_angle;
10416 anchor_coord = NULL;
10421 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10427 * clutter_actor_get_z_rotation_gravity:
10428 * @self: A #ClutterActor
10430 * Retrieves the center for the rotation around the Z axis as a
10431 * compass direction. If the center was specified in pixels or units
10432 * this will return %CLUTTER_GRAVITY_NONE.
10434 * Return value: the Z rotation center
10439 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10441 const ClutterTransformInfo *info;
10443 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10445 info = _clutter_actor_get_transform_info_or_defaults (self);
10447 return clutter_anchor_coord_get_gravity (&info->rz_center);
10451 * clutter_actor_set_clip:
10452 * @self: A #ClutterActor
10453 * @xoff: X offset of the clip rectangle
10454 * @yoff: Y offset of the clip rectangle
10455 * @width: Width of the clip rectangle
10456 * @height: Height of the clip rectangle
10458 * Sets clip area for @self. The clip area is always computed from the
10459 * upper left corner of the actor, even if the anchor point is set
10465 clutter_actor_set_clip (ClutterActor *self,
10471 ClutterActorPrivate *priv;
10473 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10477 if (priv->has_clip &&
10478 priv->clip.x == xoff &&
10479 priv->clip.y == yoff &&
10480 priv->clip.width == width &&
10481 priv->clip.height == height)
10484 priv->clip.x = xoff;
10485 priv->clip.y = yoff;
10486 priv->clip.width = width;
10487 priv->clip.height = height;
10489 priv->has_clip = TRUE;
10491 clutter_actor_queue_redraw (self);
10493 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10494 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10498 * clutter_actor_remove_clip:
10499 * @self: A #ClutterActor
10501 * Removes clip area from @self.
10504 clutter_actor_remove_clip (ClutterActor *self)
10506 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10508 if (!self->priv->has_clip)
10511 self->priv->has_clip = FALSE;
10513 clutter_actor_queue_redraw (self);
10515 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10519 * clutter_actor_has_clip:
10520 * @self: a #ClutterActor
10522 * Determines whether the actor has a clip area set or not.
10524 * Return value: %TRUE if the actor has a clip area set.
10529 clutter_actor_has_clip (ClutterActor *self)
10531 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10533 return self->priv->has_clip;
10537 * clutter_actor_get_clip:
10538 * @self: a #ClutterActor
10539 * @xoff: (out) (allow-none): return location for the X offset of
10540 * the clip rectangle, or %NULL
10541 * @yoff: (out) (allow-none): return location for the Y offset of
10542 * the clip rectangle, or %NULL
10543 * @width: (out) (allow-none): return location for the width of
10544 * the clip rectangle, or %NULL
10545 * @height: (out) (allow-none): return location for the height of
10546 * the clip rectangle, or %NULL
10548 * Gets the clip area for @self, if any is set
10553 clutter_actor_get_clip (ClutterActor *self,
10559 ClutterActorPrivate *priv;
10561 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10565 if (!priv->has_clip)
10569 *xoff = priv->clip.x;
10572 *yoff = priv->clip.y;
10575 *width = priv->clip.width;
10577 if (height != NULL)
10578 *height = priv->clip.height;
10582 * clutter_actor_get_children:
10583 * @self: a #ClutterActor
10585 * Retrieves the list of children of @self.
10587 * Return value: (transfer container) (element-type ClutterActor): A newly
10588 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10594 clutter_actor_get_children (ClutterActor *self)
10596 ClutterActor *iter;
10599 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10601 /* we walk the list backward so that we can use prepend(),
10604 for (iter = self->priv->last_child, res = NULL;
10606 iter = iter->priv->prev_sibling)
10608 res = g_list_prepend (res, iter);
10615 * insert_child_at_depth:
10616 * @self: a #ClutterActor
10617 * @child: a #ClutterActor
10619 * Inserts @child inside the list of children held by @self, using
10620 * the depth as the insertion criteria.
10622 * This sadly makes the insertion not O(1), but we can keep the
10623 * list sorted so that the painters algorithm we use for painting
10624 * the children will work correctly.
10627 insert_child_at_depth (ClutterActor *self,
10628 ClutterActor *child,
10629 gpointer dummy G_GNUC_UNUSED)
10631 ClutterActor *iter;
10634 child->priv->parent = self;
10637 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10639 /* special-case the first child */
10640 if (self->priv->n_children == 0)
10642 self->priv->first_child = child;
10643 self->priv->last_child = child;
10645 child->priv->next_sibling = NULL;
10646 child->priv->prev_sibling = NULL;
10651 /* Find the right place to insert the child so that it will still be
10652 sorted and the child will be after all of the actors at the same
10654 for (iter = self->priv->first_child;
10656 iter = iter->priv->next_sibling)
10661 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10663 if (iter_depth > child_depth)
10669 ClutterActor *tmp = iter->priv->prev_sibling;
10672 tmp->priv->next_sibling = child;
10674 /* Insert the node before the found one */
10675 child->priv->prev_sibling = iter->priv->prev_sibling;
10676 child->priv->next_sibling = iter;
10677 iter->priv->prev_sibling = child;
10681 ClutterActor *tmp = self->priv->last_child;
10684 tmp->priv->next_sibling = child;
10686 /* insert the node at the end of the list */
10687 child->priv->prev_sibling = self->priv->last_child;
10688 child->priv->next_sibling = NULL;
10691 if (child->priv->prev_sibling == NULL)
10692 self->priv->first_child = child;
10694 if (child->priv->next_sibling == NULL)
10695 self->priv->last_child = child;
10699 insert_child_at_index (ClutterActor *self,
10700 ClutterActor *child,
10703 gint index_ = GPOINTER_TO_INT (data_);
10705 child->priv->parent = self;
10709 ClutterActor *tmp = self->priv->first_child;
10712 tmp->priv->prev_sibling = child;
10714 child->priv->prev_sibling = NULL;
10715 child->priv->next_sibling = tmp;
10717 else if (index_ < 0 || index_ >= self->priv->n_children)
10719 ClutterActor *tmp = self->priv->last_child;
10722 tmp->priv->next_sibling = child;
10724 child->priv->prev_sibling = tmp;
10725 child->priv->next_sibling = NULL;
10729 ClutterActor *iter;
10732 for (iter = self->priv->first_child, i = 0;
10734 iter = iter->priv->next_sibling, i += 1)
10738 ClutterActor *tmp = iter->priv->prev_sibling;
10740 child->priv->prev_sibling = tmp;
10741 child->priv->next_sibling = iter;
10743 iter->priv->prev_sibling = child;
10746 tmp->priv->next_sibling = child;
10753 if (child->priv->prev_sibling == NULL)
10754 self->priv->first_child = child;
10756 if (child->priv->next_sibling == NULL)
10757 self->priv->last_child = child;
10761 insert_child_above (ClutterActor *self,
10762 ClutterActor *child,
10765 ClutterActor *sibling = data;
10767 child->priv->parent = self;
10769 if (sibling == NULL)
10770 sibling = self->priv->last_child;
10772 child->priv->prev_sibling = sibling;
10774 if (sibling != NULL)
10776 ClutterActor *tmp = sibling->priv->next_sibling;
10778 child->priv->next_sibling = tmp;
10781 tmp->priv->prev_sibling = child;
10783 sibling->priv->next_sibling = child;
10786 child->priv->next_sibling = NULL;
10788 if (child->priv->prev_sibling == NULL)
10789 self->priv->first_child = child;
10791 if (child->priv->next_sibling == NULL)
10792 self->priv->last_child = child;
10796 insert_child_below (ClutterActor *self,
10797 ClutterActor *child,
10800 ClutterActor *sibling = data;
10802 child->priv->parent = self;
10804 if (sibling == NULL)
10805 sibling = self->priv->first_child;
10807 child->priv->next_sibling = sibling;
10809 if (sibling != NULL)
10811 ClutterActor *tmp = sibling->priv->prev_sibling;
10813 child->priv->prev_sibling = tmp;
10816 tmp->priv->next_sibling = child;
10818 sibling->priv->prev_sibling = child;
10821 child->priv->prev_sibling = NULL;
10823 if (child->priv->prev_sibling == NULL)
10824 self->priv->first_child = child;
10826 if (child->priv->next_sibling == NULL)
10827 self->priv->last_child = child;
10830 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10831 ClutterActor *child,
10835 ADD_CHILD_CREATE_META = 1 << 0,
10836 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10837 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10838 ADD_CHILD_CHECK_STATE = 1 << 3,
10839 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10841 /* default flags for public API */
10842 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10843 ADD_CHILD_EMIT_PARENT_SET |
10844 ADD_CHILD_EMIT_ACTOR_ADDED |
10845 ADD_CHILD_CHECK_STATE |
10846 ADD_CHILD_NOTIFY_FIRST_LAST,
10848 /* flags for legacy/deprecated API */
10849 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10850 ADD_CHILD_CHECK_STATE |
10851 ADD_CHILD_NOTIFY_FIRST_LAST
10852 } ClutterActorAddChildFlags;
10855 * clutter_actor_add_child_internal:
10856 * @self: a #ClutterActor
10857 * @child: a #ClutterActor
10858 * @flags: control flags for actions
10859 * @add_func: delegate function
10860 * @data: (closure): data to pass to @add_func
10862 * Adds @child to the list of children of @self.
10864 * The actual insertion inside the list is delegated to @add_func: this
10865 * function will just set up the state, perform basic checks, and emit
10868 * The @flags argument is used to perform additional operations.
10871 clutter_actor_add_child_internal (ClutterActor *self,
10872 ClutterActor *child,
10873 ClutterActorAddChildFlags flags,
10874 ClutterActorAddChildFunc add_func,
10877 ClutterTextDirection text_dir;
10878 gboolean create_meta;
10879 gboolean emit_parent_set, emit_actor_added;
10880 gboolean check_state;
10881 gboolean notify_first_last;
10882 ClutterActor *old_first_child, *old_last_child;
10884 if (child->priv->parent != NULL)
10886 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10887 "use clutter_actor_remove_child() first.",
10888 _clutter_actor_get_debug_name (child),
10889 _clutter_actor_get_debug_name (child->priv->parent));
10893 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10895 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10896 "a child of another actor.",
10897 _clutter_actor_get_debug_name (child));
10902 /* XXX - this check disallows calling methods that change the stacking
10903 * order within the destruction sequence, by triggering a critical
10904 * warning first, and leaving the actor in an undefined state, which
10905 * then ends up being caught by an assertion.
10907 * the reproducible sequence is:
10909 * - actor gets destroyed;
10910 * - another actor, linked to the first, will try to change the
10911 * stacking order of the first actor;
10912 * - changing the stacking order is a composite operation composed
10913 * by the following steps:
10914 * 1. ref() the child;
10915 * 2. remove_child_internal(), which removes the reference;
10916 * 3. add_child_internal(), which adds a reference;
10917 * - the state of the actor is not changed between (2) and (3), as
10918 * it could be an expensive recomputation;
10919 * - if (3) bails out, then the actor is in an undefined state, but
10921 * - the destruction sequence terminates, but the actor is unparented
10922 * while its state indicates being parented instead.
10923 * - assertion failure.
10925 * the obvious fix would be to decompose each set_child_*_sibling()
10926 * method into proper remove_child()/add_child(), with state validation;
10927 * this may cause excessive work, though, and trigger a cascade of other
10928 * bugs in code that assumes that a change in the stacking order is an
10929 * atomic operation.
10931 * another potential fix is to just remove this check here, and let
10932 * code doing stacking order changes inside the destruction sequence
10933 * of an actor continue doing the work.
10935 * the third fix is to silently bail out early from every
10936 * set_child_*_sibling() and set_child_at_index() method, and avoid
10939 * I have a preference for the second solution, since it involves the
10940 * least amount of work, and the least amount of code duplication.
10942 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10944 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10946 g_warning ("The actor '%s' is currently being destroyed, and "
10947 "cannot be added as a child of another actor.",
10948 _clutter_actor_get_debug_name (child));
10953 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10954 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10955 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10956 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10957 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10959 old_first_child = self->priv->first_child;
10960 old_last_child = self->priv->last_child;
10962 g_object_freeze_notify (G_OBJECT (self));
10965 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10967 g_object_ref_sink (child);
10968 child->priv->parent = NULL;
10969 child->priv->next_sibling = NULL;
10970 child->priv->prev_sibling = NULL;
10972 /* delegate the actual insertion */
10973 add_func (self, child, data);
10975 g_assert (child->priv->parent == self);
10977 self->priv->n_children += 1;
10979 self->priv->age += 1;
10981 /* if push_internal() has been called then we automatically set
10982 * the flag on the actor
10984 if (self->priv->internal_child)
10985 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
10987 /* clutter_actor_reparent() will emit ::parent-set for us */
10988 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
10989 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
10993 /* If parent is mapped or realized, we need to also be mapped or
10994 * realized once we're inside the parent.
10996 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
10998 /* propagate the parent's text direction to the child */
10999 text_dir = clutter_actor_get_text_direction (self);
11000 clutter_actor_set_text_direction (child, text_dir);
11003 if (child->priv->show_on_set_parent)
11004 clutter_actor_show (child);
11006 if (CLUTTER_ACTOR_IS_MAPPED (child))
11007 clutter_actor_queue_redraw (child);
11009 /* maintain the invariant that if an actor needs layout,
11010 * its parents do as well
11012 if (child->priv->needs_width_request ||
11013 child->priv->needs_height_request ||
11014 child->priv->needs_allocation)
11016 /* we work around the short-circuiting we do
11017 * in clutter_actor_queue_relayout() since we
11018 * want to force a relayout
11020 child->priv->needs_width_request = TRUE;
11021 child->priv->needs_height_request = TRUE;
11022 child->priv->needs_allocation = TRUE;
11024 clutter_actor_queue_relayout (child->priv->parent);
11027 if (emit_actor_added)
11028 g_signal_emit_by_name (self, "actor-added", child);
11030 if (notify_first_last)
11032 if (old_first_child != self->priv->first_child)
11033 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11035 if (old_last_child != self->priv->last_child)
11036 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11039 g_object_thaw_notify (G_OBJECT (self));
11043 * clutter_actor_add_child:
11044 * @self: a #ClutterActor
11045 * @child: a #ClutterActor
11047 * Adds @child to the children of @self.
11049 * This function will acquire a reference on @child that will only
11050 * be released when calling clutter_actor_remove_child().
11052 * This function will take into consideration the #ClutterActor:depth
11053 * of @child, and will keep the list of children sorted.
11055 * This function will emit the #ClutterContainer::actor-added signal
11061 clutter_actor_add_child (ClutterActor *self,
11062 ClutterActor *child)
11064 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11065 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11066 g_return_if_fail (self != child);
11067 g_return_if_fail (child->priv->parent == NULL);
11069 clutter_actor_add_child_internal (self, child,
11070 ADD_CHILD_DEFAULT_FLAGS,
11071 insert_child_at_depth,
11076 * clutter_actor_insert_child_at_index:
11077 * @self: a #ClutterActor
11078 * @child: a #ClutterActor
11079 * @index_: the index
11081 * Inserts @child into the list of children of @self, using the
11082 * given @index_. If @index_ is greater than the number of children
11083 * in @self, or is less than 0, then the new child is added at the end.
11085 * This function will acquire a reference on @child that will only
11086 * be released when calling clutter_actor_remove_child().
11088 * This function will not take into consideration the #ClutterActor:depth
11091 * This function will emit the #ClutterContainer::actor-added signal
11097 clutter_actor_insert_child_at_index (ClutterActor *self,
11098 ClutterActor *child,
11101 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11102 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11103 g_return_if_fail (self != child);
11104 g_return_if_fail (child->priv->parent == NULL);
11106 clutter_actor_add_child_internal (self, child,
11107 ADD_CHILD_DEFAULT_FLAGS,
11108 insert_child_at_index,
11109 GINT_TO_POINTER (index_));
11113 * clutter_actor_insert_child_above:
11114 * @self: a #ClutterActor
11115 * @child: a #ClutterActor
11116 * @sibling: (allow-none): a child of @self, or %NULL
11118 * Inserts @child into the list of children of @self, above another
11119 * child of @self or, if @sibling is %NULL, above all the children
11122 * This function will acquire a reference on @child that will only
11123 * be released when calling clutter_actor_remove_child().
11125 * This function will not take into consideration the #ClutterActor:depth
11128 * This function will emit the #ClutterContainer::actor-added signal
11134 clutter_actor_insert_child_above (ClutterActor *self,
11135 ClutterActor *child,
11136 ClutterActor *sibling)
11138 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11139 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11140 g_return_if_fail (self != child);
11141 g_return_if_fail (child != sibling);
11142 g_return_if_fail (child->priv->parent == NULL);
11143 g_return_if_fail (sibling == NULL ||
11144 (CLUTTER_IS_ACTOR (sibling) &&
11145 sibling->priv->parent == self));
11147 clutter_actor_add_child_internal (self, child,
11148 ADD_CHILD_DEFAULT_FLAGS,
11149 insert_child_above,
11154 * clutter_actor_insert_child_below:
11155 * @self: a #ClutterActor
11156 * @child: a #ClutterActor
11157 * @sibling: (allow-none): a child of @self, or %NULL
11159 * Inserts @child into the list of children of @self, below another
11160 * child of @self or, if @sibling is %NULL, below all the children
11163 * This function will acquire a reference on @child that will only
11164 * be released when calling clutter_actor_remove_child().
11166 * This function will not take into consideration the #ClutterActor:depth
11169 * This function will emit the #ClutterContainer::actor-added signal
11175 clutter_actor_insert_child_below (ClutterActor *self,
11176 ClutterActor *child,
11177 ClutterActor *sibling)
11179 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11180 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11181 g_return_if_fail (self != child);
11182 g_return_if_fail (child != sibling);
11183 g_return_if_fail (child->priv->parent == NULL);
11184 g_return_if_fail (sibling == NULL ||
11185 (CLUTTER_IS_ACTOR (sibling) &&
11186 sibling->priv->parent == self));
11188 clutter_actor_add_child_internal (self, child,
11189 ADD_CHILD_DEFAULT_FLAGS,
11190 insert_child_below,
11195 * clutter_actor_set_parent:
11196 * @self: A #ClutterActor
11197 * @parent: A new #ClutterActor parent
11199 * Sets the parent of @self to @parent.
11201 * This function will result in @parent acquiring a reference on @self,
11202 * eventually by sinking its floating reference first. The reference
11203 * will be released by clutter_actor_unparent().
11205 * This function should only be called by legacy #ClutterActor<!-- -->s
11206 * implementing the #ClutterContainer interface.
11208 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11211 clutter_actor_set_parent (ClutterActor *self,
11212 ClutterActor *parent)
11214 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11215 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11216 g_return_if_fail (self != parent);
11217 g_return_if_fail (self->priv->parent == NULL);
11219 /* as this function will be called inside ClutterContainer::add
11220 * implementations or when building up a composite actor, we have
11221 * to preserve the old behaviour, and not create child meta or
11222 * emit the ::actor-added signal, to avoid recursion or double
11225 clutter_actor_add_child_internal (parent, self,
11226 ADD_CHILD_LEGACY_FLAGS,
11227 insert_child_at_depth,
11232 * clutter_actor_get_parent:
11233 * @self: A #ClutterActor
11235 * Retrieves the parent of @self.
11237 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11238 * if no parent is set
11241 clutter_actor_get_parent (ClutterActor *self)
11243 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11245 return self->priv->parent;
11249 * clutter_actor_get_paint_visibility:
11250 * @self: A #ClutterActor
11252 * Retrieves the 'paint' visibility of an actor recursively checking for non
11255 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11257 * Return Value: %TRUE if the actor is visibile and will be painted.
11262 clutter_actor_get_paint_visibility (ClutterActor *actor)
11264 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11266 return CLUTTER_ACTOR_IS_MAPPED (actor);
11270 * clutter_actor_remove_child:
11271 * @self: a #ClutterActor
11272 * @child: a #ClutterActor
11274 * Removes @child from the children of @self.
11276 * This function will release the reference added by
11277 * clutter_actor_add_child(), so if you want to keep using @child
11278 * you will have to acquire a referenced on it before calling this
11281 * This function will emit the #ClutterContainer::actor-removed
11287 clutter_actor_remove_child (ClutterActor *self,
11288 ClutterActor *child)
11290 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11291 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11292 g_return_if_fail (self != child);
11293 g_return_if_fail (child->priv->parent != NULL);
11294 g_return_if_fail (child->priv->parent == self);
11296 clutter_actor_remove_child_internal (self, child,
11297 REMOVE_CHILD_DEFAULT_FLAGS);
11301 * clutter_actor_remove_all_children:
11302 * @self: a #ClutterActor
11304 * Removes all children of @self.
11306 * This function releases the reference added by inserting a child actor
11307 * in the list of children of @self.
11309 * If the reference count of a child drops to zero, the child will be
11310 * destroyed. If you want to ensure the destruction of all the children
11311 * of @self, use clutter_actor_destroy_all_children().
11316 clutter_actor_remove_all_children (ClutterActor *self)
11318 ClutterActorIter iter;
11320 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11322 if (self->priv->n_children == 0)
11325 g_object_freeze_notify (G_OBJECT (self));
11327 clutter_actor_iter_init (&iter, self);
11328 while (clutter_actor_iter_next (&iter, NULL))
11329 clutter_actor_iter_remove (&iter);
11331 g_object_thaw_notify (G_OBJECT (self));
11334 g_assert (self->priv->first_child == NULL);
11335 g_assert (self->priv->last_child == NULL);
11336 g_assert (self->priv->n_children == 0);
11340 * clutter_actor_destroy_all_children:
11341 * @self: a #ClutterActor
11343 * Destroys all children of @self.
11345 * This function releases the reference added by inserting a child
11346 * actor in the list of children of @self, and ensures that the
11347 * #ClutterActor::destroy signal is emitted on each child of the
11350 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11351 * when its reference count drops to 0; the default handler of the
11352 * #ClutterActor::destroy signal will destroy all the children of an
11353 * actor. This function ensures that all children are destroyed, instead
11354 * of just removed from @self, unlike clutter_actor_remove_all_children()
11355 * which will merely release the reference and remove each child.
11357 * Unless you acquired an additional reference on each child of @self
11358 * prior to calling clutter_actor_remove_all_children() and want to reuse
11359 * the actors, you should use clutter_actor_destroy_all_children() in
11360 * order to make sure that children are destroyed and signal handlers
11361 * are disconnected even in cases where circular references prevent this
11362 * from automatically happening through reference counting alone.
11367 clutter_actor_destroy_all_children (ClutterActor *self)
11369 ClutterActorIter iter;
11371 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11373 if (self->priv->n_children == 0)
11376 g_object_freeze_notify (G_OBJECT (self));
11378 clutter_actor_iter_init (&iter, self);
11379 while (clutter_actor_iter_next (&iter, NULL))
11380 clutter_actor_iter_destroy (&iter);
11382 g_object_thaw_notify (G_OBJECT (self));
11385 g_assert (self->priv->first_child == NULL);
11386 g_assert (self->priv->last_child == NULL);
11387 g_assert (self->priv->n_children == 0);
11390 typedef struct _InsertBetweenData {
11391 ClutterActor *prev_sibling;
11392 ClutterActor *next_sibling;
11393 } InsertBetweenData;
11396 insert_child_between (ClutterActor *self,
11397 ClutterActor *child,
11400 InsertBetweenData *data = data_;
11401 ClutterActor *prev_sibling = data->prev_sibling;
11402 ClutterActor *next_sibling = data->next_sibling;
11404 child->priv->parent = self;
11405 child->priv->prev_sibling = prev_sibling;
11406 child->priv->next_sibling = next_sibling;
11408 if (prev_sibling != NULL)
11409 prev_sibling->priv->next_sibling = child;
11411 if (next_sibling != NULL)
11412 next_sibling->priv->prev_sibling = child;
11414 if (child->priv->prev_sibling == NULL)
11415 self->priv->first_child = child;
11417 if (child->priv->next_sibling == NULL)
11418 self->priv->last_child = child;
11422 * clutter_actor_replace_child:
11423 * @self: a #ClutterActor
11424 * @old_child: the child of @self to replace
11425 * @new_child: the #ClutterActor to replace @old_child
11427 * Replaces @old_child with @new_child in the list of children of @self.
11432 clutter_actor_replace_child (ClutterActor *self,
11433 ClutterActor *old_child,
11434 ClutterActor *new_child)
11436 ClutterActor *prev_sibling, *next_sibling;
11437 InsertBetweenData clos;
11439 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11440 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11441 g_return_if_fail (old_child->priv->parent == self);
11442 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11443 g_return_if_fail (old_child != new_child);
11444 g_return_if_fail (new_child != self);
11445 g_return_if_fail (new_child->priv->parent == NULL);
11447 prev_sibling = old_child->priv->prev_sibling;
11448 next_sibling = old_child->priv->next_sibling;
11449 clutter_actor_remove_child_internal (self, old_child,
11450 REMOVE_CHILD_DEFAULT_FLAGS);
11452 clos.prev_sibling = prev_sibling;
11453 clos.next_sibling = next_sibling;
11454 clutter_actor_add_child_internal (self, new_child,
11455 ADD_CHILD_DEFAULT_FLAGS,
11456 insert_child_between,
11461 * clutter_actor_unparent:
11462 * @self: a #ClutterActor
11464 * Removes the parent of @self.
11466 * This will cause the parent of @self to release the reference
11467 * acquired when calling clutter_actor_set_parent(), so if you
11468 * want to keep @self you will have to acquire a reference of
11469 * your own, through g_object_ref().
11471 * This function should only be called by legacy #ClutterActor<!-- -->s
11472 * implementing the #ClutterContainer interface.
11476 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11479 clutter_actor_unparent (ClutterActor *self)
11481 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11483 if (self->priv->parent == NULL)
11486 clutter_actor_remove_child_internal (self->priv->parent, self,
11487 REMOVE_CHILD_LEGACY_FLAGS);
11491 * clutter_actor_reparent:
11492 * @self: a #ClutterActor
11493 * @new_parent: the new #ClutterActor parent
11495 * Resets the parent actor of @self.
11497 * This function is logically equivalent to calling clutter_actor_unparent()
11498 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11499 * ensures the child is not finalized when unparented, and emits the
11500 * #ClutterActor::parent-set signal only once.
11502 * In reality, calling this function is less useful than it sounds, as some
11503 * application code may rely on changes in the intermediate state between
11504 * removal and addition of the actor from its old parent to the @new_parent.
11505 * Thus, it is strongly encouraged to avoid using this function in application
11510 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11511 * clutter_actor_add_child() instead; remember to take a reference on
11512 * the actor being removed before calling clutter_actor_remove_child()
11513 * to avoid the reference count dropping to zero and the actor being
11517 clutter_actor_reparent (ClutterActor *self,
11518 ClutterActor *new_parent)
11520 ClutterActorPrivate *priv;
11522 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11523 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11524 g_return_if_fail (self != new_parent);
11526 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11528 g_warning ("Cannot set a parent on a toplevel actor");
11532 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11534 g_warning ("Cannot set a parent currently being destroyed");
11540 if (priv->parent != new_parent)
11542 ClutterActor *old_parent;
11544 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11546 old_parent = priv->parent;
11548 g_object_ref (self);
11550 if (old_parent != NULL)
11552 /* go through the Container implementation if this is a regular
11553 * child and not an internal one
11555 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11557 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11559 /* this will have to call unparent() */
11560 clutter_container_remove_actor (parent, self);
11563 clutter_actor_remove_child_internal (old_parent, self,
11564 REMOVE_CHILD_LEGACY_FLAGS);
11567 /* Note, will call set_parent() */
11568 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11569 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11571 clutter_actor_add_child_internal (new_parent, self,
11572 ADD_CHILD_LEGACY_FLAGS,
11573 insert_child_at_depth,
11576 /* we emit the ::parent-set signal once */
11577 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11579 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11581 /* the IN_REPARENT flag suspends state updates */
11582 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11584 g_object_unref (self);
11589 * clutter_actor_contains:
11590 * @self: A #ClutterActor
11591 * @descendant: A #ClutterActor, possibly contained in @self
11593 * Determines if @descendant is contained inside @self (either as an
11594 * immediate child, or as a deeper descendant). If @self and
11595 * @descendant point to the same actor then it will also return %TRUE.
11597 * Return value: whether @descendent is contained within @self
11602 clutter_actor_contains (ClutterActor *self,
11603 ClutterActor *descendant)
11605 ClutterActor *actor;
11607 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11608 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11610 for (actor = descendant; actor; actor = actor->priv->parent)
11618 * clutter_actor_set_child_above_sibling:
11619 * @self: a #ClutterActor
11620 * @child: a #ClutterActor child of @self
11621 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11623 * Sets @child to be above @sibling in the list of children of @self.
11625 * If @sibling is %NULL, @child will be the new last child of @self.
11627 * This function is logically equivalent to removing @child and using
11628 * clutter_actor_insert_child_above(), but it will not emit signals
11629 * or change state on @child.
11634 clutter_actor_set_child_above_sibling (ClutterActor *self,
11635 ClutterActor *child,
11636 ClutterActor *sibling)
11638 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11639 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11640 g_return_if_fail (child->priv->parent == self);
11641 g_return_if_fail (child != sibling);
11642 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11644 if (sibling != NULL)
11645 g_return_if_fail (sibling->priv->parent == self);
11647 /* we don't want to change the state of child, or emit signals, or
11648 * regenerate ChildMeta instances here, but we still want to follow
11649 * the correct sequence of steps encoded in remove_child() and
11650 * add_child(), so that correctness is ensured, and we only go
11651 * through one known code path.
11653 g_object_ref (child);
11654 clutter_actor_remove_child_internal (self, child, 0);
11655 clutter_actor_add_child_internal (self, child,
11656 ADD_CHILD_NOTIFY_FIRST_LAST,
11657 insert_child_above,
11660 clutter_actor_queue_relayout (self);
11664 * clutter_actor_set_child_below_sibling:
11665 * @self: a #ClutterActor
11666 * @child: a #ClutterActor child of @self
11667 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11669 * Sets @child to be below @sibling in the list of children of @self.
11671 * If @sibling is %NULL, @child will be the new first child of @self.
11673 * This function is logically equivalent to removing @self and using
11674 * clutter_actor_insert_child_below(), but it will not emit signals
11675 * or change state on @child.
11680 clutter_actor_set_child_below_sibling (ClutterActor *self,
11681 ClutterActor *child,
11682 ClutterActor *sibling)
11684 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11685 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11686 g_return_if_fail (child->priv->parent == self);
11687 g_return_if_fail (child != sibling);
11688 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11690 if (sibling != NULL)
11691 g_return_if_fail (sibling->priv->parent == self);
11693 /* see the comment in set_child_above_sibling() */
11694 g_object_ref (child);
11695 clutter_actor_remove_child_internal (self, child, 0);
11696 clutter_actor_add_child_internal (self, child,
11697 ADD_CHILD_NOTIFY_FIRST_LAST,
11698 insert_child_below,
11701 clutter_actor_queue_relayout (self);
11705 * clutter_actor_set_child_at_index:
11706 * @self: a #ClutterActor
11707 * @child: a #ClutterActor child of @self
11708 * @index_: the new index for @child
11710 * Changes the index of @child in the list of children of @self.
11712 * This function is logically equivalent to removing @child and
11713 * calling clutter_actor_insert_child_at_index(), but it will not
11714 * emit signals or change state on @child.
11719 clutter_actor_set_child_at_index (ClutterActor *self,
11720 ClutterActor *child,
11723 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11724 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11725 g_return_if_fail (child->priv->parent == self);
11726 g_return_if_fail (index_ <= self->priv->n_children);
11728 g_object_ref (child);
11729 clutter_actor_remove_child_internal (self, child, 0);
11730 clutter_actor_add_child_internal (self, child,
11731 ADD_CHILD_NOTIFY_FIRST_LAST,
11732 insert_child_at_index,
11733 GINT_TO_POINTER (index_));
11735 clutter_actor_queue_relayout (self);
11739 * clutter_actor_raise:
11740 * @self: A #ClutterActor
11741 * @below: (allow-none): A #ClutterActor to raise above.
11743 * Puts @self above @below.
11745 * Both actors must have the same parent, and the parent must implement
11746 * the #ClutterContainer interface
11748 * This function calls clutter_container_raise_child() internally.
11750 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11753 clutter_actor_raise (ClutterActor *self,
11754 ClutterActor *below)
11756 ClutterActor *parent;
11758 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11760 parent = clutter_actor_get_parent (self);
11761 if (parent == NULL)
11763 g_warning ("%s: Actor '%s' is not inside a container",
11765 _clutter_actor_get_debug_name (self));
11771 if (parent != clutter_actor_get_parent (below))
11773 g_warning ("%s Actor '%s' is not in the same container as "
11776 _clutter_actor_get_debug_name (self),
11777 _clutter_actor_get_debug_name (below));
11782 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11786 * clutter_actor_lower:
11787 * @self: A #ClutterActor
11788 * @above: (allow-none): A #ClutterActor to lower below
11790 * Puts @self below @above.
11792 * Both actors must have the same parent, and the parent must implement
11793 * the #ClutterContainer interface.
11795 * This function calls clutter_container_lower_child() internally.
11797 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11800 clutter_actor_lower (ClutterActor *self,
11801 ClutterActor *above)
11803 ClutterActor *parent;
11805 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11807 parent = clutter_actor_get_parent (self);
11808 if (parent == NULL)
11810 g_warning ("%s: Actor of type %s is not inside a container",
11812 _clutter_actor_get_debug_name (self));
11818 if (parent != clutter_actor_get_parent (above))
11820 g_warning ("%s: Actor '%s' is not in the same container as "
11823 _clutter_actor_get_debug_name (self),
11824 _clutter_actor_get_debug_name (above));
11829 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11833 * clutter_actor_raise_top:
11834 * @self: A #ClutterActor
11836 * Raises @self to the top.
11838 * This function calls clutter_actor_raise() internally.
11840 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11841 * a %NULL sibling, instead.
11844 clutter_actor_raise_top (ClutterActor *self)
11846 clutter_actor_raise (self, NULL);
11850 * clutter_actor_lower_bottom:
11851 * @self: A #ClutterActor
11853 * Lowers @self to the bottom.
11855 * This function calls clutter_actor_lower() internally.
11857 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11858 * a %NULL sibling, instead.
11861 clutter_actor_lower_bottom (ClutterActor *self)
11863 clutter_actor_lower (self, NULL);
11871 * clutter_actor_event:
11872 * @actor: a #ClutterActor
11873 * @event: a #ClutterEvent
11874 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11876 * This function is used to emit an event on the main stage.
11877 * You should rarely need to use this function, except for
11878 * synthetising events.
11880 * Return value: the return value from the signal emission: %TRUE
11881 * if the actor handled the event, or %FALSE if the event was
11887 clutter_actor_event (ClutterActor *actor,
11888 ClutterEvent *event,
11891 gboolean retval = FALSE;
11892 gint signal_num = -1;
11894 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11895 g_return_val_if_fail (event != NULL, FALSE);
11897 g_object_ref (actor);
11901 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11907 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11911 switch (event->type)
11913 case CLUTTER_NOTHING:
11915 case CLUTTER_BUTTON_PRESS:
11916 signal_num = BUTTON_PRESS_EVENT;
11918 case CLUTTER_BUTTON_RELEASE:
11919 signal_num = BUTTON_RELEASE_EVENT;
11921 case CLUTTER_SCROLL:
11922 signal_num = SCROLL_EVENT;
11924 case CLUTTER_KEY_PRESS:
11925 signal_num = KEY_PRESS_EVENT;
11927 case CLUTTER_KEY_RELEASE:
11928 signal_num = KEY_RELEASE_EVENT;
11930 case CLUTTER_MOTION:
11931 signal_num = MOTION_EVENT;
11933 case CLUTTER_ENTER:
11934 signal_num = ENTER_EVENT;
11936 case CLUTTER_LEAVE:
11937 signal_num = LEAVE_EVENT;
11939 case CLUTTER_DELETE:
11940 case CLUTTER_DESTROY_NOTIFY:
11941 case CLUTTER_CLIENT_MESSAGE:
11947 if (signal_num != -1)
11948 g_signal_emit (actor, actor_signals[signal_num], 0,
11953 g_object_unref (actor);
11959 * clutter_actor_set_reactive:
11960 * @actor: a #ClutterActor
11961 * @reactive: whether the actor should be reactive to events
11963 * Sets @actor as reactive. Reactive actors will receive events.
11968 clutter_actor_set_reactive (ClutterActor *actor,
11971 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11973 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11977 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11979 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11981 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
11985 * clutter_actor_get_reactive:
11986 * @actor: a #ClutterActor
11988 * Checks whether @actor is marked as reactive.
11990 * Return value: %TRUE if the actor is reactive
11995 clutter_actor_get_reactive (ClutterActor *actor)
11997 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11999 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12003 * clutter_actor_get_anchor_point:
12004 * @self: a #ClutterActor
12005 * @anchor_x: (out): return location for the X coordinate of the anchor point
12006 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12008 * Gets the current anchor point of the @actor in pixels.
12013 clutter_actor_get_anchor_point (ClutterActor *self,
12017 const ClutterTransformInfo *info;
12019 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12021 info = _clutter_actor_get_transform_info_or_defaults (self);
12022 clutter_anchor_coord_get_units (self, &info->anchor,
12029 * clutter_actor_set_anchor_point:
12030 * @self: a #ClutterActor
12031 * @anchor_x: X coordinate of the anchor point
12032 * @anchor_y: Y coordinate of the anchor point
12034 * Sets an anchor point for @self. The anchor point is a point in the
12035 * coordinate space of an actor to which the actor position within its
12036 * parent is relative; the default is (0, 0), i.e. the top-left corner
12042 clutter_actor_set_anchor_point (ClutterActor *self,
12046 ClutterTransformInfo *info;
12047 ClutterActorPrivate *priv;
12048 gboolean changed = FALSE;
12049 gfloat old_anchor_x, old_anchor_y;
12052 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12054 obj = G_OBJECT (self);
12056 info = _clutter_actor_get_transform_info (self);
12058 g_object_freeze_notify (obj);
12060 clutter_anchor_coord_get_units (self, &info->anchor,
12065 if (info->anchor.is_fractional)
12066 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12068 if (old_anchor_x != anchor_x)
12070 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12074 if (old_anchor_y != anchor_y)
12076 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12080 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12084 priv->transform_valid = FALSE;
12085 clutter_actor_queue_redraw (self);
12088 g_object_thaw_notify (obj);
12092 * clutter_actor_get_anchor_point_gravity:
12093 * @self: a #ClutterActor
12095 * Retrieves the anchor position expressed as a #ClutterGravity. If
12096 * the anchor point was specified using pixels or units this will
12097 * return %CLUTTER_GRAVITY_NONE.
12099 * Return value: the #ClutterGravity used by the anchor point
12104 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12106 const ClutterTransformInfo *info;
12108 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12110 info = _clutter_actor_get_transform_info_or_defaults (self);
12112 return clutter_anchor_coord_get_gravity (&info->anchor);
12116 * clutter_actor_move_anchor_point:
12117 * @self: a #ClutterActor
12118 * @anchor_x: X coordinate of the anchor point
12119 * @anchor_y: Y coordinate of the anchor point
12121 * Sets an anchor point for the actor, and adjusts the actor postion so that
12122 * the relative position of the actor toward its parent remains the same.
12127 clutter_actor_move_anchor_point (ClutterActor *self,
12131 gfloat old_anchor_x, old_anchor_y;
12132 const ClutterTransformInfo *info;
12134 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12136 info = _clutter_actor_get_transform_info (self);
12137 clutter_anchor_coord_get_units (self, &info->anchor,
12142 g_object_freeze_notify (G_OBJECT (self));
12144 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12146 if (self->priv->position_set)
12147 clutter_actor_move_by (self,
12148 anchor_x - old_anchor_x,
12149 anchor_y - old_anchor_y);
12151 g_object_thaw_notify (G_OBJECT (self));
12155 * clutter_actor_move_anchor_point_from_gravity:
12156 * @self: a #ClutterActor
12157 * @gravity: #ClutterGravity.
12159 * Sets an anchor point on the actor based on the given gravity, adjusting the
12160 * actor postion so that its relative position within its parent remains
12163 * Since version 1.0 the anchor point will be stored as a gravity so
12164 * that if the actor changes size then the anchor point will move. For
12165 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12166 * and later double the size of the actor, the anchor point will move
12167 * to the bottom right.
12172 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12173 ClutterGravity gravity)
12175 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12176 const ClutterTransformInfo *info;
12177 ClutterActorPrivate *priv;
12179 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12182 info = _clutter_actor_get_transform_info (self);
12184 g_object_freeze_notify (G_OBJECT (self));
12186 clutter_anchor_coord_get_units (self, &info->anchor,
12190 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12191 clutter_anchor_coord_get_units (self, &info->anchor,
12196 if (priv->position_set)
12197 clutter_actor_move_by (self,
12198 new_anchor_x - old_anchor_x,
12199 new_anchor_y - old_anchor_y);
12201 g_object_thaw_notify (G_OBJECT (self));
12205 * clutter_actor_set_anchor_point_from_gravity:
12206 * @self: a #ClutterActor
12207 * @gravity: #ClutterGravity.
12209 * Sets an anchor point on the actor, based on the given gravity (this is a
12210 * convenience function wrapping clutter_actor_set_anchor_point()).
12212 * Since version 1.0 the anchor point will be stored as a gravity so
12213 * that if the actor changes size then the anchor point will move. For
12214 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12215 * and later double the size of the actor, the anchor point will move
12216 * to the bottom right.
12221 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12222 ClutterGravity gravity)
12224 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12226 if (gravity == CLUTTER_GRAVITY_NONE)
12227 clutter_actor_set_anchor_point (self, 0, 0);
12230 GObject *obj = G_OBJECT (self);
12231 ClutterTransformInfo *info;
12233 g_object_freeze_notify (obj);
12235 info = _clutter_actor_get_transform_info (self);
12236 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12238 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12239 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12240 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12242 self->priv->transform_valid = FALSE;
12244 clutter_actor_queue_redraw (self);
12246 g_object_thaw_notify (obj);
12251 clutter_container_iface_init (ClutterContainerIface *iface)
12253 /* we don't override anything, as ClutterContainer already has a default
12254 * implementation that we can use, and which calls into our own API.
12269 parse_units (ClutterActor *self,
12270 ParseDimension dimension,
12273 GValue value = { 0, };
12276 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12279 json_node_get_value (node, &value);
12281 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12283 retval = (gfloat) g_value_get_int64 (&value);
12285 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12287 retval = g_value_get_double (&value);
12289 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12291 ClutterUnits units;
12294 res = clutter_units_from_string (&units, g_value_get_string (&value));
12296 retval = clutter_units_to_pixels (&units);
12299 g_warning ("Invalid value '%s': integers, strings or floating point "
12300 "values can be used for the x, y, width and height "
12301 "properties. Valid modifiers for strings are 'px', 'mm', "
12303 g_value_get_string (&value));
12309 g_warning ("Invalid value of type '%s': integers, strings of floating "
12310 "point values can be used for the x, y, width, height "
12311 "anchor-x and anchor-y properties.",
12312 g_type_name (G_VALUE_TYPE (&value)));
12315 g_value_unset (&value);
12321 ClutterRotateAxis axis;
12330 static inline gboolean
12331 parse_rotation_array (ClutterActor *actor,
12333 RotationInfo *info)
12337 if (json_array_get_length (array) != 2)
12341 element = json_array_get_element (array, 0);
12342 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12343 info->angle = json_node_get_double (element);
12348 element = json_array_get_element (array, 1);
12349 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12351 JsonArray *center = json_node_get_array (element);
12353 if (json_array_get_length (center) != 2)
12356 switch (info->axis)
12358 case CLUTTER_X_AXIS:
12359 info->center_y = parse_units (actor, PARSE_Y,
12360 json_array_get_element (center, 0));
12361 info->center_z = parse_units (actor, PARSE_Y,
12362 json_array_get_element (center, 1));
12365 case CLUTTER_Y_AXIS:
12366 info->center_x = parse_units (actor, PARSE_X,
12367 json_array_get_element (center, 0));
12368 info->center_z = parse_units (actor, PARSE_X,
12369 json_array_get_element (center, 1));
12372 case CLUTTER_Z_AXIS:
12373 info->center_x = parse_units (actor, PARSE_X,
12374 json_array_get_element (center, 0));
12375 info->center_y = parse_units (actor, PARSE_Y,
12376 json_array_get_element (center, 1));
12385 parse_rotation (ClutterActor *actor,
12387 RotationInfo *info)
12391 gboolean retval = FALSE;
12393 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12395 g_warning ("Invalid node of type '%s' found, expecting an array",
12396 json_node_type_name (node));
12400 array = json_node_get_array (node);
12401 len = json_array_get_length (array);
12403 for (i = 0; i < len; i++)
12405 JsonNode *element = json_array_get_element (array, i);
12406 JsonObject *object;
12409 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12411 g_warning ("Invalid node of type '%s' found, expecting an object",
12412 json_node_type_name (element));
12416 object = json_node_get_object (element);
12418 if (json_object_has_member (object, "x-axis"))
12420 member = json_object_get_member (object, "x-axis");
12422 info->axis = CLUTTER_X_AXIS;
12424 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12426 info->angle = json_node_get_double (member);
12429 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12430 retval = parse_rotation_array (actor,
12431 json_node_get_array (member),
12436 else if (json_object_has_member (object, "y-axis"))
12438 member = json_object_get_member (object, "y-axis");
12440 info->axis = CLUTTER_Y_AXIS;
12442 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12444 info->angle = json_node_get_double (member);
12447 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12448 retval = parse_rotation_array (actor,
12449 json_node_get_array (member),
12454 else if (json_object_has_member (object, "z-axis"))
12456 member = json_object_get_member (object, "z-axis");
12458 info->axis = CLUTTER_Z_AXIS;
12460 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12462 info->angle = json_node_get_double (member);
12465 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12466 retval = parse_rotation_array (actor,
12467 json_node_get_array (member),
12478 parse_actor_metas (ClutterScript *script,
12479 ClutterActor *actor,
12482 GList *elements, *l;
12483 GSList *retval = NULL;
12485 if (!JSON_NODE_HOLDS_ARRAY (node))
12488 elements = json_array_get_elements (json_node_get_array (node));
12490 for (l = elements; l != NULL; l = l->next)
12492 JsonNode *element = l->data;
12493 const gchar *id_ = _clutter_script_get_id_from_node (element);
12496 if (id_ == NULL || *id_ == '\0')
12499 meta = clutter_script_get_object (script, id_);
12503 retval = g_slist_prepend (retval, meta);
12506 g_list_free (elements);
12508 return g_slist_reverse (retval);
12512 parse_behaviours (ClutterScript *script,
12513 ClutterActor *actor,
12516 GList *elements, *l;
12517 GSList *retval = NULL;
12519 if (!JSON_NODE_HOLDS_ARRAY (node))
12522 elements = json_array_get_elements (json_node_get_array (node));
12524 for (l = elements; l != NULL; l = l->next)
12526 JsonNode *element = l->data;
12527 const gchar *id_ = _clutter_script_get_id_from_node (element);
12528 GObject *behaviour;
12530 if (id_ == NULL || *id_ == '\0')
12533 behaviour = clutter_script_get_object (script, id_);
12534 if (behaviour == NULL)
12537 retval = g_slist_prepend (retval, behaviour);
12540 g_list_free (elements);
12542 return g_slist_reverse (retval);
12546 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12547 ClutterScript *script,
12552 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12553 gboolean retval = FALSE;
12555 if ((name[0] == 'x' && name[1] == '\0') ||
12556 (name[0] == 'y' && name[1] == '\0') ||
12557 (strcmp (name, "width") == 0) ||
12558 (strcmp (name, "height") == 0) ||
12559 (strcmp (name, "anchor_x") == 0) ||
12560 (strcmp (name, "anchor_y") == 0))
12562 ParseDimension dimension;
12565 if (name[0] == 'x')
12566 dimension = PARSE_X;
12567 else if (name[0] == 'y')
12568 dimension = PARSE_Y;
12569 else if (name[0] == 'w')
12570 dimension = PARSE_WIDTH;
12571 else if (name[0] == 'h')
12572 dimension = PARSE_HEIGHT;
12573 else if (name[0] == 'a' && name[7] == 'x')
12574 dimension = PARSE_ANCHOR_X;
12575 else if (name[0] == 'a' && name[7] == 'y')
12576 dimension = PARSE_ANCHOR_Y;
12580 units = parse_units (actor, dimension, node);
12582 /* convert back to pixels: all properties are pixel-based */
12583 g_value_init (value, G_TYPE_FLOAT);
12584 g_value_set_float (value, units);
12588 else if (strcmp (name, "rotation") == 0)
12590 RotationInfo *info;
12592 info = g_slice_new0 (RotationInfo);
12593 retval = parse_rotation (actor, node, info);
12597 g_value_init (value, G_TYPE_POINTER);
12598 g_value_set_pointer (value, info);
12601 g_slice_free (RotationInfo, info);
12603 else if (strcmp (name, "behaviours") == 0)
12607 #ifdef CLUTTER_ENABLE_DEBUG
12608 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12609 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12610 "and it should not be used in newly "
12611 "written ClutterScript definitions.");
12614 l = parse_behaviours (script, actor, node);
12616 g_value_init (value, G_TYPE_POINTER);
12617 g_value_set_pointer (value, l);
12621 else if (strcmp (name, "actions") == 0 ||
12622 strcmp (name, "constraints") == 0 ||
12623 strcmp (name, "effects") == 0)
12627 l = parse_actor_metas (script, actor, node);
12629 g_value_init (value, G_TYPE_POINTER);
12630 g_value_set_pointer (value, l);
12639 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12640 ClutterScript *script,
12642 const GValue *value)
12644 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12646 #ifdef CLUTTER_ENABLE_DEBUG
12647 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12649 gchar *tmp = g_strdup_value_contents (value);
12651 CLUTTER_NOTE (SCRIPT,
12652 "in ClutterActor::set_custom_property('%s') = %s",
12658 #endif /* CLUTTER_ENABLE_DEBUG */
12660 if (strcmp (name, "rotation") == 0)
12662 RotationInfo *info;
12664 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12667 info = g_value_get_pointer (value);
12669 clutter_actor_set_rotation (actor,
12670 info->axis, info->angle,
12675 g_slice_free (RotationInfo, info);
12680 if (strcmp (name, "behaviours") == 0)
12682 GSList *behaviours, *l;
12684 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12687 behaviours = g_value_get_pointer (value);
12688 for (l = behaviours; l != NULL; l = l->next)
12690 ClutterBehaviour *behaviour = l->data;
12692 clutter_behaviour_apply (behaviour, actor);
12695 g_slist_free (behaviours);
12700 if (strcmp (name, "actions") == 0 ||
12701 strcmp (name, "constraints") == 0 ||
12702 strcmp (name, "effects") == 0)
12706 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12709 metas = g_value_get_pointer (value);
12710 for (l = metas; l != NULL; l = l->next)
12712 if (name[0] == 'a')
12713 clutter_actor_add_action (actor, l->data);
12715 if (name[0] == 'c')
12716 clutter_actor_add_constraint (actor, l->data);
12718 if (name[0] == 'e')
12719 clutter_actor_add_effect (actor, l->data);
12722 g_slist_free (metas);
12727 g_object_set_property (G_OBJECT (scriptable), name, value);
12731 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12733 iface->parse_custom_node = clutter_actor_parse_custom_node;
12734 iface->set_custom_property = clutter_actor_set_custom_property;
12737 static ClutterActorMeta *
12738 get_meta_from_animation_property (ClutterActor *actor,
12742 ClutterActorPrivate *priv = actor->priv;
12743 ClutterActorMeta *meta = NULL;
12746 /* if this is not a special property, fall through */
12747 if (name[0] != '@')
12750 /* detect the properties named using the following spec:
12752 * @<section>.<meta-name>.<property-name>
12754 * where <section> can be one of the following:
12760 * and <meta-name> is the name set on a specific ActorMeta
12763 tokens = g_strsplit (name + 1, ".", -1);
12764 if (tokens == NULL || g_strv_length (tokens) != 3)
12766 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12768 g_strfreev (tokens);
12772 if (strcmp (tokens[0], "actions") == 0)
12773 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12775 if (strcmp (tokens[0], "constraints") == 0)
12776 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12778 if (strcmp (tokens[0], "effects") == 0)
12779 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12781 if (name_p != NULL)
12782 *name_p = g_strdup (tokens[2]);
12784 CLUTTER_NOTE (ANIMATION,
12785 "Looking for property '%s' of object '%s' in section '%s'",
12790 g_strfreev (tokens);
12795 static GParamSpec *
12796 clutter_actor_find_property (ClutterAnimatable *animatable,
12797 const gchar *property_name)
12799 ClutterActorMeta *meta = NULL;
12800 GObjectClass *klass = NULL;
12801 GParamSpec *pspec = NULL;
12802 gchar *p_name = NULL;
12804 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12810 klass = G_OBJECT_GET_CLASS (meta);
12812 pspec = g_object_class_find_property (klass, p_name);
12816 klass = G_OBJECT_GET_CLASS (animatable);
12818 pspec = g_object_class_find_property (klass, property_name);
12827 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12828 const gchar *property_name,
12831 ClutterActorMeta *meta = NULL;
12832 gchar *p_name = NULL;
12834 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12839 g_object_get_property (G_OBJECT (meta), p_name, initial);
12841 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12847 * clutter_actor_set_animatable_property:
12848 * @actor: a #ClutterActor
12849 * @prop_id: the paramspec id
12850 * @value: the value to set
12851 * @pspec: the paramspec
12853 * Sets values of animatable properties.
12855 * This is a variant of clutter_actor_set_property() that gets called
12856 * by the #ClutterAnimatable implementation of #ClutterActor for the
12857 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12860 * Unlike the implementation of #GObjectClass.set_property(), this
12861 * function will not update the interval if a transition involving an
12862 * animatable property is in progress - this avoids cycles with the
12863 * transition API calling the public API.
12866 clutter_actor_set_animatable_property (ClutterActor *actor,
12868 const GValue *value,
12874 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12878 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12882 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12886 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12890 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12894 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12897 case PROP_BACKGROUND_COLOR:
12898 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12902 clutter_actor_set_scale_factor_internal (actor,
12903 g_value_get_double (value),
12908 clutter_actor_set_scale_factor_internal (actor,
12909 g_value_get_double (value),
12913 case PROP_ROTATION_ANGLE_X:
12914 clutter_actor_set_rotation_angle_internal (actor,
12916 g_value_get_double (value));
12919 case PROP_ROTATION_ANGLE_Y:
12920 clutter_actor_set_rotation_angle_internal (actor,
12922 g_value_get_double (value));
12925 case PROP_ROTATION_ANGLE_Z:
12926 clutter_actor_set_rotation_angle_internal (actor,
12928 g_value_get_double (value));
12932 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12938 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12939 const gchar *property_name,
12940 const GValue *final)
12942 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12943 ClutterActorMeta *meta = NULL;
12944 gchar *p_name = NULL;
12946 meta = get_meta_from_animation_property (actor,
12950 g_object_set_property (G_OBJECT (meta), p_name, final);
12953 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12956 pspec = g_object_class_find_property (obj_class, property_name);
12958 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12960 /* XXX - I'm going to the special hell for this */
12961 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12964 g_object_set_property (G_OBJECT (animatable), property_name, final);
12971 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12973 iface->find_property = clutter_actor_find_property;
12974 iface->get_initial_state = clutter_actor_get_initial_state;
12975 iface->set_final_state = clutter_actor_set_final_state;
12979 * clutter_actor_transform_stage_point:
12980 * @self: A #ClutterActor
12981 * @x: (in): x screen coordinate of the point to unproject
12982 * @y: (in): y screen coordinate of the point to unproject
12983 * @x_out: (out): return location for the unprojected x coordinance
12984 * @y_out: (out): return location for the unprojected y coordinance
12986 * This function translates screen coordinates (@x, @y) to
12987 * coordinates relative to the actor. For example, it can be used to translate
12988 * screen events from global screen coordinates into actor-local coordinates.
12990 * The conversion can fail, notably if the transform stack results in the
12991 * actor being projected on the screen as a mere line.
12993 * The conversion should not be expected to be pixel-perfect due to the
12994 * nature of the operation. In general the error grows when the skewing
12995 * of the actor rectangle on screen increases.
12997 * <note><para>This function can be computationally intensive.</para></note>
12999 * <note><para>This function only works when the allocation is up-to-date,
13000 * i.e. inside of paint().</para></note>
13002 * Return value: %TRUE if conversion was successful.
13007 clutter_actor_transform_stage_point (ClutterActor *self,
13013 ClutterVertex v[4];
13016 int du, dv, xi, yi;
13018 float xf, yf, wf, det;
13019 ClutterActorPrivate *priv;
13021 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13025 /* This implementation is based on the quad -> quad projection algorithm
13026 * described by Paul Heckbert in:
13028 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13030 * and the sample implementation at:
13032 * http://www.cs.cmu.edu/~ph/src/texfund/
13034 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13035 * quad to rectangle only, which significantly simplifies things; the
13036 * function calls have been unrolled, and most of the math is done in fixed
13040 clutter_actor_get_abs_allocation_vertices (self, v);
13042 /* Keeping these as ints simplifies the multiplication (no significant
13043 * loss of precision here).
13045 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13046 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13051 #define UX2FP(x) (x)
13052 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13054 /* First, find mapping from unit uv square to xy quadrilateral; this
13055 * equivalent to the pmap_square_quad() functions in the sample
13056 * implementation, which we can simplify, since our target is always
13059 px = v[0].x - v[1].x + v[3].x - v[2].x;
13060 py = v[0].y - v[1].y + v[3].y - v[2].y;
13064 /* affine transform */
13065 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13066 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13067 RQ[2][0] = UX2FP (v[0].x);
13068 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13069 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13070 RQ[2][1] = UX2FP (v[0].y);
13077 /* projective transform */
13078 double dx1, dx2, dy1, dy2, del;
13080 dx1 = UX2FP (v[1].x - v[3].x);
13081 dx2 = UX2FP (v[2].x - v[3].x);
13082 dy1 = UX2FP (v[1].y - v[3].y);
13083 dy2 = UX2FP (v[2].y - v[3].y);
13085 del = DET2FP (dx1, dx2, dy1, dy2);
13090 * The division here needs to be done in floating point for
13091 * precisions reasons.
13093 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13094 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13095 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13097 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13098 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13099 RQ[2][0] = UX2FP (v[0].x);
13100 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13101 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13102 RQ[2][1] = UX2FP (v[0].y);
13106 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13107 * square. Since our rectangle is based at 0,0 we only need to scale.
13117 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13120 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13121 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13122 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13123 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13124 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13125 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13126 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13127 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13128 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13131 * Check the resulting matrix is OK.
13133 det = (RQ[0][0] * ST[0][0])
13134 + (RQ[0][1] * ST[0][1])
13135 + (RQ[0][2] * ST[0][2]);
13140 * Now transform our point with the ST matrix; the notional w
13141 * coordinate is 1, hence the last part is simply added.
13146 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13147 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13148 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13166 static ClutterGeometry*
13167 clutter_geometry_copy (const ClutterGeometry *geometry)
13169 return g_slice_dup (ClutterGeometry, geometry);
13173 clutter_geometry_free (ClutterGeometry *geometry)
13175 if (G_LIKELY (geometry != NULL))
13176 g_slice_free (ClutterGeometry, geometry);
13180 * clutter_geometry_union:
13181 * @geometry_a: a #ClutterGeometry
13182 * @geometry_b: another #ClutterGeometry
13183 * @result: (out): location to store the result
13185 * Find the union of two rectangles represented as #ClutterGeometry.
13190 clutter_geometry_union (const ClutterGeometry *geometry_a,
13191 const ClutterGeometry *geometry_b,
13192 ClutterGeometry *result)
13194 /* We don't try to handle rectangles that can't be represented
13195 * as a signed integer box */
13196 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13197 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13198 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13199 geometry_b->x + (gint)geometry_b->width);
13200 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13201 geometry_b->y + (gint)geometry_b->height);
13204 result->width = x_2 - x_1;
13205 result->height = y_2 - y_1;
13209 * clutter_geometry_intersects:
13210 * @geometry0: The first geometry to test
13211 * @geometry1: The second geometry to test
13213 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13214 * they do else %FALSE.
13216 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13222 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13223 const ClutterGeometry *geometry1)
13225 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13226 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13227 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13228 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13235 clutter_geometry_progress (const GValue *a,
13240 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13241 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13242 ClutterGeometry res = { 0, };
13243 gint a_width = a_geom->width;
13244 gint b_width = b_geom->width;
13245 gint a_height = a_geom->height;
13246 gint b_height = b_geom->height;
13248 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13249 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13251 res.width = a_width + (b_width - a_width) * progress;
13252 res.height = a_height + (b_height - a_height) * progress;
13254 g_value_set_boxed (retval, &res);
13259 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13260 clutter_geometry_copy,
13261 clutter_geometry_free,
13262 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13269 * clutter_vertex_new:
13274 * Creates a new #ClutterVertex for the point in 3D space
13275 * identified by the 3 coordinates @x, @y, @z
13277 * Return value: the newly allocate #ClutterVertex. Use
13278 * clutter_vertex_free() to free the resources
13283 clutter_vertex_new (gfloat x,
13287 ClutterVertex *vertex;
13289 vertex = g_slice_new (ClutterVertex);
13298 * clutter_vertex_copy:
13299 * @vertex: a #ClutterVertex
13303 * Return value: a newly allocated copy of #ClutterVertex. Use
13304 * clutter_vertex_free() to free the allocated resources
13309 clutter_vertex_copy (const ClutterVertex *vertex)
13311 if (G_LIKELY (vertex != NULL))
13312 return g_slice_dup (ClutterVertex, vertex);
13318 * clutter_vertex_free:
13319 * @vertex: a #ClutterVertex
13321 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13326 clutter_vertex_free (ClutterVertex *vertex)
13328 if (G_UNLIKELY (vertex != NULL))
13329 g_slice_free (ClutterVertex, vertex);
13333 * clutter_vertex_equal:
13334 * @vertex_a: a #ClutterVertex
13335 * @vertex_b: a #ClutterVertex
13337 * Compares @vertex_a and @vertex_b for equality
13339 * Return value: %TRUE if the passed #ClutterVertex are equal
13344 clutter_vertex_equal (const ClutterVertex *vertex_a,
13345 const ClutterVertex *vertex_b)
13347 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13349 if (vertex_a == vertex_b)
13352 return vertex_a->x == vertex_b->x &&
13353 vertex_a->y == vertex_b->y &&
13354 vertex_a->z == vertex_b->z;
13358 clutter_vertex_progress (const GValue *a,
13363 const ClutterVertex *av = g_value_get_boxed (a);
13364 const ClutterVertex *bv = g_value_get_boxed (b);
13365 ClutterVertex res = { 0, };
13367 res.x = av->x + (bv->x - av->x) * progress;
13368 res.y = av->y + (bv->y - av->y) * progress;
13369 res.z = av->z + (bv->z - av->z) * progress;
13371 g_value_set_boxed (retval, &res);
13376 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13377 clutter_vertex_copy,
13378 clutter_vertex_free,
13379 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13382 * clutter_actor_is_rotated:
13383 * @self: a #ClutterActor
13385 * Checks whether any rotation is applied to the actor.
13387 * Return value: %TRUE if the actor is rotated.
13392 clutter_actor_is_rotated (ClutterActor *self)
13394 const ClutterTransformInfo *info;
13396 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13398 info = _clutter_actor_get_transform_info_or_defaults (self);
13400 if (info->rx_angle || info->ry_angle || info->rz_angle)
13407 * clutter_actor_is_scaled:
13408 * @self: a #ClutterActor
13410 * Checks whether the actor is scaled in either dimension.
13412 * Return value: %TRUE if the actor is scaled.
13417 clutter_actor_is_scaled (ClutterActor *self)
13419 const ClutterTransformInfo *info;
13421 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13423 info = _clutter_actor_get_transform_info_or_defaults (self);
13425 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13432 _clutter_actor_get_stage_internal (ClutterActor *actor)
13434 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13435 actor = actor->priv->parent;
13441 * clutter_actor_get_stage:
13442 * @actor: a #ClutterActor
13444 * Retrieves the #ClutterStage where @actor is contained.
13446 * Return value: (transfer none) (type Clutter.Stage): the stage
13447 * containing the actor, or %NULL
13452 clutter_actor_get_stage (ClutterActor *actor)
13454 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13456 return _clutter_actor_get_stage_internal (actor);
13460 * clutter_actor_allocate_available_size:
13461 * @self: a #ClutterActor
13462 * @x: the actor's X coordinate
13463 * @y: the actor's Y coordinate
13464 * @available_width: the maximum available width, or -1 to use the
13465 * actor's natural width
13466 * @available_height: the maximum available height, or -1 to use the
13467 * actor's natural height
13468 * @flags: flags controlling the allocation
13470 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13471 * preferred size, but limiting it to the maximum available width
13472 * and height provided.
13474 * This function will do the right thing when dealing with the
13475 * actor's request mode.
13477 * The implementation of this function is equivalent to:
13480 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13482 * clutter_actor_get_preferred_width (self, available_height,
13484 * &natural_width);
13485 * width = CLAMP (natural_width, min_width, available_width);
13487 * clutter_actor_get_preferred_height (self, width,
13489 * &natural_height);
13490 * height = CLAMP (natural_height, min_height, available_height);
13494 * clutter_actor_get_preferred_height (self, available_width,
13496 * &natural_height);
13497 * height = CLAMP (natural_height, min_height, available_height);
13499 * clutter_actor_get_preferred_width (self, height,
13501 * &natural_width);
13502 * width = CLAMP (natural_width, min_width, available_width);
13505 * box.x1 = x; box.y1 = y;
13506 * box.x2 = box.x1 + available_width;
13507 * box.y2 = box.y1 + available_height;
13508 * clutter_actor_allocate (self, &box, flags);
13511 * This function can be used by fluid layout managers to allocate
13512 * an actor's preferred size without making it bigger than the area
13513 * available for the container.
13518 clutter_actor_allocate_available_size (ClutterActor *self,
13521 gfloat available_width,
13522 gfloat available_height,
13523 ClutterAllocationFlags flags)
13525 ClutterActorPrivate *priv;
13526 gfloat width, height;
13527 gfloat min_width, min_height;
13528 gfloat natural_width, natural_height;
13529 ClutterActorBox box;
13531 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13535 width = height = 0.0;
13537 switch (priv->request_mode)
13539 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13540 clutter_actor_get_preferred_width (self, available_height,
13543 width = CLAMP (natural_width, min_width, available_width);
13545 clutter_actor_get_preferred_height (self, width,
13548 height = CLAMP (natural_height, min_height, available_height);
13551 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13552 clutter_actor_get_preferred_height (self, available_width,
13555 height = CLAMP (natural_height, min_height, available_height);
13557 clutter_actor_get_preferred_width (self, height,
13560 width = CLAMP (natural_width, min_width, available_width);
13567 box.x2 = box.x1 + width;
13568 box.y2 = box.y1 + height;
13569 clutter_actor_allocate (self, &box, flags);
13573 * clutter_actor_allocate_preferred_size:
13574 * @self: a #ClutterActor
13575 * @flags: flags controlling the allocation
13577 * Allocates the natural size of @self.
13579 * This function is a utility call for #ClutterActor implementations
13580 * that allocates the actor's preferred natural size. It can be used
13581 * by fixed layout managers (like #ClutterGroup or so called
13582 * 'composite actors') inside the ClutterActor::allocate
13583 * implementation to give each child exactly how much space it
13586 * This function is not meant to be used by applications. It is also
13587 * not meant to be used outside the implementation of the
13588 * ClutterActor::allocate virtual function.
13593 clutter_actor_allocate_preferred_size (ClutterActor *self,
13594 ClutterAllocationFlags flags)
13596 gfloat actor_x, actor_y;
13597 gfloat natural_width, natural_height;
13598 ClutterActorBox actor_box;
13600 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13602 actor_x = clutter_actor_get_x (self);
13603 actor_y = clutter_actor_get_y (self);
13605 clutter_actor_get_preferred_size (self,
13610 actor_box.x1 = actor_x;
13611 actor_box.y1 = actor_y;
13612 actor_box.x2 = actor_box.x1 + natural_width;
13613 actor_box.y2 = actor_box.y1 + natural_height;
13615 clutter_actor_allocate (self, &actor_box, flags);
13619 * clutter_actor_allocate_align_fill:
13620 * @self: a #ClutterActor
13621 * @box: a #ClutterActorBox, containing the available width and height
13622 * @x_align: the horizontal alignment, between 0 and 1
13623 * @y_align: the vertical alignment, between 0 and 1
13624 * @x_fill: whether the actor should fill horizontally
13625 * @y_fill: whether the actor should fill vertically
13626 * @flags: allocation flags to be passed to clutter_actor_allocate()
13628 * Allocates @self by taking into consideration the available allocation
13629 * area; an alignment factor on either axis; and whether the actor should
13630 * fill the allocation on either axis.
13632 * The @box should contain the available allocation width and height;
13633 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13634 * allocation will be offset by their value.
13636 * This function takes into consideration the geometry request specified by
13637 * the #ClutterActor:request-mode property, and the text direction.
13639 * This function is useful for fluid layout managers, like #ClutterBinLayout
13640 * or #ClutterTableLayout
13645 clutter_actor_allocate_align_fill (ClutterActor *self,
13646 const ClutterActorBox *box,
13651 ClutterAllocationFlags flags)
13653 ClutterActorPrivate *priv;
13654 ClutterActorBox allocation = { 0, };
13655 gfloat x_offset, y_offset;
13656 gfloat available_width, available_height;
13657 gfloat child_width, child_height;
13659 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13660 g_return_if_fail (box != NULL);
13661 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13662 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13666 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13667 clutter_actor_box_get_size (box, &available_width, &available_height);
13669 if (available_width < 0)
13670 available_width = 0;
13672 if (available_height < 0)
13673 available_height = 0;
13677 allocation.x1 = x_offset;
13678 allocation.x2 = allocation.x1 + available_width;
13683 allocation.y1 = y_offset;
13684 allocation.y2 = allocation.y1 + available_height;
13687 /* if we are filling horizontally and vertically then we're done */
13688 if (x_fill && y_fill)
13691 child_width = child_height = 0.0f;
13693 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13695 gfloat min_width, natural_width;
13696 gfloat min_height, natural_height;
13698 clutter_actor_get_preferred_width (self, available_height,
13702 child_width = CLAMP (natural_width, min_width, available_width);
13706 clutter_actor_get_preferred_height (self, child_width,
13710 child_height = CLAMP (natural_height, min_height, available_height);
13715 gfloat min_width, natural_width;
13716 gfloat min_height, natural_height;
13718 clutter_actor_get_preferred_height (self, available_width,
13722 child_height = CLAMP (natural_height, min_height, available_height);
13726 clutter_actor_get_preferred_width (self, child_height,
13730 child_width = CLAMP (natural_width, min_width, available_width);
13734 /* invert the horizontal alignment for RTL languages */
13735 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13736 x_align = 1.0 - x_align;
13740 allocation.x1 = x_offset
13741 + ((available_width - child_width) * x_align);
13742 allocation.x2 = allocation.x1 + child_width;
13747 allocation.y1 = y_offset
13748 + ((available_height - child_height) * y_align);
13749 allocation.y2 = allocation.y1 + child_height;
13753 clutter_actor_box_clamp_to_pixel (&allocation);
13754 clutter_actor_allocate (self, &allocation, flags);
13758 * clutter_actor_grab_key_focus:
13759 * @self: a #ClutterActor
13761 * Sets the key focus of the #ClutterStage including @self
13762 * to this #ClutterActor.
13767 clutter_actor_grab_key_focus (ClutterActor *self)
13769 ClutterActor *stage;
13771 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13773 stage = _clutter_actor_get_stage_internal (self);
13775 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13779 * clutter_actor_get_pango_context:
13780 * @self: a #ClutterActor
13782 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13783 * is already configured using the appropriate font map, resolution
13784 * and font options.
13786 * Unlike clutter_actor_create_pango_context(), this context is owend
13787 * by the #ClutterActor and it will be updated each time the options
13788 * stored by the #ClutterBackend change.
13790 * You can use the returned #PangoContext to create a #PangoLayout
13791 * and render text using cogl_pango_render_layout() to reuse the
13792 * glyphs cache also used by Clutter.
13794 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13795 * The returned #PangoContext is owned by the actor and should not be
13796 * unreferenced by the application code
13801 clutter_actor_get_pango_context (ClutterActor *self)
13803 ClutterActorPrivate *priv;
13805 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13809 if (priv->pango_context != NULL)
13810 return priv->pango_context;
13812 priv->pango_context = _clutter_context_get_pango_context ();
13813 g_object_ref (priv->pango_context);
13815 return priv->pango_context;
13819 * clutter_actor_create_pango_context:
13820 * @self: a #ClutterActor
13822 * Creates a #PangoContext for the given actor. The #PangoContext
13823 * is already configured using the appropriate font map, resolution
13824 * and font options.
13826 * See also clutter_actor_get_pango_context().
13828 * Return value: (transfer full): the newly created #PangoContext.
13829 * Use g_object_unref() on the returned value to deallocate its
13835 clutter_actor_create_pango_context (ClutterActor *self)
13837 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13839 return _clutter_context_create_pango_context ();
13843 * clutter_actor_create_pango_layout:
13844 * @self: a #ClutterActor
13845 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13847 * Creates a new #PangoLayout from the same #PangoContext used
13848 * by the #ClutterActor. The #PangoLayout is already configured
13849 * with the font map, resolution and font options, and the
13852 * If you want to keep around a #PangoLayout created by this
13853 * function you will have to connect to the #ClutterBackend::font-changed
13854 * and #ClutterBackend::resolution-changed signals, and call
13855 * pango_layout_context_changed() in response to them.
13857 * Return value: (transfer full): the newly created #PangoLayout.
13858 * Use g_object_unref() when done
13863 clutter_actor_create_pango_layout (ClutterActor *self,
13866 PangoContext *context;
13867 PangoLayout *layout;
13869 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13871 context = clutter_actor_get_pango_context (self);
13872 layout = pango_layout_new (context);
13875 pango_layout_set_text (layout, text, -1);
13880 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13881 * ClutterOffscreenEffect.
13884 _clutter_actor_set_opacity_override (ClutterActor *self,
13887 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13889 self->priv->opacity_override = opacity;
13893 _clutter_actor_get_opacity_override (ClutterActor *self)
13895 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13897 return self->priv->opacity_override;
13900 /* Allows you to disable applying the actors model view transform during
13901 * a paint. Used by ClutterClone. */
13903 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13906 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13908 self->priv->enable_model_view_transform = enable;
13912 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13915 ClutterActorPrivate *priv;
13917 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13921 priv->enable_paint_unmapped = enable;
13923 if (priv->enable_paint_unmapped)
13925 /* Make sure that the parents of the widget are realized first;
13926 * otherwise checks in clutter_actor_update_map_state() will
13929 clutter_actor_realize (self);
13931 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13935 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13940 clutter_anchor_coord_get_units (ClutterActor *self,
13941 const AnchorCoord *coord,
13946 if (coord->is_fractional)
13948 gfloat actor_width, actor_height;
13950 clutter_actor_get_size (self, &actor_width, &actor_height);
13953 *x = actor_width * coord->v.fraction.x;
13956 *y = actor_height * coord->v.fraction.y;
13964 *x = coord->v.units.x;
13967 *y = coord->v.units.y;
13970 *z = coord->v.units.z;
13975 clutter_anchor_coord_set_units (AnchorCoord *coord,
13980 coord->is_fractional = FALSE;
13981 coord->v.units.x = x;
13982 coord->v.units.y = y;
13983 coord->v.units.z = z;
13986 static ClutterGravity
13987 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
13989 if (coord->is_fractional)
13991 if (coord->v.fraction.x == 0.0)
13993 if (coord->v.fraction.y == 0.0)
13994 return CLUTTER_GRAVITY_NORTH_WEST;
13995 else if (coord->v.fraction.y == 0.5)
13996 return CLUTTER_GRAVITY_WEST;
13997 else if (coord->v.fraction.y == 1.0)
13998 return CLUTTER_GRAVITY_SOUTH_WEST;
14000 return CLUTTER_GRAVITY_NONE;
14002 else if (coord->v.fraction.x == 0.5)
14004 if (coord->v.fraction.y == 0.0)
14005 return CLUTTER_GRAVITY_NORTH;
14006 else if (coord->v.fraction.y == 0.5)
14007 return CLUTTER_GRAVITY_CENTER;
14008 else if (coord->v.fraction.y == 1.0)
14009 return CLUTTER_GRAVITY_SOUTH;
14011 return CLUTTER_GRAVITY_NONE;
14013 else if (coord->v.fraction.x == 1.0)
14015 if (coord->v.fraction.y == 0.0)
14016 return CLUTTER_GRAVITY_NORTH_EAST;
14017 else if (coord->v.fraction.y == 0.5)
14018 return CLUTTER_GRAVITY_EAST;
14019 else if (coord->v.fraction.y == 1.0)
14020 return CLUTTER_GRAVITY_SOUTH_EAST;
14022 return CLUTTER_GRAVITY_NONE;
14025 return CLUTTER_GRAVITY_NONE;
14028 return CLUTTER_GRAVITY_NONE;
14032 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14033 ClutterGravity gravity)
14037 case CLUTTER_GRAVITY_NORTH:
14038 coord->v.fraction.x = 0.5;
14039 coord->v.fraction.y = 0.0;
14042 case CLUTTER_GRAVITY_NORTH_EAST:
14043 coord->v.fraction.x = 1.0;
14044 coord->v.fraction.y = 0.0;
14047 case CLUTTER_GRAVITY_EAST:
14048 coord->v.fraction.x = 1.0;
14049 coord->v.fraction.y = 0.5;
14052 case CLUTTER_GRAVITY_SOUTH_EAST:
14053 coord->v.fraction.x = 1.0;
14054 coord->v.fraction.y = 1.0;
14057 case CLUTTER_GRAVITY_SOUTH:
14058 coord->v.fraction.x = 0.5;
14059 coord->v.fraction.y = 1.0;
14062 case CLUTTER_GRAVITY_SOUTH_WEST:
14063 coord->v.fraction.x = 0.0;
14064 coord->v.fraction.y = 1.0;
14067 case CLUTTER_GRAVITY_WEST:
14068 coord->v.fraction.x = 0.0;
14069 coord->v.fraction.y = 0.5;
14072 case CLUTTER_GRAVITY_NORTH_WEST:
14073 coord->v.fraction.x = 0.0;
14074 coord->v.fraction.y = 0.0;
14077 case CLUTTER_GRAVITY_CENTER:
14078 coord->v.fraction.x = 0.5;
14079 coord->v.fraction.y = 0.5;
14083 coord->v.fraction.x = 0.0;
14084 coord->v.fraction.y = 0.0;
14088 coord->is_fractional = TRUE;
14092 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14094 if (coord->is_fractional)
14095 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14097 return (coord->v.units.x == 0.0
14098 && coord->v.units.y == 0.0
14099 && coord->v.units.z == 0.0);
14103 * clutter_actor_get_flags:
14104 * @self: a #ClutterActor
14106 * Retrieves the flags set on @self
14108 * Return value: a bitwise or of #ClutterActorFlags or 0
14113 clutter_actor_get_flags (ClutterActor *self)
14115 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14117 return self->flags;
14121 * clutter_actor_set_flags:
14122 * @self: a #ClutterActor
14123 * @flags: the flags to set
14125 * Sets @flags on @self
14127 * This function will emit notifications for the changed properties
14132 clutter_actor_set_flags (ClutterActor *self,
14133 ClutterActorFlags flags)
14135 ClutterActorFlags old_flags;
14137 gboolean was_reactive_set, reactive_set;
14138 gboolean was_realized_set, realized_set;
14139 gboolean was_mapped_set, mapped_set;
14140 gboolean was_visible_set, visible_set;
14142 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14144 if (self->flags == flags)
14147 obj = G_OBJECT (self);
14148 g_object_ref (obj);
14149 g_object_freeze_notify (obj);
14151 old_flags = self->flags;
14153 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14154 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14155 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14156 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14158 self->flags |= flags;
14160 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14161 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14162 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14163 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14165 if (reactive_set != was_reactive_set)
14166 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14168 if (realized_set != was_realized_set)
14169 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14171 if (mapped_set != was_mapped_set)
14172 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14174 if (visible_set != was_visible_set)
14175 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14177 g_object_thaw_notify (obj);
14178 g_object_unref (obj);
14182 * clutter_actor_unset_flags:
14183 * @self: a #ClutterActor
14184 * @flags: the flags to unset
14186 * Unsets @flags on @self
14188 * This function will emit notifications for the changed properties
14193 clutter_actor_unset_flags (ClutterActor *self,
14194 ClutterActorFlags flags)
14196 ClutterActorFlags old_flags;
14198 gboolean was_reactive_set, reactive_set;
14199 gboolean was_realized_set, realized_set;
14200 gboolean was_mapped_set, mapped_set;
14201 gboolean was_visible_set, visible_set;
14203 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14205 obj = G_OBJECT (self);
14206 g_object_freeze_notify (obj);
14208 old_flags = self->flags;
14210 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14211 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14212 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14213 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14215 self->flags &= ~flags;
14217 if (self->flags == old_flags)
14220 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14221 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14222 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14223 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14225 if (reactive_set != was_reactive_set)
14226 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14228 if (realized_set != was_realized_set)
14229 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14231 if (mapped_set != was_mapped_set)
14232 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14234 if (visible_set != was_visible_set)
14235 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14237 g_object_thaw_notify (obj);
14241 * clutter_actor_get_transformation_matrix:
14242 * @self: a #ClutterActor
14243 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14245 * Retrieves the transformations applied to @self relative to its
14251 clutter_actor_get_transformation_matrix (ClutterActor *self,
14252 CoglMatrix *matrix)
14254 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14256 cogl_matrix_init_identity (matrix);
14258 _clutter_actor_apply_modelview_transform (self, matrix);
14262 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14263 gboolean is_in_clone_paint)
14265 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14266 self->priv->in_clone_paint = is_in_clone_paint;
14270 * clutter_actor_is_in_clone_paint:
14271 * @self: a #ClutterActor
14273 * Checks whether @self is being currently painted by a #ClutterClone
14275 * This function is useful only inside the ::paint virtual function
14276 * implementations or within handlers for the #ClutterActor::paint
14279 * This function should not be used by applications
14281 * Return value: %TRUE if the #ClutterActor is currently being painted
14282 * by a #ClutterClone, and %FALSE otherwise
14287 clutter_actor_is_in_clone_paint (ClutterActor *self)
14289 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14291 return self->priv->in_clone_paint;
14295 set_direction_recursive (ClutterActor *actor,
14296 gpointer user_data)
14298 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14300 clutter_actor_set_text_direction (actor, text_dir);
14306 * clutter_actor_set_text_direction:
14307 * @self: a #ClutterActor
14308 * @text_dir: the text direction for @self
14310 * Sets the #ClutterTextDirection for an actor
14312 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14314 * If @self implements #ClutterContainer then this function will recurse
14315 * inside all the children of @self (including the internal ones).
14317 * Composite actors not implementing #ClutterContainer, or actors requiring
14318 * special handling when the text direction changes, should connect to
14319 * the #GObject::notify signal for the #ClutterActor:text-direction property
14324 clutter_actor_set_text_direction (ClutterActor *self,
14325 ClutterTextDirection text_dir)
14327 ClutterActorPrivate *priv;
14329 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14330 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14334 if (priv->text_direction != text_dir)
14336 priv->text_direction = text_dir;
14338 /* we need to emit the notify::text-direction first, so that
14339 * the sub-classes can catch that and do specific handling of
14340 * the text direction; see clutter_text_direction_changed_cb()
14341 * inside clutter-text.c
14343 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14345 _clutter_actor_foreach_child (self, set_direction_recursive,
14346 GINT_TO_POINTER (text_dir));
14348 clutter_actor_queue_relayout (self);
14353 _clutter_actor_set_has_pointer (ClutterActor *self,
14354 gboolean has_pointer)
14356 ClutterActorPrivate *priv = self->priv;
14358 if (priv->has_pointer != has_pointer)
14360 priv->has_pointer = has_pointer;
14362 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14367 * clutter_actor_get_text_direction:
14368 * @self: a #ClutterActor
14370 * Retrieves the value set using clutter_actor_set_text_direction()
14372 * If no text direction has been previously set, the default text
14373 * direction, as returned by clutter_get_default_text_direction(), will
14374 * be returned instead
14376 * Return value: the #ClutterTextDirection for the actor
14380 ClutterTextDirection
14381 clutter_actor_get_text_direction (ClutterActor *self)
14383 ClutterActorPrivate *priv;
14385 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14386 CLUTTER_TEXT_DIRECTION_LTR);
14390 /* if no direction has been set yet use the default */
14391 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14392 priv->text_direction = clutter_get_default_text_direction ();
14394 return priv->text_direction;
14398 * clutter_actor_push_internal:
14399 * @self: a #ClutterActor
14401 * Should be used by actors implementing the #ClutterContainer and with
14402 * internal children added through clutter_actor_set_parent(), for instance:
14406 * my_actor_init (MyActor *self)
14408 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14410 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14412 * /* calling clutter_actor_set_parent() now will result in
14413 * * the internal flag being set on a child of MyActor
14416 * /* internal child - a background texture */
14417 * self->priv->background_tex = clutter_texture_new ();
14418 * clutter_actor_set_parent (self->priv->background_tex,
14419 * CLUTTER_ACTOR (self));
14421 * /* internal child - a label */
14422 * self->priv->label = clutter_text_new ();
14423 * clutter_actor_set_parent (self->priv->label,
14424 * CLUTTER_ACTOR (self));
14426 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14428 * /* calling clutter_actor_set_parent() now will not result in
14429 * * the internal flag being set on a child of MyActor
14434 * This function will be used by Clutter to toggle an "internal child"
14435 * flag whenever clutter_actor_set_parent() is called; internal children
14436 * are handled differently by Clutter, specifically when destroying their
14439 * Call clutter_actor_pop_internal() when you finished adding internal
14442 * Nested calls to clutter_actor_push_internal() are allowed, but each
14443 * one must by followed by a clutter_actor_pop_internal() call.
14447 * Deprecated: 1.10: All children of an actor are accessible through
14448 * the #ClutterActor API, and #ClutterActor implements the
14449 * #ClutterContainer interface, so this function is only useful
14450 * for legacy containers overriding the default implementation.
14453 clutter_actor_push_internal (ClutterActor *self)
14455 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14457 self->priv->internal_child += 1;
14461 * clutter_actor_pop_internal:
14462 * @self: a #ClutterActor
14464 * Disables the effects of clutter_actor_push_internal().
14468 * Deprecated: 1.10: All children of an actor are accessible through
14469 * the #ClutterActor API. This function is only useful for legacy
14470 * containers overriding the default implementation of the
14471 * #ClutterContainer interface.
14474 clutter_actor_pop_internal (ClutterActor *self)
14476 ClutterActorPrivate *priv;
14478 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14482 if (priv->internal_child == 0)
14484 g_warning ("Mismatched %s: you need to call "
14485 "clutter_actor_push_composite() at least once before "
14486 "calling this function", G_STRFUNC);
14490 priv->internal_child -= 1;
14494 * clutter_actor_has_pointer:
14495 * @self: a #ClutterActor
14497 * Checks whether an actor contains the pointer of a
14498 * #ClutterInputDevice
14500 * Return value: %TRUE if the actor contains the pointer, and
14506 clutter_actor_has_pointer (ClutterActor *self)
14508 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14510 return self->priv->has_pointer;
14513 /* XXX: This is a workaround for not being able to break the ABI of
14514 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14515 * clutter_actor_queue_clipped_redraw() for details.
14517 ClutterPaintVolume *
14518 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14520 return g_object_get_data (G_OBJECT (self),
14521 "-clutter-actor-queue-redraw-clip");
14525 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14526 ClutterPaintVolume *clip)
14528 g_object_set_data (G_OBJECT (self),
14529 "-clutter-actor-queue-redraw-clip",
14534 * clutter_actor_has_allocation:
14535 * @self: a #ClutterActor
14537 * Checks if the actor has an up-to-date allocation assigned to
14538 * it. This means that the actor should have an allocation: it's
14539 * visible and has a parent. It also means that there is no
14540 * outstanding relayout request in progress for the actor or its
14541 * children (There might be other outstanding layout requests in
14542 * progress that will cause the actor to get a new allocation
14543 * when the stage is laid out, however).
14545 * If this function returns %FALSE, then the actor will normally
14546 * be allocated before it is next drawn on the screen.
14548 * Return value: %TRUE if the actor has an up-to-date allocation
14553 clutter_actor_has_allocation (ClutterActor *self)
14555 ClutterActorPrivate *priv;
14557 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14561 return priv->parent != NULL &&
14562 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14563 !priv->needs_allocation;
14567 * clutter_actor_add_action:
14568 * @self: a #ClutterActor
14569 * @action: a #ClutterAction
14571 * Adds @action to the list of actions applied to @self
14573 * A #ClutterAction can only belong to one actor at a time
14575 * The #ClutterActor will hold a reference on @action until either
14576 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14582 clutter_actor_add_action (ClutterActor *self,
14583 ClutterAction *action)
14585 ClutterActorPrivate *priv;
14587 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14588 g_return_if_fail (CLUTTER_IS_ACTION (action));
14592 if (priv->actions == NULL)
14594 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14595 priv->actions->actor = self;
14598 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14600 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14604 * clutter_actor_add_action_with_name:
14605 * @self: a #ClutterActor
14606 * @name: the name to set on the action
14607 * @action: a #ClutterAction
14609 * A convenience function for setting the name of a #ClutterAction
14610 * while adding it to the list of actions applied to @self
14612 * This function is the logical equivalent of:
14615 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14616 * clutter_actor_add_action (self, action);
14622 clutter_actor_add_action_with_name (ClutterActor *self,
14624 ClutterAction *action)
14626 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14627 g_return_if_fail (name != NULL);
14628 g_return_if_fail (CLUTTER_IS_ACTION (action));
14630 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14631 clutter_actor_add_action (self, action);
14635 * clutter_actor_remove_action:
14636 * @self: a #ClutterActor
14637 * @action: a #ClutterAction
14639 * Removes @action from the list of actions applied to @self
14641 * The reference held by @self on the #ClutterAction will be released
14646 clutter_actor_remove_action (ClutterActor *self,
14647 ClutterAction *action)
14649 ClutterActorPrivate *priv;
14651 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14652 g_return_if_fail (CLUTTER_IS_ACTION (action));
14656 if (priv->actions == NULL)
14659 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14661 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14665 * clutter_actor_remove_action_by_name:
14666 * @self: a #ClutterActor
14667 * @name: the name of the action to remove
14669 * Removes the #ClutterAction with the given name from the list
14670 * of actions applied to @self
14675 clutter_actor_remove_action_by_name (ClutterActor *self,
14678 ClutterActorPrivate *priv;
14679 ClutterActorMeta *meta;
14681 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14682 g_return_if_fail (name != NULL);
14686 if (priv->actions == NULL)
14689 meta = _clutter_meta_group_get_meta (priv->actions, name);
14693 _clutter_meta_group_remove_meta (priv->actions, meta);
14695 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14699 * clutter_actor_get_actions:
14700 * @self: a #ClutterActor
14702 * Retrieves the list of actions applied to @self
14704 * Return value: (transfer container) (element-type Clutter.Action): a copy
14705 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14706 * owned by the #ClutterActor. Use g_list_free() to free the resources
14707 * allocated by the returned #GList
14712 clutter_actor_get_actions (ClutterActor *self)
14714 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14716 if (self->priv->actions == NULL)
14719 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14723 * clutter_actor_get_action:
14724 * @self: a #ClutterActor
14725 * @name: the name of the action to retrieve
14727 * Retrieves the #ClutterAction with the given name in the list
14728 * of actions applied to @self
14730 * Return value: (transfer none): a #ClutterAction for the given
14731 * name, or %NULL. The returned #ClutterAction is owned by the
14732 * actor and it should not be unreferenced directly
14737 clutter_actor_get_action (ClutterActor *self,
14740 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14741 g_return_val_if_fail (name != NULL, NULL);
14743 if (self->priv->actions == NULL)
14746 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14750 * clutter_actor_clear_actions:
14751 * @self: a #ClutterActor
14753 * Clears the list of actions applied to @self
14758 clutter_actor_clear_actions (ClutterActor *self)
14760 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14762 if (self->priv->actions == NULL)
14765 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14769 * clutter_actor_add_constraint:
14770 * @self: a #ClutterActor
14771 * @constraint: a #ClutterConstraint
14773 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14776 * The #ClutterActor will hold a reference on the @constraint until
14777 * either clutter_actor_remove_constraint() or
14778 * clutter_actor_clear_constraints() is called.
14783 clutter_actor_add_constraint (ClutterActor *self,
14784 ClutterConstraint *constraint)
14786 ClutterActorPrivate *priv;
14788 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14789 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14793 if (priv->constraints == NULL)
14795 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14796 priv->constraints->actor = self;
14799 _clutter_meta_group_add_meta (priv->constraints,
14800 CLUTTER_ACTOR_META (constraint));
14801 clutter_actor_queue_relayout (self);
14803 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14807 * clutter_actor_add_constraint_with_name:
14808 * @self: a #ClutterActor
14809 * @name: the name to set on the constraint
14810 * @constraint: a #ClutterConstraint
14812 * A convenience function for setting the name of a #ClutterConstraint
14813 * while adding it to the list of constraints applied to @self
14815 * This function is the logical equivalent of:
14818 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14819 * clutter_actor_add_constraint (self, constraint);
14825 clutter_actor_add_constraint_with_name (ClutterActor *self,
14827 ClutterConstraint *constraint)
14829 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14830 g_return_if_fail (name != NULL);
14831 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14833 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14834 clutter_actor_add_constraint (self, constraint);
14838 * clutter_actor_remove_constraint:
14839 * @self: a #ClutterActor
14840 * @constraint: a #ClutterConstraint
14842 * Removes @constraint from the list of constraints applied to @self
14844 * The reference held by @self on the #ClutterConstraint will be released
14849 clutter_actor_remove_constraint (ClutterActor *self,
14850 ClutterConstraint *constraint)
14852 ClutterActorPrivate *priv;
14854 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14855 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14859 if (priv->constraints == NULL)
14862 _clutter_meta_group_remove_meta (priv->constraints,
14863 CLUTTER_ACTOR_META (constraint));
14864 clutter_actor_queue_relayout (self);
14866 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14870 * clutter_actor_remove_constraint_by_name:
14871 * @self: a #ClutterActor
14872 * @name: the name of the constraint to remove
14874 * Removes the #ClutterConstraint with the given name from the list
14875 * of constraints applied to @self
14880 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14883 ClutterActorPrivate *priv;
14884 ClutterActorMeta *meta;
14886 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14887 g_return_if_fail (name != NULL);
14891 if (priv->constraints == NULL)
14894 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14898 _clutter_meta_group_remove_meta (priv->constraints, meta);
14899 clutter_actor_queue_relayout (self);
14903 * clutter_actor_get_constraints:
14904 * @self: a #ClutterActor
14906 * Retrieves the list of constraints applied to @self
14908 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14909 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14910 * owned by the #ClutterActor. Use g_list_free() to free the resources
14911 * allocated by the returned #GList
14916 clutter_actor_get_constraints (ClutterActor *self)
14918 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14920 if (self->priv->constraints == NULL)
14923 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14927 * clutter_actor_get_constraint:
14928 * @self: a #ClutterActor
14929 * @name: the name of the constraint to retrieve
14931 * Retrieves the #ClutterConstraint with the given name in the list
14932 * of constraints applied to @self
14934 * Return value: (transfer none): a #ClutterConstraint for the given
14935 * name, or %NULL. The returned #ClutterConstraint is owned by the
14936 * actor and it should not be unreferenced directly
14940 ClutterConstraint *
14941 clutter_actor_get_constraint (ClutterActor *self,
14944 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14945 g_return_val_if_fail (name != NULL, NULL);
14947 if (self->priv->constraints == NULL)
14950 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14954 * clutter_actor_clear_constraints:
14955 * @self: a #ClutterActor
14957 * Clears the list of constraints applied to @self
14962 clutter_actor_clear_constraints (ClutterActor *self)
14964 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14966 if (self->priv->constraints == NULL)
14969 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14971 clutter_actor_queue_relayout (self);
14975 * clutter_actor_set_clip_to_allocation:
14976 * @self: a #ClutterActor
14977 * @clip_set: %TRUE to apply a clip tracking the allocation
14979 * Sets whether @self should be clipped to the same size as its
14985 clutter_actor_set_clip_to_allocation (ClutterActor *self,
14988 ClutterActorPrivate *priv;
14990 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14992 clip_set = !!clip_set;
14996 if (priv->clip_to_allocation != clip_set)
14998 priv->clip_to_allocation = clip_set;
15000 clutter_actor_queue_redraw (self);
15002 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15007 * clutter_actor_get_clip_to_allocation:
15008 * @self: a #ClutterActor
15010 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15012 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15017 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15019 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15021 return self->priv->clip_to_allocation;
15025 * clutter_actor_add_effect:
15026 * @self: a #ClutterActor
15027 * @effect: a #ClutterEffect
15029 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15031 * The #ClutterActor will hold a reference on the @effect until either
15032 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15038 clutter_actor_add_effect (ClutterActor *self,
15039 ClutterEffect *effect)
15041 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15042 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15044 _clutter_actor_add_effect_internal (self, effect);
15046 clutter_actor_queue_redraw (self);
15048 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15052 * clutter_actor_add_effect_with_name:
15053 * @self: a #ClutterActor
15054 * @name: the name to set on the effect
15055 * @effect: a #ClutterEffect
15057 * A convenience function for setting the name of a #ClutterEffect
15058 * while adding it to the list of effectss applied to @self
15060 * This function is the logical equivalent of:
15063 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15064 * clutter_actor_add_effect (self, effect);
15070 clutter_actor_add_effect_with_name (ClutterActor *self,
15072 ClutterEffect *effect)
15074 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15075 g_return_if_fail (name != NULL);
15076 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15078 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15079 clutter_actor_add_effect (self, effect);
15083 * clutter_actor_remove_effect:
15084 * @self: a #ClutterActor
15085 * @effect: a #ClutterEffect
15087 * Removes @effect from the list of effects applied to @self
15089 * The reference held by @self on the #ClutterEffect will be released
15094 clutter_actor_remove_effect (ClutterActor *self,
15095 ClutterEffect *effect)
15097 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15098 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15100 _clutter_actor_remove_effect_internal (self, effect);
15102 clutter_actor_queue_redraw (self);
15104 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15108 * clutter_actor_remove_effect_by_name:
15109 * @self: a #ClutterActor
15110 * @name: the name of the effect to remove
15112 * Removes the #ClutterEffect with the given name from the list
15113 * of effects applied to @self
15118 clutter_actor_remove_effect_by_name (ClutterActor *self,
15121 ClutterActorPrivate *priv;
15122 ClutterActorMeta *meta;
15124 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15125 g_return_if_fail (name != NULL);
15129 if (priv->effects == NULL)
15132 meta = _clutter_meta_group_get_meta (priv->effects, name);
15136 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15140 * clutter_actor_get_effects:
15141 * @self: a #ClutterActor
15143 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15145 * Return value: (transfer container) (element-type Clutter.Effect): a list
15146 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15147 * list are owned by Clutter and they should not be freed. You should
15148 * free the returned list using g_list_free() when done
15153 clutter_actor_get_effects (ClutterActor *self)
15155 ClutterActorPrivate *priv;
15157 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15161 if (priv->effects == NULL)
15164 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15168 * clutter_actor_get_effect:
15169 * @self: a #ClutterActor
15170 * @name: the name of the effect to retrieve
15172 * Retrieves the #ClutterEffect with the given name in the list
15173 * of effects applied to @self
15175 * Return value: (transfer none): a #ClutterEffect for the given
15176 * name, or %NULL. The returned #ClutterEffect is owned by the
15177 * actor and it should not be unreferenced directly
15182 clutter_actor_get_effect (ClutterActor *self,
15185 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15186 g_return_val_if_fail (name != NULL, NULL);
15188 if (self->priv->effects == NULL)
15191 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15195 * clutter_actor_clear_effects:
15196 * @self: a #ClutterActor
15198 * Clears the list of effects applied to @self
15203 clutter_actor_clear_effects (ClutterActor *self)
15205 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15207 if (self->priv->effects == NULL)
15210 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15212 clutter_actor_queue_redraw (self);
15216 * clutter_actor_has_key_focus:
15217 * @self: a #ClutterActor
15219 * Checks whether @self is the #ClutterActor that has key focus
15221 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15226 clutter_actor_has_key_focus (ClutterActor *self)
15228 ClutterActor *stage;
15230 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15232 stage = _clutter_actor_get_stage_internal (self);
15236 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15240 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15241 ClutterPaintVolume *pv)
15243 ClutterActorPrivate *priv = self->priv;
15245 /* Actors are only expected to report a valid paint volume
15246 * while they have a valid allocation. */
15247 if (G_UNLIKELY (priv->needs_allocation))
15249 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15250 "Actor needs allocation",
15251 _clutter_actor_get_debug_name (self));
15255 /* Check if there are any handlers connected to the paint
15256 * signal. If there are then all bets are off for what the paint
15257 * volume for this actor might possibly be!
15259 * XXX: It's expected that this is going to end up being quite a
15260 * costly check to have to do here, but we haven't come up with
15261 * another solution that can reliably catch paint signal handlers at
15262 * the right time to either avoid artefacts due to invalid stage
15263 * clipping or due to incorrect culling.
15265 * Previously we checked in clutter_actor_paint(), but at that time
15266 * we may already be using a stage clip that could be derived from
15267 * an invalid paint-volume. We used to try and handle that by
15268 * queuing a follow up, unclipped, redraw but still the previous
15269 * checking wasn't enough to catch invalid volumes involved in
15270 * culling (considering that containers may derive their volume from
15271 * children that haven't yet been painted)
15273 * Longer term, improved solutions could be:
15274 * - Disallow painting in the paint signal, only allow using it
15275 * for tracking when paints happen. We can add another API that
15276 * allows monkey patching the paint of arbitrary actors but in a
15277 * more controlled way and that also supports modifying the
15279 * - If we could be notified somehow when signal handlers are
15280 * connected we wouldn't have to poll for handlers like this.
15282 if (g_signal_has_handler_pending (self,
15283 actor_signals[PAINT],
15287 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15288 "Actor has \"paint\" signal handlers",
15289 _clutter_actor_get_debug_name (self));
15293 _clutter_paint_volume_init_static (pv, self);
15295 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15297 clutter_paint_volume_free (pv);
15298 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15299 "Actor failed to report a volume",
15300 _clutter_actor_get_debug_name (self));
15304 /* since effects can modify the paint volume, we allow them to actually
15305 * do this by making get_paint_volume() "context sensitive"
15307 if (priv->effects != NULL)
15309 if (priv->current_effect != NULL)
15311 const GList *effects, *l;
15313 /* if we are being called from within the paint sequence of
15314 * an actor, get the paint volume up to the current effect
15316 effects = _clutter_meta_group_peek_metas (priv->effects);
15318 l != NULL || (l != NULL && l->data != priv->current_effect);
15321 if (!_clutter_effect_get_paint_volume (l->data, pv))
15323 clutter_paint_volume_free (pv);
15324 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15325 "Effect (%s) failed to report a volume",
15326 _clutter_actor_get_debug_name (self),
15327 _clutter_actor_meta_get_debug_name (l->data));
15334 const GList *effects, *l;
15336 /* otherwise, get the cumulative volume */
15337 effects = _clutter_meta_group_peek_metas (priv->effects);
15338 for (l = effects; l != NULL; l = l->next)
15339 if (!_clutter_effect_get_paint_volume (l->data, pv))
15341 clutter_paint_volume_free (pv);
15342 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15343 "Effect (%s) failed to report a volume",
15344 _clutter_actor_get_debug_name (self),
15345 _clutter_actor_meta_get_debug_name (l->data));
15354 /* The public clutter_actor_get_paint_volume API returns a const
15355 * pointer since we return a pointer directly to the cached
15356 * PaintVolume associated with the actor and don't want the user to
15357 * inadvertently modify it, but for internal uses we sometimes need
15358 * access to the same PaintVolume but need to apply some book-keeping
15359 * modifications to it so we don't want a const pointer.
15361 static ClutterPaintVolume *
15362 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15364 ClutterActorPrivate *priv;
15368 if (priv->paint_volume_valid)
15369 clutter_paint_volume_free (&priv->paint_volume);
15371 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15373 priv->paint_volume_valid = TRUE;
15374 return &priv->paint_volume;
15378 priv->paint_volume_valid = FALSE;
15384 * clutter_actor_get_paint_volume:
15385 * @self: a #ClutterActor
15387 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15388 * when a paint volume can't be determined.
15390 * The paint volume is defined as the 3D space occupied by an actor
15391 * when being painted.
15393 * This function will call the <function>get_paint_volume()</function>
15394 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15395 * should not usually care about overriding the default implementation,
15396 * unless they are, for instance: painting outside their allocation, or
15397 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15400 * <note>2D actors overriding <function>get_paint_volume()</function>
15401 * ensure their volume has a depth of 0. (This will be true so long as
15402 * you don't call clutter_paint_volume_set_depth().)</note>
15404 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15405 * or %NULL if no volume could be determined. The returned pointer
15406 * is not guaranteed to be valid across multiple frames; if you want
15407 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15411 const ClutterPaintVolume *
15412 clutter_actor_get_paint_volume (ClutterActor *self)
15414 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15416 return _clutter_actor_get_paint_volume_mutable (self);
15420 * clutter_actor_get_transformed_paint_volume:
15421 * @self: a #ClutterActor
15422 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15423 * (or %NULL for the stage)
15425 * Retrieves the 3D paint volume of an actor like
15426 * clutter_actor_get_paint_volume() does (Please refer to the
15427 * documentation of clutter_actor_get_paint_volume() for more
15428 * details.) and it additionally transforms the paint volume into the
15429 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15430 * is passed for @relative_to_ancestor)
15432 * This can be used by containers that base their paint volume on
15433 * the volume of their children. Such containers can query the
15434 * transformed paint volume of all of its children and union them
15435 * together using clutter_paint_volume_union().
15437 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15438 * or %NULL if no volume could be determined. The returned pointer is
15439 * not guaranteed to be valid across multiple frames; if you wish to
15440 * keep it, you will have to copy it using clutter_paint_volume_copy().
15444 const ClutterPaintVolume *
15445 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15446 ClutterActor *relative_to_ancestor)
15448 const ClutterPaintVolume *volume;
15449 ClutterActor *stage;
15450 ClutterPaintVolume *transformed_volume;
15452 stage = _clutter_actor_get_stage_internal (self);
15453 if (G_UNLIKELY (stage == NULL))
15456 if (relative_to_ancestor == NULL)
15457 relative_to_ancestor = stage;
15459 volume = clutter_actor_get_paint_volume (self);
15460 if (volume == NULL)
15463 transformed_volume =
15464 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15466 _clutter_paint_volume_copy_static (volume, transformed_volume);
15468 _clutter_paint_volume_transform_relative (transformed_volume,
15469 relative_to_ancestor);
15471 return transformed_volume;
15475 * clutter_actor_get_paint_box:
15476 * @self: a #ClutterActor
15477 * @box: (out): return location for a #ClutterActorBox
15479 * Retrieves the paint volume of the passed #ClutterActor, and
15480 * transforms it into a 2D bounding box in stage coordinates.
15482 * This function is useful to determine the on screen area occupied by
15483 * the actor. The box is only an approximation and may often be
15484 * considerably larger due to the optimizations used to calculate the
15485 * box. The box is never smaller though, so it can reliably be used
15488 * There are times when a 2D paint box can't be determined, e.g.
15489 * because the actor isn't yet parented under a stage or because
15490 * the actor is unable to determine a paint volume.
15492 * Return value: %TRUE if a 2D paint box could be determined, else
15498 clutter_actor_get_paint_box (ClutterActor *self,
15499 ClutterActorBox *box)
15501 ClutterActor *stage;
15502 ClutterPaintVolume *pv;
15504 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15505 g_return_val_if_fail (box != NULL, FALSE);
15507 stage = _clutter_actor_get_stage_internal (self);
15508 if (G_UNLIKELY (!stage))
15511 pv = _clutter_actor_get_paint_volume_mutable (self);
15512 if (G_UNLIKELY (!pv))
15515 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15521 * clutter_actor_has_overlaps:
15522 * @self: A #ClutterActor
15524 * Asks the actor's implementation whether it may contain overlapping
15527 * For example; Clutter may use this to determine whether the painting
15528 * should be redirected to an offscreen buffer to correctly implement
15529 * the opacity property.
15531 * Custom actors can override the default response by implementing the
15532 * #ClutterActor <function>has_overlaps</function> virtual function. See
15533 * clutter_actor_set_offscreen_redirect() for more information.
15535 * Return value: %TRUE if the actor may have overlapping primitives, and
15541 clutter_actor_has_overlaps (ClutterActor *self)
15543 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15545 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15549 * clutter_actor_has_effects:
15550 * @self: A #ClutterActor
15552 * Returns whether the actor has any effects applied.
15554 * Return value: %TRUE if the actor has any effects,
15560 clutter_actor_has_effects (ClutterActor *self)
15562 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15564 if (self->priv->effects == NULL)
15567 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15571 * clutter_actor_has_constraints:
15572 * @self: A #ClutterActor
15574 * Returns whether the actor has any constraints applied.
15576 * Return value: %TRUE if the actor has any constraints,
15582 clutter_actor_has_constraints (ClutterActor *self)
15584 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15586 return self->priv->constraints != NULL;
15590 * clutter_actor_has_actions:
15591 * @self: A #ClutterActor
15593 * Returns whether the actor has any actions applied.
15595 * Return value: %TRUE if the actor has any actions,
15601 clutter_actor_has_actions (ClutterActor *self)
15603 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15605 return self->priv->actions != NULL;
15609 * clutter_actor_get_n_children:
15610 * @self: a #ClutterActor
15612 * Retrieves the number of children of @self.
15614 * Return value: the number of children of an actor
15619 clutter_actor_get_n_children (ClutterActor *self)
15621 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15623 return self->priv->n_children;
15627 * clutter_actor_get_child_at_index:
15628 * @self: a #ClutterActor
15629 * @index_: the position in the list of children
15631 * Retrieves the actor at the given @index_ inside the list of
15632 * children of @self.
15634 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15639 clutter_actor_get_child_at_index (ClutterActor *self,
15642 ClutterActor *iter;
15645 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15646 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15648 for (iter = self->priv->first_child, i = 0;
15649 iter != NULL && i < index_;
15650 iter = iter->priv->next_sibling, i += 1)
15657 * _clutter_actor_foreach_child:
15658 * @actor: The actor whos children you want to iterate
15659 * @callback: The function to call for each child
15660 * @user_data: Private data to pass to @callback
15662 * Calls a given @callback once for each child of the specified @actor and
15663 * passing the @user_data pointer each time.
15665 * Return value: returns %TRUE if all children were iterated, else
15666 * %FALSE if a callback broke out of iteration early.
15669 _clutter_actor_foreach_child (ClutterActor *self,
15670 ClutterForeachCallback callback,
15671 gpointer user_data)
15673 ClutterActorPrivate *priv = self->priv;
15674 ClutterActor *iter;
15677 for (cont = TRUE, iter = priv->first_child;
15678 cont && iter != NULL;
15679 iter = iter->priv->next_sibling)
15681 cont = callback (iter, user_data);
15688 /* For debugging purposes this gives us a simple way to print out
15689 * the scenegraph e.g in gdb using:
15691 * _clutter_actor_traverse (stage,
15693 * clutter_debug_print_actor_cb,
15698 static ClutterActorTraverseVisitFlags
15699 clutter_debug_print_actor_cb (ClutterActor *actor,
15703 g_print ("%*s%s:%p\n",
15705 _clutter_actor_get_debug_name (actor),
15708 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15713 _clutter_actor_traverse_breadth (ClutterActor *actor,
15714 ClutterTraverseCallback callback,
15715 gpointer user_data)
15717 GQueue *queue = g_queue_new ();
15718 ClutterActor dummy;
15719 int current_depth = 0;
15721 g_queue_push_tail (queue, actor);
15722 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15724 while ((actor = g_queue_pop_head (queue)))
15726 ClutterActorTraverseVisitFlags flags;
15728 if (actor == &dummy)
15731 g_queue_push_tail (queue, &dummy);
15735 flags = callback (actor, current_depth, user_data);
15736 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15738 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15740 ClutterActor *iter;
15742 for (iter = actor->priv->first_child;
15744 iter = iter->priv->next_sibling)
15746 g_queue_push_tail (queue, iter);
15751 g_queue_free (queue);
15754 static ClutterActorTraverseVisitFlags
15755 _clutter_actor_traverse_depth (ClutterActor *actor,
15756 ClutterTraverseCallback before_children_callback,
15757 ClutterTraverseCallback after_children_callback,
15759 gpointer user_data)
15761 ClutterActorTraverseVisitFlags flags;
15763 flags = before_children_callback (actor, current_depth, user_data);
15764 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15765 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15767 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15769 ClutterActor *iter;
15771 for (iter = actor->priv->first_child;
15773 iter = iter->priv->next_sibling)
15775 flags = _clutter_actor_traverse_depth (iter,
15776 before_children_callback,
15777 after_children_callback,
15781 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15782 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15786 if (after_children_callback)
15787 return after_children_callback (actor, current_depth, user_data);
15789 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15792 /* _clutter_actor_traverse:
15793 * @actor: The actor to start traversing the graph from
15794 * @flags: These flags may affect how the traversal is done
15795 * @before_children_callback: A function to call before visiting the
15796 * children of the current actor.
15797 * @after_children_callback: A function to call after visiting the
15798 * children of the current actor. (Ignored if
15799 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15800 * @user_data: The private data to pass to the callbacks
15802 * Traverses the scenegraph starting at the specified @actor and
15803 * descending through all its children and its children's children.
15804 * For each actor traversed @before_children_callback and
15805 * @after_children_callback are called with the specified
15806 * @user_data, before and after visiting that actor's children.
15808 * The callbacks can return flags that affect the ongoing traversal
15809 * such as by skipping over an actors children or bailing out of
15810 * any further traversing.
15813 _clutter_actor_traverse (ClutterActor *actor,
15814 ClutterActorTraverseFlags flags,
15815 ClutterTraverseCallback before_children_callback,
15816 ClutterTraverseCallback after_children_callback,
15817 gpointer user_data)
15819 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15820 _clutter_actor_traverse_breadth (actor,
15821 before_children_callback,
15823 else /* DEPTH_FIRST */
15824 _clutter_actor_traverse_depth (actor,
15825 before_children_callback,
15826 after_children_callback,
15827 0, /* start depth */
15832 on_layout_manager_changed (ClutterLayoutManager *manager,
15833 ClutterActor *self)
15835 clutter_actor_queue_relayout (self);
15839 * clutter_actor_set_layout_manager:
15840 * @self: a #ClutterActor
15841 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15843 * Sets the #ClutterLayoutManager delegate object that will be used to
15844 * lay out the children of @self.
15846 * The #ClutterActor will take a reference on the passed @manager which
15847 * will be released either when the layout manager is removed, or when
15848 * the actor is destroyed.
15853 clutter_actor_set_layout_manager (ClutterActor *self,
15854 ClutterLayoutManager *manager)
15856 ClutterActorPrivate *priv;
15858 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15859 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15863 if (priv->layout_manager != NULL)
15865 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15866 G_CALLBACK (on_layout_manager_changed),
15868 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15869 g_object_unref (priv->layout_manager);
15872 priv->layout_manager = manager;
15874 if (priv->layout_manager != NULL)
15876 g_object_ref_sink (priv->layout_manager);
15877 clutter_layout_manager_set_container (priv->layout_manager,
15878 CLUTTER_CONTAINER (self));
15879 g_signal_connect (priv->layout_manager, "layout-changed",
15880 G_CALLBACK (on_layout_manager_changed),
15884 clutter_actor_queue_relayout (self);
15886 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15890 * clutter_actor_get_layout_manager:
15891 * @self: a #ClutterActor
15893 * Retrieves the #ClutterLayoutManager used by @self.
15895 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15900 ClutterLayoutManager *
15901 clutter_actor_get_layout_manager (ClutterActor *self)
15903 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15905 return self->priv->layout_manager;
15908 static const ClutterLayoutInfo default_layout_info = {
15911 { 0, 0, 0, 0 }, /* margin */
15912 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15913 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15914 0.f, 0.f, /* min_width, natural_width */
15915 0.f, 0.f, /* natual_width, natural_height */
15919 layout_info_free (gpointer data)
15921 if (G_LIKELY (data != NULL))
15922 g_slice_free (ClutterLayoutInfo, data);
15926 * _clutter_actor_get_layout_info:
15927 * @self: a #ClutterActor
15929 * Retrieves a pointer to the ClutterLayoutInfo structure.
15931 * If the actor does not have a ClutterLayoutInfo associated to it, one
15932 * will be created and initialized to the default values.
15934 * This function should be used for setters.
15936 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15939 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15941 ClutterLayoutInfo *
15942 _clutter_actor_get_layout_info (ClutterActor *self)
15944 ClutterLayoutInfo *retval;
15946 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15947 if (retval == NULL)
15949 retval = g_slice_new (ClutterLayoutInfo);
15951 *retval = default_layout_info;
15953 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15962 * _clutter_actor_get_layout_info_or_defaults:
15963 * @self: a #ClutterActor
15965 * Retrieves the ClutterLayoutInfo structure associated to an actor.
15967 * If the actor does not have a ClutterLayoutInfo structure associated to it,
15968 * then the default structure will be returned.
15970 * This function should only be used for getters.
15972 * Return value: a const pointer to the ClutterLayoutInfo structure
15974 const ClutterLayoutInfo *
15975 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15977 const ClutterLayoutInfo *info;
15979 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15981 return &default_layout_info;
15987 * clutter_actor_set_x_align:
15988 * @self: a #ClutterActor
15989 * @x_align: the horizontal alignment policy
15991 * Sets the horizontal alignment policy of a #ClutterActor, in case the
15992 * actor received extra horizontal space.
15994 * See also the #ClutterActor:x-align property.
15999 clutter_actor_set_x_align (ClutterActor *self,
16000 ClutterActorAlign x_align)
16002 ClutterLayoutInfo *info;
16004 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16006 info = _clutter_actor_get_layout_info (self);
16008 if (info->x_align != x_align)
16010 info->x_align = x_align;
16012 clutter_actor_queue_relayout (self);
16014 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16019 * clutter_actor_get_x_align:
16020 * @self: a #ClutterActor
16022 * Retrieves the horizontal alignment policy set using
16023 * clutter_actor_set_x_align().
16025 * Return value: the horizontal alignment policy.
16030 clutter_actor_get_x_align (ClutterActor *self)
16032 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16034 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16038 * clutter_actor_set_y_align:
16039 * @self: a #ClutterActor
16040 * @y_align: the vertical alignment policy
16042 * Sets the vertical alignment policy of a #ClutterActor, in case the
16043 * actor received extra vertical space.
16045 * See also the #ClutterActor:y-align property.
16050 clutter_actor_set_y_align (ClutterActor *self,
16051 ClutterActorAlign y_align)
16053 ClutterLayoutInfo *info;
16055 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16057 info = _clutter_actor_get_layout_info (self);
16059 if (info->y_align != y_align)
16061 info->y_align = y_align;
16063 clutter_actor_queue_relayout (self);
16065 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16070 * clutter_actor_get_y_align:
16071 * @self: a #ClutterActor
16073 * Retrieves the vertical alignment policy set using
16074 * clutter_actor_set_y_align().
16076 * Return value: the vertical alignment policy.
16081 clutter_actor_get_y_align (ClutterActor *self)
16083 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16085 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16090 * clutter_margin_new:
16092 * Creates a new #ClutterMargin.
16094 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16095 * clutter_margin_free() to free the resources associated with it when
16101 clutter_margin_new (void)
16103 return g_slice_new0 (ClutterMargin);
16107 * clutter_margin_copy:
16108 * @margin_: a #ClutterMargin
16110 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16111 * the newly created structure.
16113 * Return value: (transfer full): a copy of the #ClutterMargin.
16118 clutter_margin_copy (const ClutterMargin *margin_)
16120 if (G_LIKELY (margin_ != NULL))
16121 return g_slice_dup (ClutterMargin, margin_);
16127 * clutter_margin_free:
16128 * @margin_: a #ClutterMargin
16130 * Frees the resources allocated by clutter_margin_new() and
16131 * clutter_margin_copy().
16136 clutter_margin_free (ClutterMargin *margin_)
16138 if (G_LIKELY (margin_ != NULL))
16139 g_slice_free (ClutterMargin, margin_);
16142 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16143 clutter_margin_copy,
16144 clutter_margin_free)
16147 * clutter_actor_set_margin:
16148 * @self: a #ClutterActor
16149 * @margin: a #ClutterMargin
16151 * Sets all the components of the margin of a #ClutterActor.
16156 clutter_actor_set_margin (ClutterActor *self,
16157 const ClutterMargin *margin)
16159 ClutterLayoutInfo *info;
16163 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16164 g_return_if_fail (margin != NULL);
16166 obj = G_OBJECT (self);
16169 g_object_freeze_notify (obj);
16171 info = _clutter_actor_get_layout_info (self);
16173 if (info->margin.top != margin->top)
16175 info->margin.top = margin->top;
16176 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16180 if (info->margin.right != margin->right)
16182 info->margin.right = margin->right;
16183 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16187 if (info->margin.bottom != margin->bottom)
16189 info->margin.bottom = margin->bottom;
16190 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16194 if (info->margin.left != margin->left)
16196 info->margin.left = margin->left;
16197 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16202 clutter_actor_queue_relayout (self);
16204 g_object_thaw_notify (obj);
16208 * clutter_actor_get_margin:
16209 * @self: a #ClutterActor
16210 * @margin: (out caller-allocates): return location for a #ClutterMargin
16212 * Retrieves all the components of the margin of a #ClutterActor.
16217 clutter_actor_get_margin (ClutterActor *self,
16218 ClutterMargin *margin)
16220 const ClutterLayoutInfo *info;
16222 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16223 g_return_if_fail (margin != NULL);
16225 info = _clutter_actor_get_layout_info_or_defaults (self);
16227 *margin = info->margin;
16231 * clutter_actor_set_margin_top:
16232 * @self: a #ClutterActor
16233 * @margin: the top margin
16235 * Sets the margin from the top of a #ClutterActor.
16240 clutter_actor_set_margin_top (ClutterActor *self,
16243 ClutterLayoutInfo *info;
16245 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16246 g_return_if_fail (margin >= 0.f);
16248 info = _clutter_actor_get_layout_info (self);
16250 if (info->margin.top == margin)
16253 info->margin.top = margin;
16255 clutter_actor_queue_relayout (self);
16257 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16261 * clutter_actor_get_margin_top:
16262 * @self: a #ClutterActor
16264 * Retrieves the top margin of a #ClutterActor.
16266 * Return value: the top margin
16271 clutter_actor_get_margin_top (ClutterActor *self)
16273 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16275 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16279 * clutter_actor_set_margin_bottom:
16280 * @self: a #ClutterActor
16281 * @margin: the bottom margin
16283 * Sets the margin from the bottom of a #ClutterActor.
16288 clutter_actor_set_margin_bottom (ClutterActor *self,
16291 ClutterLayoutInfo *info;
16293 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16294 g_return_if_fail (margin >= 0.f);
16296 info = _clutter_actor_get_layout_info (self);
16298 if (info->margin.bottom == margin)
16301 info->margin.bottom = margin;
16303 clutter_actor_queue_relayout (self);
16305 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16309 * clutter_actor_get_margin_bottom:
16310 * @self: a #ClutterActor
16312 * Retrieves the bottom margin of a #ClutterActor.
16314 * Return value: the bottom margin
16319 clutter_actor_get_margin_bottom (ClutterActor *self)
16321 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16323 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16327 * clutter_actor_set_margin_left:
16328 * @self: a #ClutterActor
16329 * @margin: the left margin
16331 * Sets the margin from the left of a #ClutterActor.
16336 clutter_actor_set_margin_left (ClutterActor *self,
16339 ClutterLayoutInfo *info;
16341 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16342 g_return_if_fail (margin >= 0.f);
16344 info = _clutter_actor_get_layout_info (self);
16346 if (info->margin.left == margin)
16349 info->margin.left = margin;
16351 clutter_actor_queue_relayout (self);
16353 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16357 * clutter_actor_get_margin_left:
16358 * @self: a #ClutterActor
16360 * Retrieves the left margin of a #ClutterActor.
16362 * Return value: the left margin
16367 clutter_actor_get_margin_left (ClutterActor *self)
16369 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16371 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16375 * clutter_actor_set_margin_right:
16376 * @self: a #ClutterActor
16377 * @margin: the right margin
16379 * Sets the margin from the right of a #ClutterActor.
16384 clutter_actor_set_margin_right (ClutterActor *self,
16387 ClutterLayoutInfo *info;
16389 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16390 g_return_if_fail (margin >= 0.f);
16392 info = _clutter_actor_get_layout_info (self);
16394 if (info->margin.right == margin)
16397 info->margin.right = margin;
16399 clutter_actor_queue_relayout (self);
16401 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16405 * clutter_actor_get_margin_right:
16406 * @self: a #ClutterActor
16408 * Retrieves the right margin of a #ClutterActor.
16410 * Return value: the right margin
16415 clutter_actor_get_margin_right (ClutterActor *self)
16417 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16419 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16423 clutter_actor_set_background_color_internal (ClutterActor *self,
16424 const ClutterColor *color)
16426 ClutterActorPrivate *priv = self->priv;
16429 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16432 obj = G_OBJECT (self);
16434 priv->bg_color = *color;
16435 priv->bg_color_set = TRUE;
16437 clutter_actor_queue_redraw (self);
16439 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16440 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16444 * clutter_actor_set_background_color:
16445 * @self: a #ClutterActor
16446 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16449 * Sets the background color of a #ClutterActor.
16451 * The background color will be used to cover the whole allocation of the
16452 * actor. The default background color of an actor is transparent.
16454 * To check whether an actor has a background color, you can use the
16455 * #ClutterActor:background-color-set actor property.
16457 * The #ClutterActor:background-color property is animatable.
16462 clutter_actor_set_background_color (ClutterActor *self,
16463 const ClutterColor *color)
16465 ClutterActorPrivate *priv;
16467 GParamSpec *bg_color_pspec;
16469 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16471 obj = G_OBJECT (self);
16477 priv->bg_color_set = FALSE;
16478 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16479 clutter_actor_queue_redraw (self);
16483 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16484 if (clutter_actor_get_easing_duration (self) != 0)
16486 ClutterTransition *transition;
16488 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16489 if (transition == NULL)
16491 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16494 clutter_timeline_start (CLUTTER_TIMELINE (transition));
16497 _clutter_actor_update_transition (self, bg_color_pspec, color);
16499 clutter_actor_queue_redraw (self);
16502 clutter_actor_set_background_color_internal (self, color);
16506 * clutter_actor_get_background_color:
16507 * @self: a #ClutterActor
16508 * @color: (out caller-allocates): return location for a #ClutterColor
16510 * Retrieves the color set using clutter_actor_set_background_color().
16515 clutter_actor_get_background_color (ClutterActor *self,
16516 ClutterColor *color)
16518 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16519 g_return_if_fail (color != NULL);
16521 *color = self->priv->bg_color;
16525 * clutter_actor_get_previous_sibling:
16526 * @self: a #ClutterActor
16528 * Retrieves the sibling of @self that comes before it in the list
16529 * of children of @self's parent.
16531 * The returned pointer is only valid until the scene graph changes; it
16532 * is not safe to modify the list of children of @self while iterating
16535 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16540 clutter_actor_get_previous_sibling (ClutterActor *self)
16542 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16544 return self->priv->prev_sibling;
16548 * clutter_actor_get_next_sibling:
16549 * @self: a #ClutterActor
16551 * Retrieves the sibling of @self that comes after it in the list
16552 * of children of @self's parent.
16554 * The returned pointer is only valid until the scene graph changes; it
16555 * is not safe to modify the list of children of @self while iterating
16558 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16563 clutter_actor_get_next_sibling (ClutterActor *self)
16565 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16567 return self->priv->next_sibling;
16571 * clutter_actor_get_first_child:
16572 * @self: a #ClutterActor
16574 * Retrieves the first child of @self.
16576 * The returned pointer is only valid until the scene graph changes; it
16577 * is not safe to modify the list of children of @self while iterating
16580 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16585 clutter_actor_get_first_child (ClutterActor *self)
16587 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16589 return self->priv->first_child;
16593 * clutter_actor_get_last_child:
16594 * @self: a #ClutterActor
16596 * Retrieves the last child of @self.
16598 * The returned pointer is only valid until the scene graph changes; it
16599 * is not safe to modify the list of children of @self while iterating
16602 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16607 clutter_actor_get_last_child (ClutterActor *self)
16609 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16611 return self->priv->last_child;
16614 /* easy way to have properly named fields instead of the dummy ones
16615 * we use in the public structure
16617 typedef struct _RealActorIter
16619 ClutterActor *root; /* dummy1 */
16620 ClutterActor *current; /* dummy2 */
16621 gpointer padding_1; /* dummy3 */
16622 gint age; /* dummy4 */
16623 gpointer padding_2; /* dummy5 */
16627 * clutter_actor_iter_init:
16628 * @iter: a #ClutterActorIter
16629 * @root: a #ClutterActor
16631 * Initializes a #ClutterActorIter, which can then be used to iterate
16632 * efficiently over a section of the scene graph, and associates it
16635 * Modifying the scene graph section that contains @root will invalidate
16639 * ClutterActorIter iter;
16640 * ClutterActor *child;
16642 * clutter_actor_iter_init (&iter, container);
16643 * while (clutter_actor_iter_next (&iter, &child))
16645 * /* do something with child */
16652 clutter_actor_iter_init (ClutterActorIter *iter,
16653 ClutterActor *root)
16655 RealActorIter *ri = (RealActorIter *) iter;
16657 g_return_if_fail (iter != NULL);
16658 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16661 ri->current = NULL;
16662 ri->age = root->priv->age;
16666 * clutter_actor_iter_next:
16667 * @iter: a #ClutterActorIter
16668 * @child: (out): return location for a #ClutterActor
16670 * Advances the @iter and retrieves the next child of the root #ClutterActor
16671 * that was used to initialize the #ClutterActorIterator.
16673 * If the iterator can advance, this function returns %TRUE and sets the
16676 * If the iterator cannot advance, this function returns %FALSE, and
16677 * the contents of @child are undefined.
16679 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16684 clutter_actor_iter_next (ClutterActorIter *iter,
16685 ClutterActor **child)
16687 RealActorIter *ri = (RealActorIter *) iter;
16689 g_return_val_if_fail (iter != NULL, FALSE);
16690 g_return_val_if_fail (ri->root != NULL, FALSE);
16691 #ifndef G_DISABLE_ASSERT
16692 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16695 if (ri->current == NULL)
16696 ri->current = ri->root->priv->first_child;
16698 ri->current = ri->current->priv->next_sibling;
16701 *child = ri->current;
16703 return ri->current != NULL;
16707 * clutter_actor_iter_prev:
16708 * @iter: a #ClutterActorIter
16709 * @child: (out): return location for a #ClutterActor
16711 * Advances the @iter and retrieves the previous child of the root
16712 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16714 * If the iterator can advance, this function returns %TRUE and sets the
16717 * If the iterator cannot advance, this function returns %FALSE, and
16718 * the contents of @child are undefined.
16720 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16725 clutter_actor_iter_prev (ClutterActorIter *iter,
16726 ClutterActor **child)
16728 RealActorIter *ri = (RealActorIter *) iter;
16730 g_return_val_if_fail (iter != NULL, FALSE);
16731 g_return_val_if_fail (ri->root != NULL, FALSE);
16732 #ifndef G_DISABLE_ASSERT
16733 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16736 if (ri->current == NULL)
16737 ri->current = ri->root->priv->last_child;
16739 ri->current = ri->current->priv->prev_sibling;
16742 *child = ri->current;
16744 return ri->current != NULL;
16748 * clutter_actor_iter_remove:
16749 * @iter: a #ClutterActorIter
16751 * Safely removes the #ClutterActor currently pointer to by the iterator
16754 * This function can only be called after clutter_actor_iter_next() or
16755 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16756 * than once for the same actor.
16758 * This function will call clutter_actor_remove_child() internally.
16763 clutter_actor_iter_remove (ClutterActorIter *iter)
16765 RealActorIter *ri = (RealActorIter *) iter;
16768 g_return_if_fail (iter != NULL);
16769 g_return_if_fail (ri->root != NULL);
16770 #ifndef G_DISABLE_ASSERT
16771 g_return_if_fail (ri->age == ri->root->priv->age);
16773 g_return_if_fail (ri->current != NULL);
16779 ri->current = cur->priv->prev_sibling;
16781 clutter_actor_remove_child_internal (ri->root, cur,
16782 REMOVE_CHILD_DEFAULT_FLAGS);
16789 * clutter_actor_iter_destroy:
16790 * @iter: a #ClutterActorIter
16792 * Safely destroys the #ClutterActor currently pointer to by the iterator
16795 * This function can only be called after clutter_actor_iter_next() or
16796 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16797 * than once for the same actor.
16799 * This function will call clutter_actor_destroy() internally.
16804 clutter_actor_iter_destroy (ClutterActorIter *iter)
16806 RealActorIter *ri = (RealActorIter *) iter;
16809 g_return_if_fail (iter != NULL);
16810 g_return_if_fail (ri->root != NULL);
16811 #ifndef G_DISABLE_ASSERT
16812 g_return_if_fail (ri->age == ri->root->priv->age);
16814 g_return_if_fail (ri->current != NULL);
16820 ri->current = cur->priv->prev_sibling;
16822 clutter_actor_destroy (cur);
16828 static const ClutterAnimationInfo default_animation_info = {
16829 NULL, /* transitions */
16831 NULL, /* cur_state */
16835 clutter_animation_info_free (gpointer data)
16839 ClutterAnimationInfo *info = data;
16841 if (info->transitions != NULL)
16842 g_hash_table_unref (info->transitions);
16844 if (info->states != NULL)
16845 g_array_unref (info->states);
16847 g_slice_free (ClutterAnimationInfo, info);
16851 const ClutterAnimationInfo *
16852 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16854 const ClutterAnimationInfo *res;
16855 GObject *obj = G_OBJECT (self);
16857 res = g_object_get_qdata (obj, quark_actor_animation_info);
16861 return &default_animation_info;
16864 ClutterAnimationInfo *
16865 _clutter_actor_get_animation_info (ClutterActor *self)
16867 GObject *obj = G_OBJECT (self);
16868 ClutterAnimationInfo *res;
16870 res = g_object_get_qdata (obj, quark_actor_animation_info);
16873 res = g_slice_new (ClutterAnimationInfo);
16875 *res = default_animation_info;
16877 g_object_set_qdata_full (obj, quark_actor_animation_info,
16879 clutter_animation_info_free);
16885 ClutterTransition *
16886 _clutter_actor_get_transition (ClutterActor *actor,
16889 const ClutterAnimationInfo *info;
16891 info = _clutter_actor_get_animation_info_or_defaults (actor);
16893 if (info->transitions == NULL)
16896 return g_hash_table_lookup (info->transitions, pspec->name);
16899 typedef struct _TransitionClosure
16901 ClutterActor *actor;
16902 ClutterTransition *transition;
16904 gulong completed_id;
16905 } TransitionClosure;
16908 transition_closure_free (gpointer data)
16910 if (G_LIKELY (data != NULL))
16912 TransitionClosure *clos = data;
16914 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16915 g_free (clos->name);
16917 g_slice_free (TransitionClosure, clos);
16922 on_transition_completed (ClutterTransition *transition,
16923 TransitionClosure *clos)
16925 ClutterAnimationInfo *info;
16927 info = _clutter_actor_get_animation_info (clos->actor);
16929 /* this will take care of cleaning clos for us */
16930 g_hash_table_remove (info->transitions, clos->name);
16934 _clutter_actor_update_transition (ClutterActor *actor,
16938 TransitionClosure *clos;
16939 ClutterInterval *interval;
16940 const ClutterAnimationInfo *info;
16943 GValue initial = G_VALUE_INIT;
16944 GValue final = G_VALUE_INIT;
16945 char *error = NULL;
16947 info = _clutter_actor_get_animation_info_or_defaults (actor);
16949 if (info->transitions == NULL)
16952 clos = g_hash_table_lookup (info->transitions, pspec->name);
16956 va_start (var_args, pspec);
16958 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16960 g_value_init (&initial, ptype);
16961 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16965 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16968 g_critical ("%s: %s", G_STRLOC, error);
16973 interval = clutter_transition_get_interval (clos->transition);
16974 clutter_interval_set_initial_value (interval, &initial);
16975 clutter_interval_set_final_value (interval, &final);
16977 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16980 g_value_unset (&initial);
16981 g_value_unset (&final);
16987 * _clutter_actor_create_transition:
16988 * @actor: a #ClutterActor
16989 * @pspec: the property used for the transition
16990 * @...: initial and final state
16992 * Creates a #ClutterTransition for the property represented by @pspec.
16994 * Return value: a #ClutterTransition
16996 ClutterTransition *
16997 _clutter_actor_create_transition (ClutterActor *actor,
17001 ClutterAnimationInfo *info;
17002 ClutterTransition *res = NULL;
17003 gboolean call_restore = FALSE;
17004 TransitionClosure *clos;
17007 info = _clutter_actor_get_animation_info (actor);
17009 if (info->states == NULL)
17011 clutter_actor_save_easing_state (actor);
17012 call_restore = TRUE;
17015 if (info->transitions == NULL)
17016 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17018 transition_closure_free);
17020 va_start (var_args, pspec);
17022 clos = g_hash_table_lookup (info->transitions, pspec->name);
17025 ClutterInterval *interval;
17026 GValue initial = G_VALUE_INIT;
17027 GValue final = G_VALUE_INIT;
17031 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17033 G_VALUE_COLLECT_INIT (&initial, ptype,
17038 g_critical ("%s: %s", G_STRLOC, error);
17043 G_VALUE_COLLECT_INIT (&final, ptype,
17049 g_critical ("%s: %s", G_STRLOC, error);
17050 g_value_unset (&initial);
17055 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17057 g_value_unset (&initial);
17058 g_value_unset (&final);
17060 res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17063 clutter_transition_set_interval (res, interval);
17064 clutter_transition_set_remove_on_complete (res, TRUE);
17066 clutter_actor_add_transition (actor, pspec->name, res);
17069 res = clos->transition;
17073 clutter_actor_restore_easing_state (actor);
17081 * clutter_actor_add_transition:
17082 * @self: a #ClutterActor
17083 * @name: the name of the transition to add
17084 * @transition: the #ClutterTransition to add
17086 * Adds a @transition to the #ClutterActor's list of animations.
17088 * The @name string is a per-actor unique identifier of the @transition: only
17089 * one #ClutterTransition can be associated to the specified @name.
17091 * The @transition will be given the easing duration, mode, and delay
17092 * associated to the actor's current easing state; it is possible to modify
17093 * these values after calling clutter_actor_add_transition().
17095 * This function is usually called implicitly when modifying an animatable
17101 clutter_actor_add_transition (ClutterActor *self,
17103 ClutterTransition *transition)
17105 ClutterTimeline *timeline;
17106 TransitionClosure *clos;
17107 ClutterAnimationInfo *info;
17109 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17110 g_return_if_fail (name != NULL);
17111 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17113 info = _clutter_actor_get_animation_info (self);
17115 if (info->cur_state == NULL)
17117 g_warning ("No easing state is defined for the actor '%s'; you "
17118 "must call clutter_actor_save_easing_state() before "
17119 "calling clutter_actor_add_transition().",
17120 _clutter_actor_get_debug_name (self));
17124 if (info->transitions == NULL)
17125 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17127 transition_closure_free);
17129 if (g_hash_table_lookup (info->transitions, name) != NULL)
17131 g_warning ("A transition with name '%s' already exists for "
17134 _clutter_actor_get_debug_name (self));
17138 timeline = CLUTTER_TIMELINE (transition);
17140 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17141 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17142 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17144 clos = g_slice_new (TransitionClosure);
17145 clos->actor = self;
17146 clos->transition = transition;
17147 clos->name = g_strdup (name);
17148 clos->completed_id = g_signal_connect (timeline, "completed",
17149 G_CALLBACK (on_transition_completed),
17152 g_hash_table_insert (info->transitions, clos->name, clos);
17156 * clutter_actor_remove_transition:
17157 * @self: a #ClutterActor
17158 * @name: the name of the transition to remove
17160 * Removes the transition stored inside a #ClutterActor using @name
17166 clutter_actor_remove_transition (ClutterActor *self,
17169 const ClutterAnimationInfo *info;
17171 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17172 g_return_if_fail (name != NULL);
17174 info = _clutter_actor_get_animation_info_or_defaults (self);
17176 if (info->transitions == NULL)
17179 g_hash_table_remove (info->transitions, name);
17183 * clutter_actor_remove_all_transitions:
17184 * @self: a #ClutterActor
17186 * Removes all transitions associated to @self.
17191 clutter_actor_remove_all_transitions (ClutterActor *self)
17193 const ClutterAnimationInfo *info;
17195 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17197 info = _clutter_actor_get_animation_info_or_defaults (self);
17198 if (info->transitions == NULL)
17201 g_hash_table_remove_all (info->transitions);
17205 * clutter_actor_set_easing_duration:
17206 * @self: a #ClutterActor
17207 * @msecs: the duration of the easing, or %NULL
17209 * Sets the duration of the tweening for animatable properties
17210 * of @self for the current easing state.
17212 * Calling this function will implicitly call
17213 * clutter_actor_save_easing_state() if no previous call to
17214 * that function was made.
17219 clutter_actor_set_easing_duration (ClutterActor *self,
17222 ClutterAnimationInfo *info;
17224 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17226 info = _clutter_actor_get_animation_info (self);
17228 if (info->states == NULL)
17229 clutter_actor_save_easing_state (self);
17231 if (info->cur_state->easing_duration != msecs)
17232 info->cur_state->easing_duration = msecs;
17236 * clutter_actor_get_easing_duration:
17237 * @self: a #ClutterActor
17239 * Retrieves the duration of the tweening for animatable
17240 * properties of @self for the current easing state.
17242 * Return value: the duration of the tweening, in milliseconds
17247 clutter_actor_get_easing_duration (ClutterActor *self)
17249 const ClutterAnimationInfo *info;
17251 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17253 info = _clutter_actor_get_animation_info_or_defaults (self);
17255 if (info->cur_state != NULL)
17256 return info->cur_state->easing_duration;
17262 * clutter_actor_set_easing_mode:
17263 * @self: a #ClutterActor
17264 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17266 * Sets the easing mode for the tweening of animatable properties
17269 * Calling this function will implicitly call
17270 * clutter_actor_save_easing_state() if no previous calls to
17271 * that function were made.
17276 clutter_actor_set_easing_mode (ClutterActor *self,
17277 ClutterAnimationMode mode)
17279 ClutterAnimationInfo *info;
17281 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17282 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17283 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17285 info = _clutter_actor_get_animation_info (self);
17287 if (info->states == NULL)
17288 clutter_actor_save_easing_state (self);
17290 if (info->cur_state->easing_mode != mode)
17291 info->cur_state->easing_mode = mode;
17295 * clutter_actor_get_easing_mode:
17296 * @self: a #ClutterActor
17298 * Retrieves the easing mode for the tweening of animatable properties
17299 * of @self for the current easing state.
17301 * Return value: an easing mode
17305 ClutterAnimationMode
17306 clutter_actor_get_easing_mode (ClutterActor *self)
17308 const ClutterAnimationInfo *info;
17310 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17312 info = _clutter_actor_get_animation_info_or_defaults (self);
17314 if (info->cur_state != NULL)
17315 return info->cur_state->easing_mode;
17317 return CLUTTER_EASE_OUT_CUBIC;
17321 * clutter_actor_set_easing_delay:
17322 * @self: a #ClutterActor
17323 * @msecs: the delay before the start of the tweening, in milliseconds
17325 * Sets the delay that should be applied before tweening animatable
17328 * Calling this function will implicitly call
17329 * clutter_actor_save_easing_state() if no previous calls to
17330 * that function were made.
17335 clutter_actor_set_easing_delay (ClutterActor *self,
17338 ClutterAnimationInfo *info;
17340 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17342 info = _clutter_actor_get_animation_info (self);
17344 if (info->states == NULL)
17345 clutter_actor_save_easing_state (self);
17347 if (info->cur_state->easing_delay != msecs)
17348 info->cur_state->easing_delay = msecs;
17352 * clutter_actor_get_easing_delay:
17353 * @self: a #ClutterActor
17355 * Retrieves the delay that should be applied when tweening animatable
17358 * Return value: a delay, in milliseconds
17363 clutter_actor_get_easing_delay (ClutterActor *self)
17365 const ClutterAnimationInfo *info;
17367 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17369 info = _clutter_actor_get_animation_info_or_defaults (self);
17371 if (info->cur_state != NULL)
17372 return info->cur_state->easing_delay;
17378 * clutter_actor_get_transition:
17379 * @self: a #ClutterActor
17380 * @name: the name of the transition
17382 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17383 * transition @name.
17385 * Transitions created for animatable properties use the name of the
17386 * property itself, for instance the code below:
17389 * clutter_actor_set_easing_duration (actor, 1000);
17390 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17392 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17393 * g_signal_connect (transition, "completed",
17394 * G_CALLBACK (on_transition_complete),
17398 * will call the <function>on_transition_complete</function> callback when
17399 * the transition is complete.
17401 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17402 * was found to match the passed name; the returned instance is owned
17403 * by Clutter and it should not be freed
17407 ClutterTransition *
17408 clutter_actor_get_transition (ClutterActor *self,
17411 TransitionClosure *clos;
17412 const ClutterAnimationInfo *info;
17414 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17415 g_return_val_if_fail (name != NULL, NULL);
17417 info = _clutter_actor_get_animation_info_or_defaults (self);
17419 if (info->transitions == NULL)
17422 clos = g_hash_table_lookup (info->transitions, name);
17426 return clos->transition;
17430 * clutter_actor_save_easing_state:
17431 * @self: a #ClutterActor
17433 * Saves the current easing state for animatable properties, and creates
17434 * a new state with the default values for easing mode and duration.
17439 clutter_actor_save_easing_state (ClutterActor *self)
17441 ClutterAnimationInfo *info;
17444 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17446 info = _clutter_actor_get_animation_info (self);
17448 if (info->states == NULL)
17449 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17451 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17452 new_state.easing_duration = 250;
17453 new_state.easing_delay = 0;
17455 g_array_append_val (info->states, new_state);
17457 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17461 * clutter_actor_restore_easing_state:
17462 * @self: a #ClutterActor
17464 * Restores the easing state as it was prior to a call to
17465 * clutter_actor_save_easing_state().
17470 clutter_actor_restore_easing_state (ClutterActor *self)
17472 ClutterAnimationInfo *info;
17474 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17476 info = _clutter_actor_get_animation_info (self);
17478 if (info->states == NULL)
17480 g_critical ("The function clutter_actor_restore_easing_state() has "
17481 "called without a previous call to "
17482 "clutter_actor_save_easing_state().");
17486 g_array_remove_index (info->states, info->states->len - 1);
17487 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17491 * clutter_actor_set_content:
17492 * @self: a #ClutterActor
17493 * @content: (allow-none): a #ClutterContent, or %NULL
17495 * Sets the contents of a #ClutterActor.
17500 clutter_actor_set_content (ClutterActor *self,
17501 ClutterContent *content)
17503 ClutterActorPrivate *priv;
17505 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17506 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17510 if (priv->content != NULL)
17512 _clutter_content_detached (priv->content, self);
17513 g_object_unref (priv->content);
17516 priv->content = content;
17518 if (priv->content != NULL)
17520 g_object_ref (priv->content);
17521 _clutter_content_attached (priv->content, self);
17524 /* given that the content is always painted within the allocation,
17525 * we only need to queue a redraw here
17527 clutter_actor_queue_redraw (self);
17529 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17531 /* if the content gravity is not resize-fill, and the new content has a
17532 * different preferred size than the previous one, then the content box
17533 * may have been changed. since we compute that lazily, we just notify
17534 * here, and let whomever watches :content-box do whatever they need to
17537 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17538 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17542 * clutter_actor_get_content:
17543 * @self: a #ClutterActor
17545 * Retrieves the contents of @self.
17547 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17548 * or %NULL if none was set
17553 clutter_actor_get_content (ClutterActor *self)
17555 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17557 return self->priv->content;
17561 * clutter_actor_set_content_gravity:
17562 * @self: a #ClutterActor
17563 * @gravity: the #ClutterContentGravity
17565 * Sets the gravity of the #ClutterContent used by @self.
17567 * See the description of the #ClutterActor:content-gravity property for
17568 * more information.
17573 clutter_actor_set_content_gravity (ClutterActor *self,
17574 ClutterContentGravity gravity)
17576 ClutterActorPrivate *priv;
17578 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17582 if (priv->content_gravity == gravity)
17585 priv->content_gravity = gravity;
17587 clutter_actor_queue_redraw (self);
17589 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17590 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17594 * clutter_actor_get_content_gravity:
17595 * @self: a #ClutterActor
17597 * Retrieves the content gravity as set using
17598 * clutter_actor_get_content_gravity().
17600 * Return value: the content gravity
17604 ClutterContentGravity
17605 clutter_actor_get_content_gravity (ClutterActor *self)
17607 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17608 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17610 return self->priv->content_gravity;
17614 * clutter_actor_get_content_box:
17615 * @self: a #ClutterActor
17616 * @box: (out caller-allocates): the return location for the bounding
17617 * box for the #ClutterContent
17619 * Retrieves the bounding box for the #ClutterContent of @self.
17621 * If no #ClutterContent is set for @self, or if @self has not been
17622 * allocated yet, then the result is undefined.
17624 * The content box is guaranteed to be, at most, as big as the allocation
17625 * of the #ClutterActor.
17627 * If the #ClutterContent used by the actor has a preferred size, then
17628 * it is possible to modify the content box by using the
17629 * #ClutterActor:content-gravity property.
17634 clutter_actor_get_content_box (ClutterActor *self,
17635 ClutterActorBox *box)
17637 ClutterActorPrivate *priv;
17638 gfloat content_w, content_h;
17639 gfloat alloc_w, alloc_h;
17641 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17642 g_return_if_fail (box != NULL);
17646 if (!clutter_actor_has_allocation (self))
17651 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17652 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17654 if (priv->content == NULL)
17657 /* no need to do any more work */
17658 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17661 /* if the content does not have a preferred size then there is
17662 * no point in computing the content box
17664 if (!clutter_content_get_preferred_size (priv->content,
17669 clutter_actor_box_get_size (&priv->allocation, &alloc_w, &alloc_h);
17671 switch (priv->content_gravity)
17673 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17674 box->x2 = box->x1 + MIN (content_w, alloc_w);
17675 box->y2 = box->y1 + MIN (content_h, alloc_h);
17678 case CLUTTER_CONTENT_GRAVITY_TOP:
17679 if (alloc_w > content_w)
17681 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17682 box->x2 = box->x1 + content_w;
17684 box->y2 = box->y1 + MIN (content_h, alloc_h);
17687 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17688 if (alloc_w > content_w)
17690 box->x1 += (alloc_w - content_w);
17691 box->x2 = box->x1 + content_w;
17693 box->y2 = box->y1 + MIN (content_h, alloc_h);
17696 case CLUTTER_CONTENT_GRAVITY_LEFT:
17697 box->x2 = box->x1 + MIN (content_w, alloc_w);
17698 if (alloc_h > content_h)
17700 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17701 box->y2 = box->y1 + content_h;
17705 case CLUTTER_CONTENT_GRAVITY_CENTER:
17706 if (alloc_w > content_w)
17708 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17709 box->x2 = box->x1 + content_w;
17711 if (alloc_h > content_h)
17713 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17714 box->y2 = box->y1 + content_h;
17718 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17719 if (alloc_w > content_w)
17721 box->x1 += (alloc_w - content_w);
17722 box->x2 = box->x1 + content_w;
17724 if (alloc_h > content_h)
17726 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17727 box->y2 = box->y1 + content_h;
17731 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17732 box->x2 = box->x1 + MIN (content_w, alloc_w);
17733 if (alloc_h > content_h)
17735 box->y1 += (alloc_h - content_h);
17736 box->y2 = box->y1 + content_h;
17740 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17741 if (alloc_w > content_w)
17743 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17744 box->x2 = box->x1 + content_w;
17746 if (alloc_h > content_h)
17748 box->y1 += (alloc_h - content_h);
17749 box->y2 = box->y1 + content_h;
17753 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17754 if (alloc_w > content_w)
17756 box->x1 += (alloc_w - content_w);
17757 box->x2 = box->x1 + content_w;
17759 if (alloc_h > content_h)
17761 box->y1 += (alloc_h - content_h);
17762 box->y2 = box->y1 + content_h;
17766 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17767 g_assert_not_reached ();
17770 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17771 if (content_w >= content_h && content_h > 0)
17773 double ratio = content_w / content_h;
17775 box->x2 = box->x1 + alloc_w;
17777 box->y1 += ceilf ((alloc_h - (alloc_h / ratio)) / 2.0);
17778 box->y2 = box->y1 + (alloc_h / ratio);
17780 else if (content_h > content_w && content_w > 0)
17782 double ratio = content_h / content_w;
17784 box->x1 += ceilf ((alloc_w - (alloc_w / ratio)) / 2.0);
17785 box->x2 = box->x2 + (alloc_w / ratio);
17787 box->y2 = box->x1 + alloc_h;
17794 * clutter_actor_set_content_scaling_filters:
17795 * @self: a #ClutterActor
17796 * @min_filter: FIXME
17797 * @mag_filter: FIXME
17804 clutter_actor_set_content_scaling_filters (ClutterActor *self,
17805 ClutterScalingFilter min_filter,
17806 ClutterScalingFilter mag_filter)
17808 ClutterActorPrivate *priv;
17812 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17815 obj = G_OBJECT (self);
17817 g_object_freeze_notify (obj);
17821 if (priv->min_filter != min_filter)
17823 priv->min_filter = min_filter;
17826 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17829 if (priv->mag_filter != mag_filter)
17831 priv->mag_filter = mag_filter;
17834 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17838 clutter_actor_queue_redraw (self);
17840 g_object_thaw_notify (obj);
17844 * clutter_actor_get_content_scaling_filters:
17845 * @self: a #ClutterActor
17846 * @min_filter: (out): FIXME
17847 * @mag_filter: (out): FIXME
17854 clutter_actor_get_content_scaling_filters (ClutterActor *self,
17855 ClutterScalingFilter *min_filter,
17856 ClutterScalingFilter *mag_filter)
17858 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17860 if (min_filter != NULL)
17861 *min_filter = self->priv->min_filter;
17863 if (mag_filter != NULL)
17864 *mag_filter = self->priv->mag_filter;