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: The basic element of the scene graph
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_TRILINEAR,
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 width, height;
2062 x = priv->allocation.x1;
2063 y = priv->allocation.y1;
2064 width = priv->allocation.x2 - priv->allocation.x1;
2065 height = 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 (width != (old->x2 - old->x1))
2074 g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2076 if (height != (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 ||
2133 x2_changed || y2_changed ||
2136 CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2137 _clutter_actor_get_debug_name (self));
2139 priv->transform_valid = FALSE;
2141 g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2143 /* if the allocation changes, so does the content box */
2144 if (priv->content != NULL)
2145 g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2152 clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2154 g_object_thaw_notify (obj);
2159 static void clutter_actor_real_allocate (ClutterActor *self,
2160 const ClutterActorBox *box,
2161 ClutterAllocationFlags flags);
2164 clutter_actor_maybe_layout_children (ClutterActor *self,
2165 const ClutterActorBox *allocation,
2166 ClutterAllocationFlags flags)
2168 ClutterActorPrivate *priv = self->priv;
2170 /* this is going to be a bit hard to follow, so let's put an explanation
2173 * we want ClutterActor to have a default layout manager if the actor was
2174 * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2176 * we also want any subclass of ClutterActor that does not override the
2177 * ::allocate() virtual function to delegate to a layout manager.
2179 * finally, we want to allow people subclassing ClutterActor and overriding
2180 * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2182 * on the other hand, we want existing actor subclasses overriding the
2183 * ::allocate() virtual function and chaining up to the parent's
2184 * implementation to continue working without allocating their children
2185 * twice, or without entering an allocation loop.
2187 * for the first two points, we check if the class of the actor is
2188 * overridding the ::allocate() virtual function; if it isn't, then we
2189 * follow through with checking whether we have children and a layout
2190 * manager, and eventually calling clutter_layout_manager_allocate().
2192 * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2193 * allocation flags that we got passed, and if it is present, we continue
2194 * with the check above.
2196 * if neither of these two checks yields a positive result, we just
2197 * assume that the ::allocate() virtual function that resulted in this
2198 * function being called will also allocate the children of the actor.
2201 if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2204 if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2210 if (priv->n_children != 0 &&
2211 priv->layout_manager != NULL)
2213 ClutterContainer *container = CLUTTER_CONTAINER (self);
2214 ClutterAllocationFlags children_flags;
2215 ClutterActorBox children_box;
2217 /* normalize the box passed to the layout manager */
2218 children_box.x1 = children_box.y1 = 0.f;
2219 children_box.x2 = (allocation->x2 - allocation->x1);
2220 children_box.y2 = (allocation->y2 - allocation->y1);
2222 /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2223 * the actor's children, since it refers only to the current
2224 * actor's allocation.
2226 children_flags = flags;
2227 children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2229 CLUTTER_NOTE (LAYOUT,
2230 "Allocating %d children of %s "
2231 "at { %.2f, %.2f - %.2f x %.2f } "
2234 _clutter_actor_get_debug_name (self),
2237 (allocation->x2 - allocation->x1),
2238 (allocation->y2 - allocation->y1),
2239 G_OBJECT_TYPE_NAME (priv->layout_manager));
2241 clutter_layout_manager_allocate (priv->layout_manager,
2249 clutter_actor_real_allocate (ClutterActor *self,
2250 const ClutterActorBox *box,
2251 ClutterAllocationFlags flags)
2253 ClutterActorPrivate *priv = self->priv;
2256 g_object_freeze_notify (G_OBJECT (self));
2258 changed = clutter_actor_set_allocation_internal (self, box, flags);
2260 /* we allocate our children before we notify changes in our geometry,
2261 * so that people connecting to properties will be able to get valid
2262 * data out of the sub-tree of the scene graph that has this actor at
2265 clutter_actor_maybe_layout_children (self, box, flags);
2269 ClutterActorBox signal_box = priv->allocation;
2270 ClutterAllocationFlags signal_flags = priv->allocation_flags;
2272 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2277 g_object_thaw_notify (G_OBJECT (self));
2281 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2282 ClutterActor *origin)
2284 /* no point in queuing a redraw on a destroyed actor */
2285 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2288 /* NB: We can't bail out early here if the actor is hidden in case
2289 * the actor bas been cloned. In this case the clone will need to
2290 * receive the signal so it can queue its own redraw.
2293 /* calls klass->queue_redraw in default handler */
2294 g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2298 clutter_actor_real_queue_redraw (ClutterActor *self,
2299 ClutterActor *origin)
2301 ClutterActor *parent;
2303 CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2304 _clutter_actor_get_debug_name (self),
2305 origin != NULL ? _clutter_actor_get_debug_name (origin)
2308 /* no point in queuing a redraw on a destroyed actor */
2309 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2312 /* If the queue redraw is coming from a child then the actor has
2313 become dirty and any queued effect is no longer valid */
2316 self->priv->is_dirty = TRUE;
2317 self->priv->effect_to_redraw = NULL;
2320 /* If the actor isn't visible, we still had to emit the signal
2321 * to allow for a ClutterClone, but the appearance of the parent
2322 * won't change so we don't have to propagate up the hierarchy.
2324 if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2327 /* Although we could determine here that a full stage redraw
2328 * has already been queued and immediately bail out, we actually
2329 * guarantee that we will propagate a queue-redraw signal to our
2330 * parent at least once so that it's possible to implement a
2331 * container that tracks which of its children have queued a
2334 if (self->priv->propagated_one_redraw)
2336 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2337 if (stage != NULL &&
2338 _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2342 self->priv->propagated_one_redraw = TRUE;
2344 /* notify parents, if they are all visible eventually we'll
2345 * queue redraw on the stage, which queues the redraw idle.
2347 parent = clutter_actor_get_parent (self);
2350 /* this will go up recursively */
2351 _clutter_actor_signal_queue_redraw (parent, origin);
2356 clutter_actor_real_queue_relayout (ClutterActor *self)
2358 ClutterActorPrivate *priv = self->priv;
2360 /* no point in queueing a redraw on a destroyed actor */
2361 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2364 priv->needs_width_request = TRUE;
2365 priv->needs_height_request = TRUE;
2366 priv->needs_allocation = TRUE;
2368 /* reset the cached size requests */
2369 memset (priv->width_requests, 0,
2370 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2371 memset (priv->height_requests, 0,
2372 N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2374 /* We need to go all the way up the hierarchy */
2375 if (priv->parent != NULL)
2376 _clutter_actor_queue_only_relayout (priv->parent);
2380 * clutter_actor_apply_relative_transform_to_point:
2381 * @self: A #ClutterActor
2382 * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2383 * default #ClutterStage
2384 * @point: A point as #ClutterVertex
2385 * @vertex: (out caller-allocates): The translated #ClutterVertex
2387 * Transforms @point in coordinates relative to the actor into
2388 * ancestor-relative coordinates using the relevant transform
2389 * stack (i.e. scale, rotation, etc).
2391 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2392 * this case, the coordinates returned will be the coordinates on
2393 * the stage before the projection is applied. This is different from
2394 * the behaviour of clutter_actor_apply_transform_to_point().
2399 clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
2400 ClutterActor *ancestor,
2401 const ClutterVertex *point,
2402 ClutterVertex *vertex)
2407 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2408 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2409 g_return_if_fail (point != NULL);
2410 g_return_if_fail (vertex != NULL);
2415 if (ancestor == NULL)
2416 ancestor = _clutter_actor_get_stage_internal (self);
2418 if (ancestor == NULL)
2424 _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2425 cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2429 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2430 const ClutterVertex *vertices_in,
2431 ClutterVertex *vertices_out,
2434 ClutterActor *stage;
2435 CoglMatrix modelview;
2436 CoglMatrix projection;
2439 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2441 stage = _clutter_actor_get_stage_internal (self);
2443 /* We really can't do anything meaningful in this case so don't try
2444 * to do any transform */
2448 /* Note: we pass NULL as the ancestor because we don't just want the modelview
2449 * that gets us to stage coordinates, we want to go all the way to eye
2451 _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2453 /* Fetch the projection and viewport */
2454 _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2455 _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2461 _clutter_util_fully_transform_vertices (&modelview,
2472 * clutter_actor_apply_transform_to_point:
2473 * @self: A #ClutterActor
2474 * @point: A point as #ClutterVertex
2475 * @vertex: (out caller-allocates): The translated #ClutterVertex
2477 * Transforms @point in coordinates relative to the actor
2478 * into screen-relative coordinates with the current actor
2479 * transformation (i.e. scale, rotation, etc)
2484 clutter_actor_apply_transform_to_point (ClutterActor *self,
2485 const ClutterVertex *point,
2486 ClutterVertex *vertex)
2488 g_return_if_fail (point != NULL);
2489 g_return_if_fail (vertex != NULL);
2490 _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2494 * _clutter_actor_get_relative_transformation_matrix:
2495 * @self: The actor whose coordinate space you want to transform from.
2496 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2497 * or %NULL if you want to transform all the way to eye coordinates.
2498 * @matrix: A #CoglMatrix to store the transformation
2500 * This gets a transformation @matrix that will transform coordinates from the
2501 * coordinate space of @self into the coordinate space of @ancestor.
2503 * For example if you need a matrix that can transform the local actor
2504 * coordinates of @self into stage coordinates you would pass the actor's stage
2505 * pointer as the @ancestor.
2507 * If you pass %NULL then the transformation will take you all the way through
2508 * to eye coordinates. This can be useful if you want to extract the entire
2509 * modelview transform that Clutter applies before applying the projection
2510 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2511 * using cogl_set_modelview_matrix() for example then you would want a matrix
2512 * that transforms into eye coordinates.
2514 * <note><para>This function explicitly initializes the given @matrix. If you just
2515 * want clutter to multiply a relative transformation with an existing matrix
2516 * you can use clutter_actor_apply_relative_transformation_matrix()
2517 * instead.</para></note>
2520 /* XXX: We should consider caching the stage relative modelview along with
2521 * the actor itself */
2523 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2524 ClutterActor *ancestor,
2527 cogl_matrix_init_identity (matrix);
2529 _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2532 /* Project the given @box into stage window coordinates, writing the
2533 * transformed vertices to @verts[]. */
2535 _clutter_actor_transform_and_project_box (ClutterActor *self,
2536 const ClutterActorBox *box,
2537 ClutterVertex verts[])
2539 ClutterVertex box_vertices[4];
2541 box_vertices[0].x = box->x1;
2542 box_vertices[0].y = box->y1;
2543 box_vertices[0].z = 0;
2544 box_vertices[1].x = box->x2;
2545 box_vertices[1].y = box->y1;
2546 box_vertices[1].z = 0;
2547 box_vertices[2].x = box->x1;
2548 box_vertices[2].y = box->y2;
2549 box_vertices[2].z = 0;
2550 box_vertices[3].x = box->x2;
2551 box_vertices[3].y = box->y2;
2552 box_vertices[3].z = 0;
2555 _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2559 * clutter_actor_get_allocation_vertices:
2560 * @self: A #ClutterActor
2561 * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2562 * against, or %NULL to use the #ClutterStage
2563 * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2564 * location for an array of 4 #ClutterVertex in which to store the result
2566 * Calculates the transformed coordinates of the four corners of the
2567 * actor in the plane of @ancestor. The returned vertices relate to
2568 * the #ClutterActorBox coordinates as follows:
2570 * <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2571 * <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2572 * <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2573 * <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2576 * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2577 * this case, the coordinates returned will be the coordinates on
2578 * the stage before the projection is applied. This is different from
2579 * the behaviour of clutter_actor_get_abs_allocation_vertices().
2584 clutter_actor_get_allocation_vertices (ClutterActor *self,
2585 ClutterActor *ancestor,
2586 ClutterVertex verts[])
2588 ClutterActorPrivate *priv;
2589 ClutterActorBox box;
2590 ClutterVertex vertices[4];
2591 CoglMatrix modelview;
2593 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2594 g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2596 if (ancestor == NULL)
2597 ancestor = _clutter_actor_get_stage_internal (self);
2599 /* Fallback to a NOP transform if the actor isn't parented under a
2601 if (ancestor == NULL)
2606 /* if the actor needs to be allocated we force a relayout, so that
2607 * we will have valid values to use in the transformations */
2608 if (priv->needs_allocation)
2610 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2612 _clutter_stage_maybe_relayout (stage);
2615 box.x1 = box.y1 = 0;
2616 /* The result isn't really meaningful in this case but at
2617 * least try to do something *vaguely* reasonable... */
2618 clutter_actor_get_size (self, &box.x2, &box.y2);
2622 clutter_actor_get_allocation_box (self, &box);
2624 vertices[0].x = box.x1;
2625 vertices[0].y = box.y1;
2627 vertices[1].x = box.x2;
2628 vertices[1].y = box.y1;
2630 vertices[2].x = box.x1;
2631 vertices[2].y = box.y2;
2633 vertices[3].x = box.x2;
2634 vertices[3].y = box.y2;
2637 _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2640 cogl_matrix_transform_points (&modelview,
2642 sizeof (ClutterVertex),
2644 sizeof (ClutterVertex),
2650 * clutter_actor_get_abs_allocation_vertices:
2651 * @self: A #ClutterActor
2652 * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2653 * of 4 #ClutterVertex where to store the result.
2655 * Calculates the transformed screen coordinates of the four corners of
2656 * the actor; the returned vertices relate to the #ClutterActorBox
2657 * coordinates as follows:
2659 * <listitem><para>v[0] contains (x1, y1)</para></listitem>
2660 * <listitem><para>v[1] contains (x2, y1)</para></listitem>
2661 * <listitem><para>v[2] contains (x1, y2)</para></listitem>
2662 * <listitem><para>v[3] contains (x2, y2)</para></listitem>
2668 clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
2669 ClutterVertex verts[])
2671 ClutterActorPrivate *priv;
2672 ClutterActorBox actor_space_allocation;
2674 g_return_if_fail (CLUTTER_IS_ACTOR (self));
2678 /* if the actor needs to be allocated we force a relayout, so that
2679 * the actor allocation box will be valid for
2680 * _clutter_actor_transform_and_project_box()
2682 if (priv->needs_allocation)
2684 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2685 /* There's nothing meaningful we can do now */
2689 _clutter_stage_maybe_relayout (stage);
2692 /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2693 * own coordinate space... */
2694 actor_space_allocation.x1 = 0;
2695 actor_space_allocation.y1 = 0;
2696 actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2697 actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2698 _clutter_actor_transform_and_project_box (self,
2699 &actor_space_allocation,
2704 clutter_actor_real_apply_transform (ClutterActor *self,
2707 ClutterActorPrivate *priv = self->priv;
2709 if (!priv->transform_valid)
2711 CoglMatrix *transform = &priv->transform;
2712 const ClutterTransformInfo *info;
2714 info = _clutter_actor_get_transform_info_or_defaults (self);
2716 cogl_matrix_init_identity (transform);
2718 cogl_matrix_translate (transform,
2719 priv->allocation.x1,
2720 priv->allocation.y1,
2724 cogl_matrix_translate (transform, 0, 0, info->depth);
2727 * because the rotation involves translations, we must scale
2728 * before applying the rotations (if we apply the scale after
2729 * the rotations, the translations included in the rotation are
2730 * not scaled and so the entire object will move on the screen
2731 * as a result of rotating it).
2733 if (info->scale_x != 1.0 || info->scale_y != 1.0)
2735 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2736 &info->scale_center,
2737 cogl_matrix_scale (transform,
2744 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2746 cogl_matrix_rotate (transform,
2751 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2753 cogl_matrix_rotate (transform,
2758 TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2760 cogl_matrix_rotate (transform,
2764 if (!clutter_anchor_coord_is_zero (&info->anchor))
2768 clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2769 cogl_matrix_translate (transform, -x, -y, -z);
2772 priv->transform_valid = TRUE;
2775 cogl_matrix_multiply (matrix, matrix, &priv->transform);
2778 /* Applies the transforms associated with this actor to the given
2781 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2784 CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2788 * clutter_actor_apply_relative_transformation_matrix:
2789 * @self: The actor whose coordinate space you want to transform from.
2790 * @ancestor: The ancestor actor whose coordinate space you want to transform too
2791 * or %NULL if you want to transform all the way to eye coordinates.
2792 * @matrix: A #CoglMatrix to apply the transformation too.
2794 * This multiplies a transform with @matrix that will transform coordinates
2795 * from the coordinate space of @self into the coordinate space of @ancestor.
2797 * For example if you need a matrix that can transform the local actor
2798 * coordinates of @self into stage coordinates you would pass the actor's stage
2799 * pointer as the @ancestor.
2801 * If you pass %NULL then the transformation will take you all the way through
2802 * to eye coordinates. This can be useful if you want to extract the entire
2803 * modelview transform that Clutter applies before applying the projection
2804 * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2805 * using cogl_set_modelview_matrix() for example then you would want a matrix
2806 * that transforms into eye coordinates.
2808 * <note>This function doesn't initialize the given @matrix, it simply
2809 * multiplies the requested transformation matrix with the existing contents of
2810 * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2811 * before calling this function, or you can use
2812 * clutter_actor_get_relative_transformation_matrix() instead.</note>
2815 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2816 ClutterActor *ancestor,
2819 ClutterActor *parent;
2821 /* Note we terminate before ever calling stage->apply_transform()
2822 * since that would conceptually be relative to the underlying
2823 * window OpenGL coordinates so we'd need a special @ancestor
2824 * value to represent the fake parent of the stage. */
2825 if (self == ancestor)
2828 parent = clutter_actor_get_parent (self);
2831 _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2834 _clutter_actor_apply_modelview_transform (self, matrix);
2838 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2839 ClutterPaintVolume *pv,
2841 const CoglColor *color)
2843 static CoglPipeline *outline = NULL;
2844 CoglPrimitive *prim;
2845 ClutterVertex line_ends[12 * 2];
2848 clutter_backend_get_cogl_context (clutter_get_default_backend ());
2849 /* XXX: at some point we'll query this from the stage but we can't
2850 * do that until the osx backend uses Cogl natively. */
2851 CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2853 if (outline == NULL)
2854 outline = cogl_pipeline_new (ctx);
2856 _clutter_paint_volume_complete (pv);
2858 n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2861 line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2862 line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2863 line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2864 line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2869 line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2870 line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2871 line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2872 line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2874 /* Lines connecting front face to back face */
2875 line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2876 line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2877 line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
2878 line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
2881 prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
2883 (CoglVertexP3 *)line_ends);
2885 cogl_pipeline_set_color (outline, color);
2886 cogl_framebuffer_draw_primitive (fb, outline, prim);
2887 cogl_object_unref (prim);
2891 PangoLayout *layout;
2892 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2893 pango_layout_set_text (layout, label, -1);
2894 cogl_pango_render_layout (layout,
2899 g_object_unref (layout);
2904 _clutter_actor_draw_paint_volume (ClutterActor *self)
2906 ClutterPaintVolume *pv;
2909 pv = _clutter_actor_get_paint_volume_mutable (self);
2912 gfloat width, height;
2913 ClutterPaintVolume fake_pv;
2915 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2916 _clutter_paint_volume_init_static (&fake_pv, stage);
2918 clutter_actor_get_size (self, &width, &height);
2919 clutter_paint_volume_set_width (&fake_pv, width);
2920 clutter_paint_volume_set_height (&fake_pv, height);
2922 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2923 _clutter_actor_draw_paint_volume_full (self, &fake_pv,
2924 _clutter_actor_get_debug_name (self),
2927 clutter_paint_volume_free (&fake_pv);
2931 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2932 _clutter_actor_draw_paint_volume_full (self, pv,
2933 _clutter_actor_get_debug_name (self),
2939 _clutter_actor_paint_cull_result (ClutterActor *self,
2941 ClutterCullResult result)
2943 ClutterPaintVolume *pv;
2948 if (result == CLUTTER_CULL_RESULT_IN)
2949 cogl_color_init_from_4f (&color, 0, 1, 0, 1);
2950 else if (result == CLUTTER_CULL_RESULT_OUT)
2951 cogl_color_init_from_4f (&color, 0, 0, 1, 1);
2953 cogl_color_init_from_4f (&color, 0, 1, 1, 1);
2956 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2958 if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
2959 _clutter_actor_draw_paint_volume_full (self, pv,
2960 _clutter_actor_get_debug_name (self),
2964 PangoLayout *layout;
2966 g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
2967 cogl_color_init_from_4f (&color, 1, 1, 1, 1);
2968 cogl_set_source_color (&color);
2970 layout = pango_layout_new (clutter_actor_get_pango_context (self));
2971 pango_layout_set_text (layout, label, -1);
2972 cogl_pango_render_layout (layout,
2978 g_object_unref (layout);
2982 static int clone_paint_level = 0;
2985 _clutter_actor_push_clone_paint (void)
2987 clone_paint_level++;
2991 _clutter_actor_pop_clone_paint (void)
2993 clone_paint_level--;
2997 in_clone_paint (void)
2999 return clone_paint_level > 0;
3002 /* Returns TRUE if the actor can be ignored */
3003 /* FIXME: we should return a ClutterCullResult, and
3004 * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3005 * means there's no point in trying to cull descendants of the current
3008 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3010 ClutterActorPrivate *priv = self->priv;
3011 ClutterActor *stage;
3012 const ClutterPlane *stage_clip;
3014 if (!priv->last_paint_volume_valid)
3016 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3017 "->last_paint_volume_valid == FALSE",
3018 _clutter_actor_get_debug_name (self));
3022 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3025 stage = _clutter_actor_get_stage_internal (self);
3026 stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3027 if (G_UNLIKELY (!stage_clip))
3029 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3030 "No stage clip set",
3031 _clutter_actor_get_debug_name (self));
3035 if (cogl_get_draw_framebuffer () !=
3036 _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3038 CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3039 "Current framebuffer doesn't correspond to stage",
3040 _clutter_actor_get_debug_name (self));
3045 _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3050 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3052 ClutterActorPrivate *priv = self->priv;
3053 const ClutterPaintVolume *pv;
3055 if (priv->last_paint_volume_valid)
3057 clutter_paint_volume_free (&priv->last_paint_volume);
3058 priv->last_paint_volume_valid = FALSE;
3061 pv = clutter_actor_get_paint_volume (self);
3064 CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3065 "Actor failed to report a paint volume",
3066 _clutter_actor_get_debug_name (self));
3070 _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3072 _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3073 NULL); /* eye coordinates */
3075 priv->last_paint_volume_valid = TRUE;
3078 static inline gboolean
3079 actor_has_shader_data (ClutterActor *self)
3081 return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3085 _clutter_actor_get_pick_id (ClutterActor *self)
3087 if (self->priv->pick_id < 0)
3090 return self->priv->pick_id;
3093 /* This is the same as clutter_actor_add_effect except that it doesn't
3094 queue a redraw and it doesn't notify on the effect property */
3096 _clutter_actor_add_effect_internal (ClutterActor *self,
3097 ClutterEffect *effect)
3099 ClutterActorPrivate *priv = self->priv;
3101 if (priv->effects == NULL)
3103 priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3104 priv->effects->actor = self;
3107 _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3110 /* This is the same as clutter_actor_remove_effect except that it doesn't
3111 queue a redraw and it doesn't notify on the effect property */
3113 _clutter_actor_remove_effect_internal (ClutterActor *self,
3114 ClutterEffect *effect)
3116 ClutterActorPrivate *priv = self->priv;
3118 if (priv->effects == NULL)
3121 _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3125 needs_flatten_effect (ClutterActor *self)
3127 ClutterActorPrivate *priv = self->priv;
3129 if (G_UNLIKELY (clutter_paint_debug_flags &
3130 CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3133 if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3135 else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3137 if (clutter_actor_get_paint_opacity (self) < 255 &&
3138 clutter_actor_has_overlaps (self))
3146 add_or_remove_flatten_effect (ClutterActor *self)
3148 ClutterActorPrivate *priv = self->priv;
3150 /* Add or remove the flatten effect depending on the
3151 offscreen-redirect property. */
3152 if (needs_flatten_effect (self))
3154 if (priv->flatten_effect == NULL)
3156 ClutterActorMeta *actor_meta;
3159 priv->flatten_effect = _clutter_flatten_effect_new ();
3160 /* Keep a reference to the effect so that we can queue
3162 g_object_ref_sink (priv->flatten_effect);
3164 /* Set the priority of the effect to high so that it will
3165 always be applied to the actor first. It uses an internal
3166 priority so that it won't be visible to applications */
3167 actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3168 priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3169 _clutter_actor_meta_set_priority (actor_meta, priority);
3171 /* This will add the effect without queueing a redraw */
3172 _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3177 if (priv->flatten_effect != NULL)
3179 /* Destroy the effect so that it will lose its fbo cache of
3181 _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3182 g_object_unref (priv->flatten_effect);
3183 priv->flatten_effect = NULL;
3189 clutter_actor_real_paint (ClutterActor *actor)
3191 ClutterActorPrivate *priv = actor->priv;
3194 for (iter = priv->first_child;
3196 iter = iter->priv->next_sibling)
3198 CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3199 _clutter_actor_get_debug_name (iter),
3200 _clutter_actor_get_debug_name (actor),
3201 iter->priv->allocation.x1,
3202 iter->priv->allocation.y1,
3203 iter->priv->allocation.x2 - iter->priv->allocation.x1,
3204 iter->priv->allocation.y2 - iter->priv->allocation.y1);
3206 clutter_actor_paint (iter);
3211 clutter_actor_paint_node (ClutterActor *actor,
3212 ClutterPaintNode *root)
3214 ClutterActorPrivate *priv = actor->priv;
3219 if (priv->bg_color_set &&
3220 !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3222 ClutterPaintNode *node;
3223 ClutterColor bg_color;
3224 ClutterActorBox box;
3228 box.x2 = clutter_actor_box_get_width (&priv->allocation);
3229 box.y2 = clutter_actor_box_get_height (&priv->allocation);
3231 bg_color = priv->bg_color;
3232 bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3233 * priv->bg_color.alpha
3236 node = clutter_color_node_new (&bg_color);
3237 clutter_paint_node_set_name (node, "backgroundColor");
3238 clutter_paint_node_add_rectangle (node, &box);
3239 clutter_paint_node_add_child (root, node);
3240 clutter_paint_node_unref (node);
3243 if (priv->content != NULL)
3244 _clutter_content_paint_content (priv->content, actor, root);
3246 if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3247 CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3249 if (clutter_paint_node_get_n_children (root) == 0)
3252 #ifdef CLUTTER_ENABLE_DEBUG
3253 if (CLUTTER_HAS_DEBUG (PAINT))
3255 /* dump the tree only if we have one */
3256 _clutter_paint_node_dump_tree (root);
3258 #endif /* CLUTTER_ENABLE_DEBUG */
3260 _clutter_paint_node_paint (root);
3263 /* XXX: Uncomment this when we disable emitting the paint signal */
3264 CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3271 * clutter_actor_paint:
3272 * @self: A #ClutterActor
3274 * Renders the actor to display.
3276 * This function should not be called directly by applications.
3277 * Call clutter_actor_queue_redraw() to queue paints, instead.
3279 * This function is context-aware, and will either cause a
3280 * regular paint or a pick paint.
3282 * This function will emit the #ClutterActor::paint signal or
3283 * the #ClutterActor::pick signal, depending on the context.
3285 * This function does not paint the actor if the actor is set to 0,
3286 * unless it is performing a pick paint.
3289 clutter_actor_paint (ClutterActor *self)
3291 ClutterActorPrivate *priv;
3292 ClutterPickMode pick_mode;
3293 gboolean clip_set = FALSE;
3294 gboolean shader_applied = FALSE;
3296 CLUTTER_STATIC_COUNTER (actor_paint_counter,
3297 "Actor real-paint counter",
3298 "Increments each time any actor is painted",
3299 0 /* no application private data */);
3300 CLUTTER_STATIC_COUNTER (actor_pick_counter,
3301 "Actor pick-paint counter",
3302 "Increments each time any actor is painted "
3304 0 /* no application private data */);
3306 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3308 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3313 pick_mode = _clutter_context_get_pick_mode ();
3315 if (pick_mode == CLUTTER_PICK_NONE)
3316 priv->propagated_one_redraw = FALSE;
3318 /* It's an important optimization that we consider painting of
3319 * actors with 0 opacity to be a NOP... */
3320 if (pick_mode == CLUTTER_PICK_NONE &&
3321 /* ignore top-levels, since they might be transparent */
3322 !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3323 /* Use the override opacity if its been set */
3324 ((priv->opacity_override >= 0) ?
3325 priv->opacity_override : priv->opacity) == 0)
3328 /* if we aren't paintable (not in a toplevel with all
3329 * parents paintable) then do nothing.
3331 if (!CLUTTER_ACTOR_IS_MAPPED (self))
3334 /* mark that we are in the paint process */
3335 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3339 if (priv->enable_model_view_transform)
3343 /* XXX: It could be better to cache the modelview with the actor
3344 * instead of progressively building up the transformations on
3345 * the matrix stack every time we paint. */
3346 cogl_get_modelview_matrix (&matrix);
3347 _clutter_actor_apply_modelview_transform (self, &matrix);
3349 #ifdef CLUTTER_ENABLE_DEBUG
3350 /* Catch when out-of-band transforms have been made by actors not as part
3351 * of an apply_transform vfunc... */
3352 if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3354 CoglMatrix expected_matrix;
3356 _clutter_actor_get_relative_transformation_matrix (self, NULL,
3359 if (!cogl_matrix_equal (&matrix, &expected_matrix))
3361 GString *buf = g_string_sized_new (1024);
3362 ClutterActor *parent;
3365 while (parent != NULL)
3367 g_string_append (buf, _clutter_actor_get_debug_name (parent));
3369 if (parent->priv->parent != NULL)
3370 g_string_append (buf, "->");
3372 parent = parent->priv->parent;
3375 g_warning ("Unexpected transform found when painting actor "
3376 "\"%s\". This will be caused by one of the actor's "
3377 "ancestors (%s) using the Cogl API directly to transform "
3378 "children instead of using ::apply_transform().",
3379 _clutter_actor_get_debug_name (self),
3382 g_string_free (buf, TRUE);
3385 #endif /* CLUTTER_ENABLE_DEBUG */
3387 cogl_set_modelview_matrix (&matrix);
3392 cogl_clip_push_rectangle (priv->clip.x,
3394 priv->clip.x + priv->clip.width,
3395 priv->clip.y + priv->clip.height);
3398 else if (priv->clip_to_allocation)
3400 gfloat width, height;
3402 width = priv->allocation.x2 - priv->allocation.x1;
3403 height = priv->allocation.y2 - priv->allocation.y1;
3405 cogl_clip_push_rectangle (0, 0, width, height);
3409 if (pick_mode == CLUTTER_PICK_NONE)
3411 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3413 /* We check whether we need to add the flatten effect before
3414 each paint so that we can avoid having a mechanism for
3415 applications to notify when the value of the
3416 has_overlaps virtual changes. */
3417 add_or_remove_flatten_effect (self);
3420 CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3422 /* We save the current paint volume so that the next time the
3423 * actor queues a redraw we can constrain the redraw to just
3424 * cover the union of the new bounding box and the old.
3426 * We also fetch the current paint volume to perform culling so
3427 * we can avoid painting actors outside the current clip region.
3429 * If we are painting inside a clone, we should neither update
3430 * the paint volume or use it to cull painting, since the paint
3431 * box represents the location of the source actor on the
3434 * XXX: We are starting to do a lot of vertex transforms on
3435 * the CPU in a typical paint, so at some point we should
3436 * audit these and consider caching some things.
3438 * NB: We don't perform culling while picking at this point because
3439 * clutter-stage.c doesn't setup the clipping planes appropriately.
3441 * NB: We don't want to update the last-paint-volume during picking
3442 * because the last-paint-volume is used to determine the old screen
3443 * space location of an actor that has moved so we can know the
3444 * minimal region to redraw to clear an old view of the actor. If we
3445 * update this during picking then by the time we come around to
3446 * paint then the last-paint-volume would likely represent the new
3447 * actor position not the old.
3449 if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3452 /* annoyingly gcc warns if uninitialized even though
3453 * the initialization is redundant :-( */
3454 ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3456 if (G_LIKELY ((clutter_paint_debug_flags &
3457 (CLUTTER_DEBUG_DISABLE_CULLING |
3458 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3459 (CLUTTER_DEBUG_DISABLE_CULLING |
3460 CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3461 _clutter_actor_update_last_paint_volume (self);
3463 success = cull_actor (self, &result);
3465 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3466 _clutter_actor_paint_cull_result (self, success, result);
3467 else if (result == CLUTTER_CULL_RESULT_OUT && success)
3471 if (priv->effects == NULL)
3473 if (pick_mode == CLUTTER_PICK_NONE &&
3474 actor_has_shader_data (self))
3476 _clutter_actor_shader_pre_paint (self, FALSE);
3477 shader_applied = TRUE;
3480 priv->next_effect_to_paint = NULL;
3483 priv->next_effect_to_paint =
3484 _clutter_meta_group_peek_metas (priv->effects);
3486 clutter_actor_continue_paint (self);
3489 _clutter_actor_shader_post_paint (self);
3491 if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3492 pick_mode == CLUTTER_PICK_NONE))
3493 _clutter_actor_draw_paint_volume (self);
3496 /* If we make it here then the actor has run through a complete
3497 paint run including all the effects so it's no longer dirty */
3498 if (pick_mode == CLUTTER_PICK_NONE)
3499 priv->is_dirty = FALSE;
3506 /* paint sequence complete */
3507 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3511 * clutter_actor_continue_paint:
3512 * @self: A #ClutterActor
3514 * Run the next stage of the paint sequence. This function should only
3515 * be called within the implementation of the ‘run’ virtual of a
3516 * #ClutterEffect. It will cause the run method of the next effect to
3517 * be applied, or it will paint the actual actor if the current effect
3518 * is the last effect in the chain.
3523 clutter_actor_continue_paint (ClutterActor *self)
3525 ClutterActorPrivate *priv;
3527 g_return_if_fail (CLUTTER_IS_ACTOR (self));
3528 /* This should only be called from with in the ‘run’ implementation
3529 of a ClutterEffect */
3530 g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3534 /* Skip any effects that are disabled */
3535 while (priv->next_effect_to_paint &&
3536 !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3537 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3539 /* If this has come from the last effect then we'll just paint the
3541 if (priv->next_effect_to_paint == NULL)
3543 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3545 ClutterPaintNode *dummy;
3547 /* XXX - this will go away in 2.0, when we can get rid of this
3548 * stuff and switch to a pure retained render tree of PaintNodes
3549 * for the entire frame, starting from the Stage; the paint()
3550 * virtual function can then be called directly.
3552 dummy = _clutter_dummy_node_new (self);
3553 clutter_paint_node_set_name (dummy, "Root");
3555 /* XXX - for 1.12, we use the return value of paint_node() to
3556 * decide whether we should emit the ::paint signal.
3558 clutter_actor_paint_node (self, dummy);
3559 clutter_paint_node_unref (dummy);
3561 g_signal_emit (self, actor_signals[PAINT], 0);
3565 ClutterColor col = { 0, };
3567 _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3569 /* Actor will then paint silhouette of itself in supplied
3570 * color. See clutter_stage_get_actor_at_pos() for where
3571 * picking is enabled.
3573 g_signal_emit (self, actor_signals[PICK], 0, &col);
3578 ClutterEffect *old_current_effect;
3579 ClutterEffectPaintFlags run_flags = 0;
3581 /* Cache the current effect so that we can put it back before
3583 old_current_effect = priv->current_effect;
3585 priv->current_effect = priv->next_effect_to_paint->data;
3586 priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3588 if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3592 /* If there's an effect queued with this redraw then all
3593 effects up to that one will be considered dirty. It
3594 is expected the queued effect will paint the cached
3595 image and not call clutter_actor_continue_paint again
3596 (although it should work ok if it does) */
3597 if (priv->effect_to_redraw == NULL ||
3598 priv->current_effect != priv->effect_to_redraw)
3599 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3602 _clutter_effect_paint (priv->current_effect, run_flags);
3606 /* We can't determine when an actor has been modified since
3607 its last pick so lets just assume it has always been
3609 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3611 _clutter_effect_pick (priv->current_effect, run_flags);
3614 priv->current_effect = old_current_effect;
3618 static ClutterActorTraverseVisitFlags
3619 invalidate_queue_redraw_entry (ClutterActor *self,
3623 ClutterActorPrivate *priv = self->priv;
3625 if (priv->queue_redraw_entry != NULL)
3627 _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3628 priv->queue_redraw_entry = NULL;
3631 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3635 remove_child (ClutterActor *self,
3636 ClutterActor *child)
3638 ClutterActor *prev_sibling, *next_sibling;
3640 prev_sibling = child->priv->prev_sibling;
3641 next_sibling = child->priv->next_sibling;
3643 if (prev_sibling != NULL)
3644 prev_sibling->priv->next_sibling = next_sibling;
3646 if (next_sibling != NULL)
3647 next_sibling->priv->prev_sibling = prev_sibling;
3649 if (self->priv->first_child == child)
3650 self->priv->first_child = next_sibling;
3652 if (self->priv->last_child == child)
3653 self->priv->last_child = prev_sibling;
3655 child->priv->parent = NULL;
3656 child->priv->prev_sibling = NULL;
3657 child->priv->next_sibling = NULL;
3661 REMOVE_CHILD_DESTROY_META = 1 << 0,
3662 REMOVE_CHILD_EMIT_PARENT_SET = 1 << 1,
3663 REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3664 REMOVE_CHILD_CHECK_STATE = 1 << 3,
3665 REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
3666 REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
3668 /* default flags for public API */
3669 REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_DESTROY_META |
3670 REMOVE_CHILD_EMIT_PARENT_SET |
3671 REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3672 REMOVE_CHILD_CHECK_STATE |
3673 REMOVE_CHILD_FLUSH_QUEUE |
3674 REMOVE_CHILD_NOTIFY_FIRST_LAST,
3676 /* flags for legacy/deprecated API */
3677 REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_CHECK_STATE |
3678 REMOVE_CHILD_FLUSH_QUEUE |
3679 REMOVE_CHILD_EMIT_PARENT_SET |
3680 REMOVE_CHILD_NOTIFY_FIRST_LAST
3681 } ClutterActorRemoveChildFlags;
3684 * clutter_actor_remove_child_internal:
3685 * @self: a #ClutterActor
3686 * @child: the child of @self that has to be removed
3687 * @flags: control the removal operations
3689 * Removes @child from the list of children of @self.
3692 clutter_actor_remove_child_internal (ClutterActor *self,
3693 ClutterActor *child,
3694 ClutterActorRemoveChildFlags flags)
3696 ClutterActor *old_first, *old_last;
3697 gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3698 gboolean flush_queue;
3699 gboolean notify_first_last;
3700 gboolean was_mapped;
3702 destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3703 emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3704 emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3705 check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3706 flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3707 notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3709 g_object_freeze_notify (G_OBJECT (self));
3712 clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3716 was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3718 /* we need to unrealize *before* we set parent_actor to NULL,
3719 * because in an unrealize method actors are dissociating from the
3720 * stage, which means they need to be able to
3721 * clutter_actor_get_stage().
3723 * yhis should unmap and unrealize, unless we're reparenting.
3725 clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3732 /* We take this opportunity to invalidate any queue redraw entry
3733 * associated with the actor and descendants since we won't be able to
3734 * determine the appropriate stage after this.
3736 * we do this after we updated the mapped state because actors might
3737 * end up queueing redraws inside their mapped/unmapped virtual
3738 * functions, and if we invalidate the redraw entry we could end up
3739 * with an inconsistent state and weird memory corruption. see
3742 * http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3743 * https://bugzilla.gnome.org/show_bug.cgi?id=652036
3745 _clutter_actor_traverse (child,
3747 invalidate_queue_redraw_entry,
3752 old_first = self->priv->first_child;
3753 old_last = self->priv->last_child;
3755 remove_child (self, child);
3757 self->priv->n_children -= 1;
3759 self->priv->age += 1;
3761 /* clutter_actor_reparent() will emit ::parent-set for us */
3762 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3763 g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3765 /* if the child was mapped then we need to relayout ourselves to account
3766 * for the removed child
3769 clutter_actor_queue_relayout (self);
3771 /* we need to emit the signal before dropping the reference */
3772 if (emit_actor_removed)
3773 g_signal_emit_by_name (self, "actor-removed", child);
3775 if (notify_first_last)
3777 if (old_first != self->priv->first_child)
3778 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3780 if (old_last != self->priv->last_child)
3781 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3784 g_object_thaw_notify (G_OBJECT (self));
3786 /* remove the reference we acquired in clutter_actor_add_child() */
3787 g_object_unref (child);
3790 static const ClutterTransformInfo default_transform_info = {
3791 0.0, { 0, }, /* rotation-x */
3792 0.0, { 0, }, /* rotation-y */
3793 0.0, { 0, }, /* rotation-z */
3795 1.0, 1.0, { 0, }, /* scale */
3797 { 0, }, /* anchor */
3803 * _clutter_actor_get_transform_info_or_defaults:
3804 * @self: a #ClutterActor
3806 * Retrieves the ClutterTransformInfo structure associated to an actor.
3808 * If the actor does not have a ClutterTransformInfo structure associated
3809 * to it, then the default structure will be returned.
3811 * This function should only be used for getters.
3813 * Return value: a const pointer to the ClutterTransformInfo structure
3815 const ClutterTransformInfo *
3816 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3818 ClutterTransformInfo *info;
3820 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3824 return &default_transform_info;
3828 clutter_transform_info_free (gpointer data)
3831 g_slice_free (ClutterTransformInfo, data);
3835 * _clutter_actor_get_transform_info:
3836 * @self: a #ClutterActor
3838 * Retrieves a pointer to the ClutterTransformInfo structure.
3840 * If the actor does not have a ClutterTransformInfo associated to it, one
3841 * will be created and initialized to the default values.
3843 * This function should be used for setters.
3845 * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3848 * Return value: (transfer none): a pointer to the ClutterTransformInfo
3851 ClutterTransformInfo *
3852 _clutter_actor_get_transform_info (ClutterActor *self)
3854 ClutterTransformInfo *info;
3856 info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3859 info = g_slice_new (ClutterTransformInfo);
3861 *info = default_transform_info;
3863 g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3865 clutter_transform_info_free);
3872 * clutter_actor_set_rotation_angle_internal:
3873 * @self: a #ClutterActor
3874 * @axis: the axis of the angle to change
3875 * @angle: the angle of rotation
3877 * Sets the rotation angle on the given axis without affecting the
3878 * rotation center point.
3881 clutter_actor_set_rotation_angle_internal (ClutterActor *self,
3882 ClutterRotateAxis axis,
3885 GObject *obj = G_OBJECT (self);
3886 ClutterTransformInfo *info;
3888 info = _clutter_actor_get_transform_info (self);
3890 g_object_freeze_notify (obj);
3894 case CLUTTER_X_AXIS:
3895 info->rx_angle = angle;
3896 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
3899 case CLUTTER_Y_AXIS:
3900 info->ry_angle = angle;
3901 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
3904 case CLUTTER_Z_AXIS:
3905 info->rz_angle = angle;
3906 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
3910 self->priv->transform_valid = FALSE;
3912 g_object_thaw_notify (obj);
3914 clutter_actor_queue_redraw (self);
3918 clutter_actor_set_rotation_angle (ClutterActor *self,
3919 ClutterRotateAxis axis,
3922 ClutterTransformInfo *info;
3924 info = _clutter_actor_get_transform_info (self);
3926 if (clutter_actor_get_easing_duration (self) != 0)
3928 ClutterTransition *transition;
3929 GParamSpec *pspec = NULL;
3930 double *cur_angle_p = NULL;
3934 case CLUTTER_X_AXIS:
3935 cur_angle_p = &info->rx_angle;
3936 pspec = obj_props[PROP_ROTATION_ANGLE_X];
3939 case CLUTTER_Y_AXIS:
3940 cur_angle_p = &info->ry_angle;
3941 pspec = obj_props[PROP_ROTATION_ANGLE_Y];
3944 case CLUTTER_Z_AXIS:
3945 cur_angle_p = &info->rz_angle;
3946 pspec = obj_props[PROP_ROTATION_ANGLE_Z];
3950 g_assert (pspec != NULL);
3951 g_assert (cur_angle_p != NULL);
3953 transition = _clutter_actor_get_transition (self, pspec);
3954 if (transition == NULL)
3956 transition = _clutter_actor_create_transition (self, pspec,
3959 clutter_timeline_start (CLUTTER_TIMELINE (transition));
3962 _clutter_actor_update_transition (self, pspec, angle);
3964 self->priv->transform_valid = FALSE;
3965 clutter_actor_queue_redraw (self);
3968 clutter_actor_set_rotation_angle_internal (self, axis, angle);
3972 * clutter_actor_set_rotation_center_internal:
3973 * @self: a #ClutterActor
3974 * @axis: the axis of the center to change
3975 * @center: the coordinates of the rotation center
3977 * Sets the rotation center on the given axis without affecting the
3981 clutter_actor_set_rotation_center_internal (ClutterActor *self,
3982 ClutterRotateAxis axis,
3983 const ClutterVertex *center)
3985 GObject *obj = G_OBJECT (self);
3986 ClutterTransformInfo *info;
3987 ClutterVertex v = { 0, 0, 0 };
3989 info = _clutter_actor_get_transform_info (self);
3994 g_object_freeze_notify (obj);
3998 case CLUTTER_X_AXIS:
3999 clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4000 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4003 case CLUTTER_Y_AXIS:
4004 clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4005 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4008 case CLUTTER_Z_AXIS:
4009 /* if the previously set rotation center was fractional, then
4010 * setting explicit coordinates will have to notify the
4011 * :rotation-center-z-gravity property as well
4013 if (info->rz_center.is_fractional)
4014 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4016 clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4017 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4021 self->priv->transform_valid = FALSE;
4023 g_object_thaw_notify (obj);
4025 clutter_actor_queue_redraw (self);
4029 clutter_actor_animate_scale_factor (ClutterActor *self,
4034 ClutterTransition *transition;
4036 transition = _clutter_actor_get_transition (self, pspec);
4037 if (transition == NULL)
4039 transition = _clutter_actor_create_transition (self, pspec,
4042 clutter_timeline_start (CLUTTER_TIMELINE (transition));
4045 _clutter_actor_update_transition (self, pspec, new_factor);
4048 self->priv->transform_valid = FALSE;
4049 clutter_actor_queue_redraw (self);
4053 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4057 GObject *obj = G_OBJECT (self);
4058 ClutterTransformInfo *info;
4060 info = _clutter_actor_get_transform_info (self);
4062 if (pspec == obj_props[PROP_SCALE_X])
4063 info->scale_x = factor;
4065 info->scale_y = factor;
4067 self->priv->transform_valid = FALSE;
4068 clutter_actor_queue_redraw (self);
4069 g_object_notify_by_pspec (obj, pspec);
4073 clutter_actor_set_scale_factor (ClutterActor *self,
4074 ClutterRotateAxis axis,
4077 GObject *obj = G_OBJECT (self);
4078 ClutterTransformInfo *info;
4081 info = _clutter_actor_get_transform_info (self);
4083 g_object_freeze_notify (obj);
4087 case CLUTTER_X_AXIS:
4088 pspec = obj_props[PROP_SCALE_X];
4090 if (clutter_actor_get_easing_duration (self) != 0)
4091 clutter_actor_animate_scale_factor (self, info->scale_x, factor, pspec);
4093 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4096 case CLUTTER_Y_AXIS:
4097 pspec = obj_props[PROP_SCALE_Y];
4099 if (clutter_actor_get_easing_duration (self) != 0)
4100 clutter_actor_animate_scale_factor (self, info->scale_y, factor, pspec);
4102 clutter_actor_set_scale_factor_internal (self, factor, pspec);
4106 g_assert_not_reached ();
4109 g_object_thaw_notify (obj);
4113 clutter_actor_set_scale_center (ClutterActor *self,
4114 ClutterRotateAxis axis,
4117 GObject *obj = G_OBJECT (self);
4118 ClutterTransformInfo *info;
4119 gfloat center_x, center_y;
4121 info = _clutter_actor_get_transform_info (self);
4123 g_object_freeze_notify (obj);
4125 /* get the current scale center coordinates */
4126 clutter_anchor_coord_get_units (self, &info->scale_center,
4131 /* we need to notify this too, because setting explicit coordinates will
4132 * change the gravity as a side effect
4134 if (info->scale_center.is_fractional)
4135 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4139 case CLUTTER_X_AXIS:
4140 clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4141 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4144 case CLUTTER_Y_AXIS:
4145 clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4146 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4150 g_assert_not_reached ();
4153 self->priv->transform_valid = FALSE;
4155 clutter_actor_queue_redraw (self);
4157 g_object_thaw_notify (obj);
4161 clutter_actor_set_anchor_coord (ClutterActor *self,
4162 ClutterRotateAxis axis,
4165 GObject *obj = G_OBJECT (self);
4166 ClutterTransformInfo *info;
4167 gfloat anchor_x, anchor_y;
4169 info = _clutter_actor_get_transform_info (self);
4171 g_object_freeze_notify (obj);
4173 clutter_anchor_coord_get_units (self, &info->anchor,
4178 if (info->anchor.is_fractional)
4179 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4183 case CLUTTER_X_AXIS:
4184 clutter_anchor_coord_set_units (&info->anchor,
4188 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4191 case CLUTTER_Y_AXIS:
4192 clutter_anchor_coord_set_units (&info->anchor,
4196 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4200 g_assert_not_reached ();
4203 self->priv->transform_valid = FALSE;
4205 clutter_actor_queue_redraw (self);
4207 g_object_thaw_notify (obj);
4211 clutter_actor_set_property (GObject *object,
4213 const GValue *value,
4216 ClutterActor *actor = CLUTTER_ACTOR (object);
4217 ClutterActorPrivate *priv = actor->priv;
4222 clutter_actor_set_x (actor, g_value_get_float (value));
4226 clutter_actor_set_y (actor, g_value_get_float (value));
4230 clutter_actor_set_width (actor, g_value_get_float (value));
4234 clutter_actor_set_height (actor, g_value_get_float (value));
4238 clutter_actor_set_x (actor, g_value_get_float (value));
4242 clutter_actor_set_y (actor, g_value_get_float (value));
4245 case PROP_FIXED_POSITION_SET:
4246 clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4249 case PROP_MIN_WIDTH:
4250 clutter_actor_set_min_width (actor, g_value_get_float (value));
4253 case PROP_MIN_HEIGHT:
4254 clutter_actor_set_min_height (actor, g_value_get_float (value));
4257 case PROP_NATURAL_WIDTH:
4258 clutter_actor_set_natural_width (actor, g_value_get_float (value));
4261 case PROP_NATURAL_HEIGHT:
4262 clutter_actor_set_natural_height (actor, g_value_get_float (value));
4265 case PROP_MIN_WIDTH_SET:
4266 clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4269 case PROP_MIN_HEIGHT_SET:
4270 clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4273 case PROP_NATURAL_WIDTH_SET:
4274 clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4277 case PROP_NATURAL_HEIGHT_SET:
4278 clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4281 case PROP_REQUEST_MODE:
4282 clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4286 clutter_actor_set_depth (actor, g_value_get_float (value));
4290 clutter_actor_set_opacity (actor, g_value_get_uint (value));
4293 case PROP_OFFSCREEN_REDIRECT:
4294 clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4298 clutter_actor_set_name (actor, g_value_get_string (value));
4302 if (g_value_get_boolean (value) == TRUE)
4303 clutter_actor_show (actor);
4305 clutter_actor_hide (actor);
4309 clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4310 g_value_get_double (value));
4314 clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4315 g_value_get_double (value));
4318 case PROP_SCALE_CENTER_X:
4319 clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4320 g_value_get_float (value));
4323 case PROP_SCALE_CENTER_Y:
4324 clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4325 g_value_get_float (value));
4328 case PROP_SCALE_GRAVITY:
4330 const ClutterTransformInfo *info;
4331 ClutterGravity gravity;
4333 info = _clutter_actor_get_transform_info_or_defaults (actor);
4334 gravity = g_value_get_enum (value);
4336 clutter_actor_set_scale_with_gravity (actor,
4345 const ClutterGeometry *geom = g_value_get_boxed (value);
4347 clutter_actor_set_clip (actor,
4349 geom->width, geom->height);
4353 case PROP_CLIP_TO_ALLOCATION:
4354 clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4358 clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4361 case PROP_ROTATION_ANGLE_X:
4362 clutter_actor_set_rotation_angle (actor,
4364 g_value_get_double (value));
4367 case PROP_ROTATION_ANGLE_Y:
4368 clutter_actor_set_rotation_angle (actor,
4370 g_value_get_double (value));
4373 case PROP_ROTATION_ANGLE_Z:
4374 clutter_actor_set_rotation_angle (actor,
4376 g_value_get_double (value));
4379 case PROP_ROTATION_CENTER_X:
4380 clutter_actor_set_rotation_center_internal (actor,
4382 g_value_get_boxed (value));
4385 case PROP_ROTATION_CENTER_Y:
4386 clutter_actor_set_rotation_center_internal (actor,
4388 g_value_get_boxed (value));
4391 case PROP_ROTATION_CENTER_Z:
4392 clutter_actor_set_rotation_center_internal (actor,
4394 g_value_get_boxed (value));
4397 case PROP_ROTATION_CENTER_Z_GRAVITY:
4399 const ClutterTransformInfo *info;
4401 info = _clutter_actor_get_transform_info_or_defaults (actor);
4402 clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4403 g_value_get_enum (value));
4408 clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4409 g_value_get_float (value));
4413 clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4414 g_value_get_float (value));
4417 case PROP_ANCHOR_GRAVITY:
4418 clutter_actor_set_anchor_point_from_gravity (actor,
4419 g_value_get_enum (value));
4422 case PROP_SHOW_ON_SET_PARENT:
4423 priv->show_on_set_parent = g_value_get_boolean (value);
4426 case PROP_TEXT_DIRECTION:
4427 clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4431 clutter_actor_add_action (actor, g_value_get_object (value));
4434 case PROP_CONSTRAINTS:
4435 clutter_actor_add_constraint (actor, g_value_get_object (value));
4439 clutter_actor_add_effect (actor, g_value_get_object (value));
4442 case PROP_LAYOUT_MANAGER:
4443 clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4447 clutter_actor_set_x_align (actor, g_value_get_enum (value));
4451 clutter_actor_set_y_align (actor, g_value_get_enum (value));
4454 case PROP_MARGIN_TOP:
4455 clutter_actor_set_margin_top (actor, g_value_get_float (value));
4458 case PROP_MARGIN_BOTTOM:
4459 clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4462 case PROP_MARGIN_LEFT:
4463 clutter_actor_set_margin_left (actor, g_value_get_float (value));
4466 case PROP_MARGIN_RIGHT:
4467 clutter_actor_set_margin_right (actor, g_value_get_float (value));
4470 case PROP_BACKGROUND_COLOR:
4471 clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4475 clutter_actor_set_content (actor, g_value_get_object (value));
4478 case PROP_CONTENT_GRAVITY:
4479 clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4482 case PROP_MINIFICATION_FILTER:
4483 clutter_actor_set_content_scaling_filters (actor,
4484 g_value_get_enum (value),
4485 actor->priv->mag_filter);
4488 case PROP_MAGNIFICATION_FILTER:
4489 clutter_actor_set_content_scaling_filters (actor,
4490 actor->priv->min_filter,
4491 g_value_get_enum (value));
4495 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4501 clutter_actor_get_property (GObject *object,
4506 ClutterActor *actor = CLUTTER_ACTOR (object);
4507 ClutterActorPrivate *priv = actor->priv;
4512 g_value_set_float (value, clutter_actor_get_x (actor));
4516 g_value_set_float (value, clutter_actor_get_y (actor));
4520 g_value_set_float (value, clutter_actor_get_width (actor));
4524 g_value_set_float (value, clutter_actor_get_height (actor));
4529 const ClutterLayoutInfo *info;
4531 info = _clutter_actor_get_layout_info_or_defaults (actor);
4532 g_value_set_float (value, info->fixed_x);
4538 const ClutterLayoutInfo *info;
4540 info = _clutter_actor_get_layout_info_or_defaults (actor);
4541 g_value_set_float (value, info->fixed_y);
4545 case PROP_FIXED_POSITION_SET:
4546 g_value_set_boolean (value, priv->position_set);
4549 case PROP_MIN_WIDTH:
4551 const ClutterLayoutInfo *info;
4553 info = _clutter_actor_get_layout_info_or_defaults (actor);
4554 g_value_set_float (value, info->min_width);
4558 case PROP_MIN_HEIGHT:
4560 const ClutterLayoutInfo *info;
4562 info = _clutter_actor_get_layout_info_or_defaults (actor);
4563 g_value_set_float (value, info->min_height);
4567 case PROP_NATURAL_WIDTH:
4569 const ClutterLayoutInfo *info;
4571 info = _clutter_actor_get_layout_info_or_defaults (actor);
4572 g_value_set_float (value, info->natural_width);
4576 case PROP_NATURAL_HEIGHT:
4578 const ClutterLayoutInfo *info;
4580 info = _clutter_actor_get_layout_info_or_defaults (actor);
4581 g_value_set_float (value, info->natural_height);
4585 case PROP_MIN_WIDTH_SET:
4586 g_value_set_boolean (value, priv->min_width_set);
4589 case PROP_MIN_HEIGHT_SET:
4590 g_value_set_boolean (value, priv->min_height_set);
4593 case PROP_NATURAL_WIDTH_SET:
4594 g_value_set_boolean (value, priv->natural_width_set);
4597 case PROP_NATURAL_HEIGHT_SET:
4598 g_value_set_boolean (value, priv->natural_height_set);
4601 case PROP_REQUEST_MODE:
4602 g_value_set_enum (value, priv->request_mode);
4605 case PROP_ALLOCATION:
4606 g_value_set_boxed (value, &priv->allocation);
4610 g_value_set_float (value, clutter_actor_get_depth (actor));
4614 g_value_set_uint (value, priv->opacity);
4617 case PROP_OFFSCREEN_REDIRECT:
4618 g_value_set_enum (value, priv->offscreen_redirect);
4622 g_value_set_string (value, priv->name);
4626 g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4630 g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4634 g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4638 g_value_set_boolean (value, priv->has_clip);
4643 ClutterGeometry clip;
4645 clip.x = CLUTTER_NEARBYINT (priv->clip.x);
4646 clip.y = CLUTTER_NEARBYINT (priv->clip.y);
4647 clip.width = CLUTTER_NEARBYINT (priv->clip.width);
4648 clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4650 g_value_set_boxed (value, &clip);
4654 case PROP_CLIP_TO_ALLOCATION:
4655 g_value_set_boolean (value, priv->clip_to_allocation);
4660 const ClutterTransformInfo *info;
4662 info = _clutter_actor_get_transform_info_or_defaults (actor);
4663 g_value_set_double (value, info->scale_x);
4669 const ClutterTransformInfo *info;
4671 info = _clutter_actor_get_transform_info_or_defaults (actor);
4672 g_value_set_double (value, info->scale_y);
4676 case PROP_SCALE_CENTER_X:
4680 clutter_actor_get_scale_center (actor, ¢er, NULL);
4682 g_value_set_float (value, center);
4686 case PROP_SCALE_CENTER_Y:
4690 clutter_actor_get_scale_center (actor, NULL, ¢er);
4692 g_value_set_float (value, center);
4696 case PROP_SCALE_GRAVITY:
4697 g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4701 g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4704 case PROP_ROTATION_ANGLE_X:
4706 const ClutterTransformInfo *info;
4708 info = _clutter_actor_get_transform_info_or_defaults (actor);
4709 g_value_set_double (value, info->rx_angle);
4713 case PROP_ROTATION_ANGLE_Y:
4715 const ClutterTransformInfo *info;
4717 info = _clutter_actor_get_transform_info_or_defaults (actor);
4718 g_value_set_double (value, info->ry_angle);
4722 case PROP_ROTATION_ANGLE_Z:
4724 const ClutterTransformInfo *info;
4726 info = _clutter_actor_get_transform_info_or_defaults (actor);
4727 g_value_set_double (value, info->rz_angle);
4731 case PROP_ROTATION_CENTER_X:
4733 ClutterVertex center;
4735 clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4740 g_value_set_boxed (value, ¢er);
4744 case PROP_ROTATION_CENTER_Y:
4746 ClutterVertex center;
4748 clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4753 g_value_set_boxed (value, ¢er);
4757 case PROP_ROTATION_CENTER_Z:
4759 ClutterVertex center;
4761 clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4766 g_value_set_boxed (value, ¢er);
4770 case PROP_ROTATION_CENTER_Z_GRAVITY:
4771 g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4776 const ClutterTransformInfo *info;
4779 info = _clutter_actor_get_transform_info_or_defaults (actor);
4780 clutter_anchor_coord_get_units (actor, &info->anchor,
4784 g_value_set_float (value, anchor_x);
4790 const ClutterTransformInfo *info;
4793 info = _clutter_actor_get_transform_info_or_defaults (actor);
4794 clutter_anchor_coord_get_units (actor, &info->anchor,
4798 g_value_set_float (value, anchor_y);
4802 case PROP_ANCHOR_GRAVITY:
4803 g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4806 case PROP_SHOW_ON_SET_PARENT:
4807 g_value_set_boolean (value, priv->show_on_set_parent);
4810 case PROP_TEXT_DIRECTION:
4811 g_value_set_enum (value, priv->text_direction);
4814 case PROP_HAS_POINTER:
4815 g_value_set_boolean (value, priv->has_pointer);
4818 case PROP_LAYOUT_MANAGER:
4819 g_value_set_object (value, priv->layout_manager);
4824 const ClutterLayoutInfo *info;
4826 info = _clutter_actor_get_layout_info_or_defaults (actor);
4827 g_value_set_enum (value, info->x_align);
4833 const ClutterLayoutInfo *info;
4835 info = _clutter_actor_get_layout_info_or_defaults (actor);
4836 g_value_set_enum (value, info->y_align);
4840 case PROP_MARGIN_TOP:
4842 const ClutterLayoutInfo *info;
4844 info = _clutter_actor_get_layout_info_or_defaults (actor);
4845 g_value_set_float (value, info->margin.top);
4849 case PROP_MARGIN_BOTTOM:
4851 const ClutterLayoutInfo *info;
4853 info = _clutter_actor_get_layout_info_or_defaults (actor);
4854 g_value_set_float (value, info->margin.bottom);
4858 case PROP_MARGIN_LEFT:
4860 const ClutterLayoutInfo *info;
4862 info = _clutter_actor_get_layout_info_or_defaults (actor);
4863 g_value_set_float (value, info->margin.left);
4867 case PROP_MARGIN_RIGHT:
4869 const ClutterLayoutInfo *info;
4871 info = _clutter_actor_get_layout_info_or_defaults (actor);
4872 g_value_set_float (value, info->margin.right);
4876 case PROP_BACKGROUND_COLOR_SET:
4877 g_value_set_boolean (value, priv->bg_color_set);
4880 case PROP_BACKGROUND_COLOR:
4881 g_value_set_boxed (value, &priv->bg_color);
4884 case PROP_FIRST_CHILD:
4885 g_value_set_object (value, priv->first_child);
4888 case PROP_LAST_CHILD:
4889 g_value_set_object (value, priv->last_child);
4893 g_value_set_object (value, priv->content);
4896 case PROP_CONTENT_GRAVITY:
4897 g_value_set_enum (value, priv->content_gravity);
4900 case PROP_CONTENT_BOX:
4902 ClutterActorBox box = { 0, };
4904 clutter_actor_get_content_box (actor, &box);
4905 g_value_set_boxed (value, &box);
4909 case PROP_MINIFICATION_FILTER:
4910 g_value_set_enum (value, priv->min_filter);
4913 case PROP_MAGNIFICATION_FILTER:
4914 g_value_set_enum (value, priv->mag_filter);
4918 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4924 clutter_actor_dispose (GObject *object)
4926 ClutterActor *self = CLUTTER_ACTOR (object);
4927 ClutterActorPrivate *priv = self->priv;
4929 CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
4931 g_type_name (G_OBJECT_TYPE (self)),
4934 g_signal_emit (self, actor_signals[DESTROY], 0);
4936 /* avoid recursing when called from clutter_actor_destroy() */
4937 if (priv->parent != NULL)
4939 ClutterActor *parent = priv->parent;
4941 /* go through the Container implementation unless this
4942 * is an internal child and has been marked as such.
4944 * removing the actor from its parent will reset the
4945 * realized and mapped states.
4947 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
4948 clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
4950 clutter_actor_remove_child_internal (parent, self,
4951 REMOVE_CHILD_LEGACY_FLAGS);
4954 /* parent must be gone at this point */
4955 g_assert (priv->parent == NULL);
4957 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
4959 /* can't be mapped or realized with no parent */
4960 g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
4961 g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
4964 g_clear_object (&priv->pango_context);
4965 g_clear_object (&priv->actions);
4966 g_clear_object (&priv->constraints);
4967 g_clear_object (&priv->effects);
4968 g_clear_object (&priv->flatten_effect);
4970 if (priv->layout_manager != NULL)
4972 clutter_layout_manager_set_container (priv->layout_manager, NULL);
4973 g_clear_object (&priv->layout_manager);
4976 if (priv->content != NULL)
4978 _clutter_content_detached (priv->content, self);
4979 g_clear_object (&priv->content);
4982 G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
4986 clutter_actor_finalize (GObject *object)
4988 ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
4990 CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
4991 priv->name != NULL ? priv->name : "<none>",
4993 g_type_name (G_OBJECT_TYPE (object)));
4995 _clutter_context_release_id (priv->id);
4997 g_free (priv->name);
4999 G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5004 * clutter_actor_get_accessible:
5005 * @self: a #ClutterActor
5007 * Returns the accessible object that describes the actor to an
5008 * assistive technology.
5010 * If no class-specific #AtkObject implementation is available for the
5011 * actor instance in question, it will inherit an #AtkObject
5012 * implementation from the first ancestor class for which such an
5013 * implementation is defined.
5015 * The documentation of the <ulink
5016 * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5017 * library contains more information about accessible objects and
5020 * Returns: (transfer none): the #AtkObject associated with @actor
5023 clutter_actor_get_accessible (ClutterActor *self)
5025 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5027 return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5031 clutter_actor_real_get_accessible (ClutterActor *actor)
5033 return atk_gobject_accessible_for_object (G_OBJECT (actor));
5037 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5039 AtkObject *accessible;
5041 accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5042 if (accessible != NULL)
5043 g_object_ref (accessible);
5049 atk_implementor_iface_init (AtkImplementorIface *iface)
5051 iface->ref_accessible = _clutter_actor_ref_accessible;
5055 clutter_actor_update_default_paint_volume (ClutterActor *self,
5056 ClutterPaintVolume *volume)
5058 ClutterActorPrivate *priv = self->priv;
5059 gboolean res = FALSE;
5061 /* we start from the allocation */
5062 clutter_paint_volume_set_width (volume,
5063 priv->allocation.x2 - priv->allocation.x1);
5064 clutter_paint_volume_set_height (volume,
5065 priv->allocation.y2 - priv->allocation.y1);
5067 /* if the actor has a clip set then we have a pretty definite
5068 * size for the paint volume: the actor cannot possibly paint
5069 * outside the clip region.
5071 if (priv->clip_to_allocation)
5073 /* the allocation has already been set, so we just flip the
5080 ClutterActor *child;
5082 if (priv->has_clip &&
5083 priv->clip.width >= 0 &&
5084 priv->clip.height >= 0)
5086 ClutterVertex origin;
5088 origin.x = priv->clip.x;
5089 origin.y = priv->clip.y;
5092 clutter_paint_volume_set_origin (volume, &origin);
5093 clutter_paint_volume_set_width (volume, priv->clip.width);
5094 clutter_paint_volume_set_height (volume, priv->clip.height);
5099 /* if we don't have children we just bail out here... */
5100 if (priv->n_children == 0)
5103 /* ...but if we have children then we ask for their paint volume in
5104 * our coordinates. if any of our children replies that it doesn't
5105 * have a paint volume, we bail out
5107 for (child = priv->first_child;
5109 child = child->priv->next_sibling)
5111 const ClutterPaintVolume *child_volume;
5113 child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5114 if (child_volume == NULL)
5120 clutter_paint_volume_union (volume, child_volume);
5130 clutter_actor_real_get_paint_volume (ClutterActor *self,
5131 ClutterPaintVolume *volume)
5133 ClutterActorClass *klass;
5136 klass = CLUTTER_ACTOR_GET_CLASS (self);
5138 /* XXX - this thoroughly sucks, but we don't want to penalize users
5139 * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5140 * redraw. This should go away in 2.0.
5142 if (klass->paint == clutter_actor_real_paint &&
5143 klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5149 /* this is the default return value: we cannot know if a class
5150 * is going to paint outside its allocation, so we take the
5151 * conservative approach.
5156 if (clutter_actor_update_default_paint_volume (self, volume))
5163 * clutter_actor_get_default_paint_volume:
5164 * @self: a #ClutterActor
5166 * Retrieves the default paint volume for @self.
5168 * This function provides the same #ClutterPaintVolume that would be
5169 * computed by the default implementation inside #ClutterActor of the
5170 * #ClutterActorClass.get_paint_volume() virtual function.
5172 * This function should only be used by #ClutterActor subclasses that
5173 * cannot chain up to the parent implementation when computing their
5176 * Return value: (transfer none): a pointer to the default
5177 * #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5178 * the actor could not compute a valid paint volume. The returned value
5179 * is not guaranteed to be stable across multiple frames, so if you
5180 * want to retain it, you will need to copy it using
5181 * clutter_paint_volume_copy().
5185 const ClutterPaintVolume *
5186 clutter_actor_get_default_paint_volume (ClutterActor *self)
5188 ClutterPaintVolume volume;
5189 ClutterPaintVolume *res;
5191 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5194 _clutter_paint_volume_init_static (&volume, self);
5195 if (clutter_actor_update_default_paint_volume (self, &volume))
5197 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5201 res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5202 _clutter_paint_volume_copy_static (&volume, res);
5206 clutter_paint_volume_free (&volume);
5212 clutter_actor_real_has_overlaps (ClutterActor *self)
5214 /* By default we'll assume that all actors need an offscreen redirect to get
5215 * the correct opacity. Actors such as ClutterTexture that would never need
5216 * an offscreen redirect can override this to return FALSE. */
5221 clutter_actor_real_destroy (ClutterActor *actor)
5223 ClutterActorIter iter;
5225 clutter_actor_iter_init (&iter, actor);
5226 while (clutter_actor_iter_next (&iter, NULL))
5227 clutter_actor_iter_destroy (&iter);
5231 clutter_actor_constructor (GType gtype,
5233 GObjectConstructParam *props)
5235 GObjectClass *gobject_class;
5239 gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5240 retval = gobject_class->constructor (gtype, n_props, props);
5241 self = CLUTTER_ACTOR (retval);
5243 if (self->priv->layout_manager == NULL)
5245 ClutterLayoutManager *default_layout;
5247 CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5249 default_layout = clutter_fixed_layout_new ();
5250 clutter_actor_set_layout_manager (self, default_layout);
5257 clutter_actor_class_init (ClutterActorClass *klass)
5259 GObjectClass *object_class = G_OBJECT_CLASS (klass);
5261 quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5262 quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5263 quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5264 quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5266 object_class->constructor = clutter_actor_constructor;
5267 object_class->set_property = clutter_actor_set_property;
5268 object_class->get_property = clutter_actor_get_property;
5269 object_class->dispose = clutter_actor_dispose;
5270 object_class->finalize = clutter_actor_finalize;
5272 klass->show = clutter_actor_real_show;
5273 klass->show_all = clutter_actor_show;
5274 klass->hide = clutter_actor_real_hide;
5275 klass->hide_all = clutter_actor_hide;
5276 klass->map = clutter_actor_real_map;
5277 klass->unmap = clutter_actor_real_unmap;
5278 klass->unrealize = clutter_actor_real_unrealize;
5279 klass->pick = clutter_actor_real_pick;
5280 klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5281 klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5282 klass->allocate = clutter_actor_real_allocate;
5283 klass->queue_redraw = clutter_actor_real_queue_redraw;
5284 klass->queue_relayout = clutter_actor_real_queue_relayout;
5285 klass->apply_transform = clutter_actor_real_apply_transform;
5286 klass->get_accessible = clutter_actor_real_get_accessible;
5287 klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5288 klass->has_overlaps = clutter_actor_real_has_overlaps;
5289 klass->paint = clutter_actor_real_paint;
5290 klass->destroy = clutter_actor_real_destroy;
5292 g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5297 * X coordinate of the actor in pixels. If written, forces a fixed
5298 * position for the actor. If read, returns the fixed position if any,
5299 * otherwise the allocation if available, otherwise 0.
5301 * The #ClutterActor:x property is animatable.
5304 g_param_spec_float ("x",
5306 P_("X coordinate of the actor"),
5307 -G_MAXFLOAT, G_MAXFLOAT,
5310 G_PARAM_STATIC_STRINGS |
5311 CLUTTER_PARAM_ANIMATABLE);
5316 * Y coordinate of the actor in pixels. If written, forces a fixed
5317 * position for the actor. If read, returns the fixed position if
5318 * any, otherwise the allocation if available, otherwise 0.
5320 * The #ClutterActor:y property is animatable.
5323 g_param_spec_float ("y",
5325 P_("Y coordinate of the actor"),
5326 -G_MAXFLOAT, G_MAXFLOAT,
5329 G_PARAM_STATIC_STRINGS |
5330 CLUTTER_PARAM_ANIMATABLE);
5333 * ClutterActor:width:
5335 * Width of the actor (in pixels). If written, forces the minimum and
5336 * natural size request of the actor to the given width. If read, returns
5337 * the allocated width if available, otherwise the width request.
5339 * The #ClutterActor:width property is animatable.
5341 obj_props[PROP_WIDTH] =
5342 g_param_spec_float ("width",
5344 P_("Width of the actor"),
5348 G_PARAM_STATIC_STRINGS |
5349 CLUTTER_PARAM_ANIMATABLE);
5352 * ClutterActor:height:
5354 * Height of the actor (in pixels). If written, forces the minimum and
5355 * natural size request of the actor to the given height. If read, returns
5356 * the allocated height if available, otherwise the height request.
5358 * The #ClutterActor:height property is animatable.
5360 obj_props[PROP_HEIGHT] =
5361 g_param_spec_float ("height",
5363 P_("Height of the actor"),
5367 G_PARAM_STATIC_STRINGS |
5368 CLUTTER_PARAM_ANIMATABLE);
5371 * ClutterActor:fixed-x:
5373 * The fixed X position of the actor in pixels.
5375 * Writing this property sets #ClutterActor:fixed-position-set
5376 * property as well, as a side effect
5380 obj_props[PROP_FIXED_X] =
5381 g_param_spec_float ("fixed-x",
5383 P_("Forced X position of the actor"),
5384 -G_MAXFLOAT, G_MAXFLOAT,
5386 CLUTTER_PARAM_READWRITE);
5389 * ClutterActor:fixed-y:
5391 * The fixed Y position of the actor in pixels.
5393 * Writing this property sets the #ClutterActor:fixed-position-set
5394 * property as well, as a side effect
5398 obj_props[PROP_FIXED_Y] =
5399 g_param_spec_float ("fixed-y",
5401 P_("Forced Y position of the actor"),
5402 -G_MAXFLOAT, G_MAXFLOAT,
5404 CLUTTER_PARAM_READWRITE);
5407 * ClutterActor:fixed-position-set:
5409 * This flag controls whether the #ClutterActor:fixed-x and
5410 * #ClutterActor:fixed-y properties are used
5414 obj_props[PROP_FIXED_POSITION_SET] =
5415 g_param_spec_boolean ("fixed-position-set",
5416 P_("Fixed position set"),
5417 P_("Whether to use fixed positioning for the actor"),
5419 CLUTTER_PARAM_READWRITE);
5422 * ClutterActor:min-width:
5424 * A forced minimum width request for the actor, in pixels
5426 * Writing this property sets the #ClutterActor:min-width-set property
5427 * as well, as a side effect.
5429 *This property overrides the usual width request of the actor.
5433 obj_props[PROP_MIN_WIDTH] =
5434 g_param_spec_float ("min-width",
5436 P_("Forced minimum width request for the actor"),
5439 CLUTTER_PARAM_READWRITE);
5442 * ClutterActor:min-height:
5444 * A forced minimum height request for the actor, in pixels
5446 * Writing this property sets the #ClutterActor:min-height-set property
5447 * as well, as a side effect. This property overrides the usual height
5448 * request of the actor.
5452 obj_props[PROP_MIN_HEIGHT] =
5453 g_param_spec_float ("min-height",
5455 P_("Forced minimum height request for the actor"),
5458 CLUTTER_PARAM_READWRITE);
5461 * ClutterActor:natural-width:
5463 * A forced natural width request for the actor, in pixels
5465 * Writing this property sets the #ClutterActor:natural-width-set
5466 * property as well, as a side effect. This property overrides the
5467 * usual width request of the actor
5471 obj_props[PROP_NATURAL_WIDTH] =
5472 g_param_spec_float ("natural-width",
5473 P_("Natural Width"),
5474 P_("Forced natural width request for the actor"),
5477 CLUTTER_PARAM_READWRITE);
5480 * ClutterActor:natural-height:
5482 * A forced natural height request for the actor, in pixels
5484 * Writing this property sets the #ClutterActor:natural-height-set
5485 * property as well, as a side effect. This property overrides the
5486 * usual height request of the actor
5490 obj_props[PROP_NATURAL_HEIGHT] =
5491 g_param_spec_float ("natural-height",
5492 P_("Natural Height"),
5493 P_("Forced natural height request for the actor"),
5496 CLUTTER_PARAM_READWRITE);
5499 * ClutterActor:min-width-set:
5501 * This flag controls whether the #ClutterActor:min-width property
5506 obj_props[PROP_MIN_WIDTH_SET] =
5507 g_param_spec_boolean ("min-width-set",
5508 P_("Minimum width set"),
5509 P_("Whether to use the min-width property"),
5511 CLUTTER_PARAM_READWRITE);
5514 * ClutterActor:min-height-set:
5516 * This flag controls whether the #ClutterActor:min-height property
5521 obj_props[PROP_MIN_HEIGHT_SET] =
5522 g_param_spec_boolean ("min-height-set",
5523 P_("Minimum height set"),
5524 P_("Whether to use the min-height property"),
5526 CLUTTER_PARAM_READWRITE);
5529 * ClutterActor:natural-width-set:
5531 * This flag controls whether the #ClutterActor:natural-width property
5536 obj_props[PROP_NATURAL_WIDTH_SET] =
5537 g_param_spec_boolean ("natural-width-set",
5538 P_("Natural width set"),
5539 P_("Whether to use the natural-width property"),
5541 CLUTTER_PARAM_READWRITE);
5544 * ClutterActor:natural-height-set:
5546 * This flag controls whether the #ClutterActor:natural-height property
5551 obj_props[PROP_NATURAL_HEIGHT_SET] =
5552 g_param_spec_boolean ("natural-height-set",
5553 P_("Natural height set"),
5554 P_("Whether to use the natural-height property"),
5556 CLUTTER_PARAM_READWRITE);
5559 * ClutterActor:allocation:
5561 * The allocation for the actor, in pixels
5563 * This is property is read-only, but you might monitor it to know when an
5564 * actor moves or resizes
5568 obj_props[PROP_ALLOCATION] =
5569 g_param_spec_boxed ("allocation",
5571 P_("The actor's allocation"),
5572 CLUTTER_TYPE_ACTOR_BOX,
5573 CLUTTER_PARAM_READABLE);
5576 * ClutterActor:request-mode:
5578 * Request mode for the #ClutterActor. The request mode determines the
5579 * type of geometry management used by the actor, either height for width
5580 * (the default) or width for height.
5582 * For actors implementing height for width, the parent container should get
5583 * the preferred width first, and then the preferred height for that width.
5585 * For actors implementing width for height, the parent container should get
5586 * the preferred height first, and then the preferred width for that height.
5591 * ClutterRequestMode mode;
5592 * gfloat natural_width, min_width;
5593 * gfloat natural_height, min_height;
5595 * mode = clutter_actor_get_request_mode (child);
5596 * if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5598 * clutter_actor_get_preferred_width (child, -1,
5600 * &natural_width);
5601 * clutter_actor_get_preferred_height (child, natural_width,
5603 * &natural_height);
5607 * clutter_actor_get_preferred_height (child, -1,
5609 * &natural_height);
5610 * clutter_actor_get_preferred_width (child, natural_height,
5612 * &natural_width);
5616 * will retrieve the minimum and natural width and height depending on the
5617 * preferred request mode of the #ClutterActor "child".
5619 * The clutter_actor_get_preferred_size() function will implement this
5624 obj_props[PROP_REQUEST_MODE] =
5625 g_param_spec_enum ("request-mode",
5627 P_("The actor's request mode"),
5628 CLUTTER_TYPE_REQUEST_MODE,
5629 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5630 CLUTTER_PARAM_READWRITE);
5633 * ClutterActor:depth:
5635 * The position of the actor on the Z axis.
5637 * The #ClutterActor:depth property is relative to the parent's
5640 * The #ClutterActor:depth property is animatable.
5644 obj_props[PROP_DEPTH] =
5645 g_param_spec_float ("depth",
5647 P_("Position on the Z axis"),
5648 -G_MAXFLOAT, G_MAXFLOAT,
5651 G_PARAM_STATIC_STRINGS |
5652 CLUTTER_PARAM_ANIMATABLE);
5655 * ClutterActor:opacity:
5657 * Opacity of an actor, between 0 (fully transparent) and
5658 * 255 (fully opaque)
5660 * The #ClutterActor:opacity property is animatable.
5662 obj_props[PROP_OPACITY] =
5663 g_param_spec_uint ("opacity",
5665 P_("Opacity of an actor"),
5669 G_PARAM_STATIC_STRINGS |
5670 CLUTTER_PARAM_ANIMATABLE);
5673 * ClutterActor:offscreen-redirect:
5675 * Determines the conditions in which the actor will be redirected
5676 * to an offscreen framebuffer while being painted. For example this
5677 * can be used to cache an actor in a framebuffer or for improved
5678 * handling of transparent actors. See
5679 * clutter_actor_set_offscreen_redirect() for details.
5683 obj_props[PROP_OFFSCREEN_REDIRECT] =
5684 g_param_spec_flags ("offscreen-redirect",
5685 P_("Offscreen redirect"),
5686 P_("Flags controlling when to flatten the actor into a single image"),
5687 CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5689 CLUTTER_PARAM_READWRITE);
5692 * ClutterActor:visible:
5694 * Whether the actor is set to be visible or not
5696 * See also #ClutterActor:mapped
5698 obj_props[PROP_VISIBLE] =
5699 g_param_spec_boolean ("visible",
5701 P_("Whether the actor is visible or not"),
5703 CLUTTER_PARAM_READWRITE);
5706 * ClutterActor:mapped:
5708 * Whether the actor is mapped (will be painted when the stage
5709 * to which it belongs is mapped)
5713 obj_props[PROP_MAPPED] =
5714 g_param_spec_boolean ("mapped",
5716 P_("Whether the actor will be painted"),
5718 CLUTTER_PARAM_READABLE);
5721 * ClutterActor:realized:
5723 * Whether the actor has been realized
5727 obj_props[PROP_REALIZED] =
5728 g_param_spec_boolean ("realized",
5730 P_("Whether the actor has been realized"),
5732 CLUTTER_PARAM_READABLE);
5735 * ClutterActor:reactive:
5737 * Whether the actor is reactive to events or not
5739 * Only reactive actors will emit event-related signals
5743 obj_props[PROP_REACTIVE] =
5744 g_param_spec_boolean ("reactive",
5746 P_("Whether the actor is reactive to events"),
5748 CLUTTER_PARAM_READWRITE);
5751 * ClutterActor:has-clip:
5753 * Whether the actor has the #ClutterActor:clip property set or not
5755 obj_props[PROP_HAS_CLIP] =
5756 g_param_spec_boolean ("has-clip",
5758 P_("Whether the actor has a clip set"),
5760 CLUTTER_PARAM_READABLE);
5763 * ClutterActor:clip:
5765 * The clip region for the actor, in actor-relative coordinates
5767 * Every part of the actor outside the clip region will not be
5770 obj_props[PROP_CLIP] =
5771 g_param_spec_boxed ("clip",
5773 P_("The clip region for the actor"),
5774 CLUTTER_TYPE_GEOMETRY,
5775 CLUTTER_PARAM_READWRITE);
5778 * ClutterActor:name:
5780 * The name of the actor
5784 obj_props[PROP_NAME] =
5785 g_param_spec_string ("name",
5787 P_("Name of the actor"),
5789 CLUTTER_PARAM_READWRITE);
5792 * ClutterActor:scale-x:
5794 * The horizontal scale of the actor.
5796 * The #ClutterActor:scale-x property is animatable.
5800 obj_props[PROP_SCALE_X] =
5801 g_param_spec_double ("scale-x",
5803 P_("Scale factor on the X axis"),
5807 G_PARAM_STATIC_STRINGS |
5808 CLUTTER_PARAM_ANIMATABLE);
5811 * ClutterActor:scale-y:
5813 * The vertical scale of the actor.
5815 * The #ClutterActor:scale-y property is animatable.
5819 obj_props[PROP_SCALE_Y] =
5820 g_param_spec_double ("scale-y",
5822 P_("Scale factor on the Y axis"),
5826 G_PARAM_STATIC_STRINGS |
5827 CLUTTER_PARAM_ANIMATABLE);
5830 * ClutterActor:scale-center-x:
5832 * The horizontal center point for scaling
5836 obj_props[PROP_SCALE_CENTER_X] =
5837 g_param_spec_float ("scale-center-x",
5838 P_("Scale Center X"),
5839 P_("Horizontal scale center"),
5840 -G_MAXFLOAT, G_MAXFLOAT,
5842 CLUTTER_PARAM_READWRITE);
5845 * ClutterActor:scale-center-y:
5847 * The vertical center point for scaling
5851 obj_props[PROP_SCALE_CENTER_Y] =
5852 g_param_spec_float ("scale-center-y",
5853 P_("Scale Center Y"),
5854 P_("Vertical scale center"),
5855 -G_MAXFLOAT, G_MAXFLOAT,
5857 CLUTTER_PARAM_READWRITE);
5860 * ClutterActor:scale-gravity:
5862 * The center point for scaling expressed as a #ClutterGravity
5866 obj_props[PROP_SCALE_GRAVITY] =
5867 g_param_spec_enum ("scale-gravity",
5868 P_("Scale Gravity"),
5869 P_("The center of scaling"),
5870 CLUTTER_TYPE_GRAVITY,
5871 CLUTTER_GRAVITY_NONE,
5872 CLUTTER_PARAM_READWRITE);
5875 * ClutterActor:rotation-angle-x:
5877 * The rotation angle on the X axis.
5879 * The #ClutterActor:rotation-angle-x property is animatable.
5883 obj_props[PROP_ROTATION_ANGLE_X] =
5884 g_param_spec_double ("rotation-angle-x",
5885 P_("Rotation Angle X"),
5886 P_("The rotation angle on the X axis"),
5887 -G_MAXDOUBLE, G_MAXDOUBLE,
5890 G_PARAM_STATIC_STRINGS |
5891 CLUTTER_PARAM_ANIMATABLE);
5894 * ClutterActor:rotation-angle-y:
5896 * The rotation angle on the Y axis
5898 * The #ClutterActor:rotation-angle-y property is animatable.
5902 obj_props[PROP_ROTATION_ANGLE_Y] =
5903 g_param_spec_double ("rotation-angle-y",
5904 P_("Rotation Angle Y"),
5905 P_("The rotation angle on the Y axis"),
5906 -G_MAXDOUBLE, G_MAXDOUBLE,
5909 G_PARAM_STATIC_STRINGS |
5910 CLUTTER_PARAM_ANIMATABLE);
5913 * ClutterActor:rotation-angle-z:
5915 * The rotation angle on the Z axis
5917 * The #ClutterActor:rotation-angle-z property is animatable.
5921 obj_props[PROP_ROTATION_ANGLE_Z] =
5922 g_param_spec_double ("rotation-angle-z",
5923 P_("Rotation Angle Z"),
5924 P_("The rotation angle on the Z axis"),
5925 -G_MAXDOUBLE, G_MAXDOUBLE,
5928 G_PARAM_STATIC_STRINGS |
5929 CLUTTER_PARAM_ANIMATABLE);
5932 * ClutterActor:rotation-center-x:
5934 * The rotation center on the X axis.
5938 obj_props[PROP_ROTATION_CENTER_X] =
5939 g_param_spec_boxed ("rotation-center-x",
5940 P_("Rotation Center X"),
5941 P_("The rotation center on the X axis"),
5942 CLUTTER_TYPE_VERTEX,
5943 CLUTTER_PARAM_READWRITE);
5946 * ClutterActor:rotation-center-y:
5948 * The rotation center on the Y axis.
5952 obj_props[PROP_ROTATION_CENTER_Y] =
5953 g_param_spec_boxed ("rotation-center-y",
5954 P_("Rotation Center Y"),
5955 P_("The rotation center on the Y axis"),
5956 CLUTTER_TYPE_VERTEX,
5957 CLUTTER_PARAM_READWRITE);
5960 * ClutterActor:rotation-center-z:
5962 * The rotation center on the Z axis.
5966 obj_props[PROP_ROTATION_CENTER_Z] =
5967 g_param_spec_boxed ("rotation-center-z",
5968 P_("Rotation Center Z"),
5969 P_("The rotation center on the Z axis"),
5970 CLUTTER_TYPE_VERTEX,
5971 CLUTTER_PARAM_READWRITE);
5974 * ClutterActor:rotation-center-z-gravity:
5976 * The rotation center on the Z axis expressed as a #ClutterGravity.
5980 obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
5981 g_param_spec_enum ("rotation-center-z-gravity",
5982 P_("Rotation Center Z Gravity"),
5983 P_("Center point for rotation around the Z axis"),
5984 CLUTTER_TYPE_GRAVITY,
5985 CLUTTER_GRAVITY_NONE,
5986 CLUTTER_PARAM_READWRITE);
5989 * ClutterActor:anchor-x:
5991 * The X coordinate of an actor's anchor point, relative to
5992 * the actor coordinate space, in pixels
5996 obj_props[PROP_ANCHOR_X] =
5997 g_param_spec_float ("anchor-x",
5999 P_("X coordinate of the anchor point"),
6000 -G_MAXFLOAT, G_MAXFLOAT,
6002 CLUTTER_PARAM_READWRITE);
6005 * ClutterActor:anchor-y:
6007 * The Y coordinate of an actor's anchor point, relative to
6008 * the actor coordinate space, in pixels
6012 obj_props[PROP_ANCHOR_Y] =
6013 g_param_spec_float ("anchor-y",
6015 P_("Y coordinate of the anchor point"),
6016 -G_MAXFLOAT, G_MAXFLOAT,
6018 CLUTTER_PARAM_READWRITE);
6021 * ClutterActor:anchor-gravity:
6023 * The anchor point expressed as a #ClutterGravity
6027 obj_props[PROP_ANCHOR_GRAVITY] =
6028 g_param_spec_enum ("anchor-gravity",
6029 P_("Anchor Gravity"),
6030 P_("The anchor point as a ClutterGravity"),
6031 CLUTTER_TYPE_GRAVITY,
6032 CLUTTER_GRAVITY_NONE,
6033 CLUTTER_PARAM_READWRITE);
6036 * ClutterActor:show-on-set-parent:
6038 * If %TRUE, the actor is automatically shown when parented.
6040 * Calling clutter_actor_hide() on an actor which has not been
6041 * parented will set this property to %FALSE as a side effect.
6045 obj_props[PROP_SHOW_ON_SET_PARENT] =
6046 g_param_spec_boolean ("show-on-set-parent",
6047 P_("Show on set parent"),
6048 P_("Whether the actor is shown when parented"),
6050 CLUTTER_PARAM_READWRITE);
6053 * ClutterActor:clip-to-allocation:
6055 * Whether the clip region should track the allocated area
6058 * This property is ignored if a clip area has been explicitly
6059 * set using clutter_actor_set_clip().
6063 obj_props[PROP_CLIP_TO_ALLOCATION] =
6064 g_param_spec_boolean ("clip-to-allocation",
6065 P_("Clip to Allocation"),
6066 P_("Sets the clip region to track the actor's allocation"),
6068 CLUTTER_PARAM_READWRITE);
6071 * ClutterActor:text-direction:
6073 * The direction of the text inside a #ClutterActor.
6077 obj_props[PROP_TEXT_DIRECTION] =
6078 g_param_spec_enum ("text-direction",
6079 P_("Text Direction"),
6080 P_("Direction of the text"),
6081 CLUTTER_TYPE_TEXT_DIRECTION,
6082 CLUTTER_TEXT_DIRECTION_LTR,
6083 CLUTTER_PARAM_READWRITE);
6086 * ClutterActor:has-pointer:
6088 * Whether the actor contains the pointer of a #ClutterInputDevice
6093 obj_props[PROP_HAS_POINTER] =
6094 g_param_spec_boolean ("has-pointer",
6096 P_("Whether the actor contains the pointer of an input device"),
6098 CLUTTER_PARAM_READABLE);
6101 * ClutterActor:actions:
6103 * Adds a #ClutterAction to the actor
6107 obj_props[PROP_ACTIONS] =
6108 g_param_spec_object ("actions",
6110 P_("Adds an action to the actor"),
6111 CLUTTER_TYPE_ACTION,
6112 CLUTTER_PARAM_WRITABLE);
6115 * ClutterActor:constraints:
6117 * Adds a #ClutterConstraint to the actor
6121 obj_props[PROP_CONSTRAINTS] =
6122 g_param_spec_object ("constraints",
6124 P_("Adds a constraint to the actor"),
6125 CLUTTER_TYPE_CONSTRAINT,
6126 CLUTTER_PARAM_WRITABLE);
6129 * ClutterActor:effect:
6131 * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6135 obj_props[PROP_EFFECT] =
6136 g_param_spec_object ("effect",
6138 P_("Add an effect to be applied on the actor"),
6139 CLUTTER_TYPE_EFFECT,
6140 CLUTTER_PARAM_WRITABLE);
6143 * ClutterActor:layout-manager:
6145 * A delegate object for controlling the layout of the children of
6150 obj_props[PROP_LAYOUT_MANAGER] =
6151 g_param_spec_object ("layout-manager",
6152 P_("Layout Manager"),
6153 P_("The object controlling the layout of an actor's children"),
6154 CLUTTER_TYPE_LAYOUT_MANAGER,
6155 CLUTTER_PARAM_READWRITE);
6159 * ClutterActor:x-align:
6161 * The alignment of an actor on the X axis, if the actor has been given
6162 * extra space for its allocation.
6166 obj_props[PROP_X_ALIGN] =
6167 g_param_spec_enum ("x-align",
6169 P_("The alignment of the actor on the X axis within its allocation"),
6170 CLUTTER_TYPE_ACTOR_ALIGN,
6171 CLUTTER_ACTOR_ALIGN_FILL,
6172 CLUTTER_PARAM_READWRITE);
6175 * ClutterActor:y-align:
6177 * The alignment of an actor on the Y axis, if the actor has been given
6178 * extra space for its allocation.
6182 obj_props[PROP_Y_ALIGN] =
6183 g_param_spec_enum ("y-align",
6185 P_("The alignment of the actor on the Y axis within its allocation"),
6186 CLUTTER_TYPE_ACTOR_ALIGN,
6187 CLUTTER_ACTOR_ALIGN_FILL,
6188 CLUTTER_PARAM_READWRITE);
6191 * ClutterActor:margin-top:
6193 * The margin (in pixels) from the top of the actor.
6195 * This property adds a margin to the actor's preferred size; the margin
6196 * will be automatically taken into account when allocating the actor.
6200 obj_props[PROP_MARGIN_TOP] =
6201 g_param_spec_float ("margin-top",
6203 P_("Extra space at the top"),
6206 CLUTTER_PARAM_READWRITE);
6209 * ClutterActor:margin-bottom:
6211 * The margin (in pixels) from the bottom of the actor.
6213 * This property adds a margin to the actor's preferred size; the margin
6214 * will be automatically taken into account when allocating the actor.
6218 obj_props[PROP_MARGIN_BOTTOM] =
6219 g_param_spec_float ("margin-bottom",
6220 P_("Margin Bottom"),
6221 P_("Extra space at the bottom"),
6224 CLUTTER_PARAM_READWRITE);
6227 * ClutterActor:margin-left:
6229 * The margin (in pixels) from the left of the actor.
6231 * This property adds a margin to the actor's preferred size; the margin
6232 * will be automatically taken into account when allocating the actor.
6236 obj_props[PROP_MARGIN_LEFT] =
6237 g_param_spec_float ("margin-left",
6239 P_("Extra space at the left"),
6242 CLUTTER_PARAM_READWRITE);
6245 * ClutterActor:margin-right:
6247 * The margin (in pixels) from the right of the actor.
6249 * This property adds a margin to the actor's preferred size; the margin
6250 * will be automatically taken into account when allocating the actor.
6254 obj_props[PROP_MARGIN_RIGHT] =
6255 g_param_spec_float ("margin-right",
6257 P_("Extra space at the right"),
6260 CLUTTER_PARAM_READWRITE);
6263 * ClutterActor:background-color-set:
6265 * Whether the #ClutterActor:background-color property has been set.
6269 obj_props[PROP_BACKGROUND_COLOR_SET] =
6270 g_param_spec_boolean ("background-color-set",
6271 P_("Background Color Set"),
6272 P_("Whether the background color is set"),
6274 CLUTTER_PARAM_READABLE);
6277 * ClutterActor:background-color:
6279 * Paints a solid fill of the actor's allocation using the specified
6282 * The #ClutterActor:background-color property is animatable.
6286 obj_props[PROP_BACKGROUND_COLOR] =
6287 clutter_param_spec_color ("background-color",
6288 P_("Background color"),
6289 P_("The actor's background color"),
6290 CLUTTER_COLOR_Transparent,
6292 G_PARAM_STATIC_STRINGS |
6293 CLUTTER_PARAM_ANIMATABLE);
6296 * ClutterActor:first-child:
6298 * The actor's first child.
6302 obj_props[PROP_FIRST_CHILD] =
6303 g_param_spec_object ("first-child",
6305 P_("The actor's first child"),
6307 CLUTTER_PARAM_READABLE);
6310 * ClutterActor:last-child:
6312 * The actor's last child.
6316 obj_props[PROP_LAST_CHILD] =
6317 g_param_spec_object ("last-child",
6319 P_("The actor's last child"),
6321 CLUTTER_PARAM_READABLE);
6324 * ClutterActor:content:
6326 * The #ClutterContent implementation that controls the content
6331 obj_props[PROP_CONTENT] =
6332 g_param_spec_object ("content",
6334 P_("Delegate object for painting the actor's content"),
6335 CLUTTER_TYPE_CONTENT,
6336 CLUTTER_PARAM_READWRITE);
6339 * ClutterActor:content-gravity:
6341 * The alignment that should be honoured by the #ClutterContent
6342 * set with the #ClutterActor:content property.
6344 * Changing the value of this property will change the bounding box of
6345 * the content; you can use the #ClutterActor:content-box property to
6346 * get the position and size of the content within the actor's
6349 * This property is meaningful only for #ClutterContent implementations
6350 * that have a preferred size, and if the preferred size is smaller than
6351 * the actor's allocation.
6355 obj_props[PROP_CONTENT_GRAVITY] =
6356 g_param_spec_enum ("content-gravity",
6357 P_("Content Gravity"),
6358 P_("Alignment of the actor's content"),
6359 CLUTTER_TYPE_CONTENT_GRAVITY,
6360 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6361 CLUTTER_PARAM_READWRITE);
6364 * ClutterActor:content-box:
6366 * The bounding box for the #ClutterContent used by the actor.
6368 * The value of this property is controlled by the #ClutterActor:allocation
6369 * and #ClutterActor:content-gravity properties of #ClutterActor.
6371 * The bounding box for the content is guaranteed to never exceed the
6372 * allocation's of the actor.
6376 obj_props[PROP_CONTENT_BOX] =
6377 g_param_spec_boxed ("content-box",
6379 P_("The bounding box of the actor's content"),
6380 CLUTTER_TYPE_ACTOR_BOX,
6381 CLUTTER_PARAM_READABLE);
6383 obj_props[PROP_MINIFICATION_FILTER] =
6384 g_param_spec_enum ("minification-filter",
6385 P_("Minification Filter"),
6386 P_("The filter used when reducing the size of the content"),
6387 CLUTTER_TYPE_SCALING_FILTER,
6388 CLUTTER_SCALING_FILTER_LINEAR,
6389 CLUTTER_PARAM_READWRITE);
6391 obj_props[PROP_MAGNIFICATION_FILTER] =
6392 g_param_spec_enum ("magnification-filter",
6393 P_("Magnification Filter"),
6394 P_("The filter used when increasing the size of the content"),
6395 CLUTTER_TYPE_SCALING_FILTER,
6396 CLUTTER_SCALING_FILTER_LINEAR,
6397 CLUTTER_PARAM_READWRITE);
6399 g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6402 * ClutterActor::destroy:
6403 * @actor: the #ClutterActor which emitted the signal
6405 * The ::destroy signal notifies that all references held on the
6406 * actor which emitted it should be released.
6408 * The ::destroy signal should be used by all holders of a reference
6411 * This signal might result in the finalization of the #ClutterActor
6412 * if all references are released.
6414 * Composite actors and actors implementing the #ClutterContainer
6415 * interface should override the default implementation of the
6416 * class handler of this signal and call clutter_actor_destroy() on
6417 * their children. When overriding the default class handler, it is
6418 * required to chain up to the parent's implementation.
6422 actor_signals[DESTROY] =
6423 g_signal_new (I_("destroy"),
6424 G_TYPE_FROM_CLASS (object_class),
6425 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6426 G_STRUCT_OFFSET (ClutterActorClass, destroy),
6428 _clutter_marshal_VOID__VOID,
6431 * ClutterActor::show:
6432 * @actor: the object which received the signal
6434 * The ::show signal is emitted when an actor is visible and
6435 * rendered on the stage.
6439 actor_signals[SHOW] =
6440 g_signal_new (I_("show"),
6441 G_TYPE_FROM_CLASS (object_class),
6443 G_STRUCT_OFFSET (ClutterActorClass, show),
6445 _clutter_marshal_VOID__VOID,
6448 * ClutterActor::hide:
6449 * @actor: the object which received the signal
6451 * The ::hide signal is emitted when an actor is no longer rendered
6456 actor_signals[HIDE] =
6457 g_signal_new (I_("hide"),
6458 G_TYPE_FROM_CLASS (object_class),
6460 G_STRUCT_OFFSET (ClutterActorClass, hide),
6462 _clutter_marshal_VOID__VOID,
6465 * ClutterActor::parent-set:
6466 * @actor: the object which received the signal
6467 * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6469 * This signal is emitted when the parent of the actor changes.
6473 actor_signals[PARENT_SET] =
6474 g_signal_new (I_("parent-set"),
6475 G_TYPE_FROM_CLASS (object_class),
6477 G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6479 _clutter_marshal_VOID__OBJECT,
6481 CLUTTER_TYPE_ACTOR);
6484 * ClutterActor::queue-redraw:
6485 * @actor: the actor we're bubbling the redraw request through
6486 * @origin: the actor which initiated the redraw request
6488 * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6489 * is called on @origin.
6491 * The default implementation for #ClutterActor chains up to the
6492 * parent actor and queues a redraw on the parent, thus "bubbling"
6493 * the redraw queue up through the actor graph. The default
6494 * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6495 * in a main loop idle handler.
6497 * Note that the @origin actor may be the stage, or a container; it
6498 * does not have to be a leaf node in the actor graph.
6500 * Toolkits embedding a #ClutterStage which require a redraw and
6501 * relayout cycle can stop the emission of this signal using the
6502 * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6507 * on_redraw_complete (gpointer data)
6509 * ClutterStage *stage = data;
6511 * /* execute the Clutter drawing pipeline */
6512 * clutter_stage_ensure_redraw (stage);
6516 * on_stage_queue_redraw (ClutterStage *stage)
6518 * /* this prevents the default handler to run */
6519 * g_signal_stop_emission_by_name (stage, "queue-redraw");
6521 * /* queue a redraw with the host toolkit and call
6522 * * a function when the redraw has been completed
6524 * queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6528 * <note><para>This signal is emitted before the Clutter paint
6529 * pipeline is executed. If you want to know when the pipeline has
6530 * been completed you should connect to the ::paint signal on the
6531 * Stage with g_signal_connect_after().</para></note>
6535 actor_signals[QUEUE_REDRAW] =
6536 g_signal_new (I_("queue-redraw"),
6537 G_TYPE_FROM_CLASS (object_class),
6540 G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6542 _clutter_marshal_VOID__OBJECT,
6544 CLUTTER_TYPE_ACTOR);
6547 * ClutterActor::queue-relayout
6548 * @actor: the actor being queued for relayout
6550 * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6551 * is called on an actor.
6553 * The default implementation for #ClutterActor chains up to the
6554 * parent actor and queues a relayout on the parent, thus "bubbling"
6555 * the relayout queue up through the actor graph.
6557 * The main purpose of this signal is to allow relayout to be propagated
6558 * properly in the procense of #ClutterClone actors. Applications will
6559 * not normally need to connect to this signal.
6563 actor_signals[QUEUE_RELAYOUT] =
6564 g_signal_new (I_("queue-relayout"),
6565 G_TYPE_FROM_CLASS (object_class),
6568 G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6570 _clutter_marshal_VOID__VOID,
6574 * ClutterActor::event:
6575 * @actor: the actor which received the event
6576 * @event: a #ClutterEvent
6578 * The ::event signal is emitted each time an event is received
6579 * by the @actor. This signal will be emitted on every actor,
6580 * following the hierarchy chain, until it reaches the top-level
6581 * container (the #ClutterStage).
6583 * Return value: %TRUE if the event has been handled by the actor,
6584 * or %FALSE to continue the emission.
6588 actor_signals[EVENT] =
6589 g_signal_new (I_("event"),
6590 G_TYPE_FROM_CLASS (object_class),
6592 G_STRUCT_OFFSET (ClutterActorClass, event),
6593 _clutter_boolean_handled_accumulator, NULL,
6594 _clutter_marshal_BOOLEAN__BOXED,
6596 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6598 * ClutterActor::button-press-event:
6599 * @actor: the actor which received the event
6600 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6602 * The ::button-press-event signal is emitted each time a mouse button
6603 * is pressed on @actor.
6605 * Return value: %TRUE if the event has been handled by the actor,
6606 * or %FALSE to continue the emission.
6610 actor_signals[BUTTON_PRESS_EVENT] =
6611 g_signal_new (I_("button-press-event"),
6612 G_TYPE_FROM_CLASS (object_class),
6614 G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6615 _clutter_boolean_handled_accumulator, NULL,
6616 _clutter_marshal_BOOLEAN__BOXED,
6618 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6620 * ClutterActor::button-release-event:
6621 * @actor: the actor which received the event
6622 * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6624 * The ::button-release-event signal is emitted each time a mouse button
6625 * is released on @actor.
6627 * Return value: %TRUE if the event has been handled by the actor,
6628 * or %FALSE to continue the emission.
6632 actor_signals[BUTTON_RELEASE_EVENT] =
6633 g_signal_new (I_("button-release-event"),
6634 G_TYPE_FROM_CLASS (object_class),
6636 G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6637 _clutter_boolean_handled_accumulator, NULL,
6638 _clutter_marshal_BOOLEAN__BOXED,
6640 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6642 * ClutterActor::scroll-event:
6643 * @actor: the actor which received the event
6644 * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6646 * The ::scroll-event signal is emitted each time the mouse is
6647 * scrolled on @actor
6649 * Return value: %TRUE if the event has been handled by the actor,
6650 * or %FALSE to continue the emission.
6654 actor_signals[SCROLL_EVENT] =
6655 g_signal_new (I_("scroll-event"),
6656 G_TYPE_FROM_CLASS (object_class),
6658 G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6659 _clutter_boolean_handled_accumulator, NULL,
6660 _clutter_marshal_BOOLEAN__BOXED,
6662 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6664 * ClutterActor::key-press-event:
6665 * @actor: the actor which received the event
6666 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6668 * The ::key-press-event signal is emitted each time a keyboard button
6669 * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6671 * Return value: %TRUE if the event has been handled by the actor,
6672 * or %FALSE to continue the emission.
6676 actor_signals[KEY_PRESS_EVENT] =
6677 g_signal_new (I_("key-press-event"),
6678 G_TYPE_FROM_CLASS (object_class),
6680 G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6681 _clutter_boolean_handled_accumulator, NULL,
6682 _clutter_marshal_BOOLEAN__BOXED,
6684 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6686 * ClutterActor::key-release-event:
6687 * @actor: the actor which received the event
6688 * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6690 * The ::key-release-event signal is emitted each time a keyboard button
6691 * is released while @actor has key focus (see
6692 * clutter_stage_set_key_focus()).
6694 * Return value: %TRUE if the event has been handled by the actor,
6695 * or %FALSE to continue the emission.
6699 actor_signals[KEY_RELEASE_EVENT] =
6700 g_signal_new (I_("key-release-event"),
6701 G_TYPE_FROM_CLASS (object_class),
6703 G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6704 _clutter_boolean_handled_accumulator, NULL,
6705 _clutter_marshal_BOOLEAN__BOXED,
6707 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6709 * ClutterActor::motion-event:
6710 * @actor: the actor which received the event
6711 * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6713 * The ::motion-event signal is emitted each time the mouse pointer is
6714 * moved over @actor.
6716 * Return value: %TRUE if the event has been handled by the actor,
6717 * or %FALSE to continue the emission.
6721 actor_signals[MOTION_EVENT] =
6722 g_signal_new (I_("motion-event"),
6723 G_TYPE_FROM_CLASS (object_class),
6725 G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6726 _clutter_boolean_handled_accumulator, NULL,
6727 _clutter_marshal_BOOLEAN__BOXED,
6729 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6732 * ClutterActor::key-focus-in:
6733 * @actor: the actor which now has key focus
6735 * The ::key-focus-in signal is emitted when @actor receives key focus.
6739 actor_signals[KEY_FOCUS_IN] =
6740 g_signal_new (I_("key-focus-in"),
6741 G_TYPE_FROM_CLASS (object_class),
6743 G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6745 _clutter_marshal_VOID__VOID,
6749 * ClutterActor::key-focus-out:
6750 * @actor: the actor which now has key focus
6752 * The ::key-focus-out signal is emitted when @actor loses key focus.
6756 actor_signals[KEY_FOCUS_OUT] =
6757 g_signal_new (I_("key-focus-out"),
6758 G_TYPE_FROM_CLASS (object_class),
6760 G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6762 _clutter_marshal_VOID__VOID,
6766 * ClutterActor::enter-event:
6767 * @actor: the actor which the pointer has entered.
6768 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6770 * The ::enter-event signal is emitted when the pointer enters the @actor
6772 * Return value: %TRUE if the event has been handled by the actor,
6773 * or %FALSE to continue the emission.
6777 actor_signals[ENTER_EVENT] =
6778 g_signal_new (I_("enter-event"),
6779 G_TYPE_FROM_CLASS (object_class),
6781 G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6782 _clutter_boolean_handled_accumulator, NULL,
6783 _clutter_marshal_BOOLEAN__BOXED,
6785 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6788 * ClutterActor::leave-event:
6789 * @actor: the actor which the pointer has left
6790 * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6792 * The ::leave-event signal is emitted when the pointer leaves the @actor.
6794 * Return value: %TRUE if the event has been handled by the actor,
6795 * or %FALSE to continue the emission.
6799 actor_signals[LEAVE_EVENT] =
6800 g_signal_new (I_("leave-event"),
6801 G_TYPE_FROM_CLASS (object_class),
6803 G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6804 _clutter_boolean_handled_accumulator, NULL,
6805 _clutter_marshal_BOOLEAN__BOXED,
6807 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6810 * ClutterActor::captured-event:
6811 * @actor: the actor which received the signal
6812 * @event: a #ClutterEvent
6814 * The ::captured-event signal is emitted when an event is captured
6815 * by Clutter. This signal will be emitted starting from the top-level
6816 * container (the #ClutterStage) to the actor which received the event
6817 * going down the hierarchy. This signal can be used to intercept every
6818 * event before the specialized events (like
6819 * ClutterActor::button-press-event or ::key-released-event) are
6822 * Return value: %TRUE if the event has been handled by the actor,
6823 * or %FALSE to continue the emission.
6827 actor_signals[CAPTURED_EVENT] =
6828 g_signal_new (I_("captured-event"),
6829 G_TYPE_FROM_CLASS (object_class),
6831 G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6832 _clutter_boolean_handled_accumulator, NULL,
6833 _clutter_marshal_BOOLEAN__BOXED,
6835 CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6838 * ClutterActor::paint:
6839 * @actor: the #ClutterActor that received the signal
6841 * The ::paint signal is emitted each time an actor is being painted.
6843 * Subclasses of #ClutterActor should override the class signal handler
6844 * and paint themselves in that function.
6846 * It is possible to connect a handler to the ::paint signal in order
6847 * to set up some custom aspect of a paint.
6851 actor_signals[PAINT] =
6852 g_signal_new (I_("paint"),
6853 G_TYPE_FROM_CLASS (object_class),
6856 G_STRUCT_OFFSET (ClutterActorClass, paint),
6858 _clutter_marshal_VOID__VOID,
6861 * ClutterActor::realize:
6862 * @actor: the #ClutterActor that received the signal
6864 * The ::realize signal is emitted each time an actor is being
6869 actor_signals[REALIZE] =
6870 g_signal_new (I_("realize"),
6871 G_TYPE_FROM_CLASS (object_class),
6873 G_STRUCT_OFFSET (ClutterActorClass, realize),
6875 _clutter_marshal_VOID__VOID,
6878 * ClutterActor::unrealize:
6879 * @actor: the #ClutterActor that received the signal
6881 * The ::unrealize signal is emitted each time an actor is being
6886 actor_signals[UNREALIZE] =
6887 g_signal_new (I_("unrealize"),
6888 G_TYPE_FROM_CLASS (object_class),
6890 G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6892 _clutter_marshal_VOID__VOID,
6896 * ClutterActor::pick:
6897 * @actor: the #ClutterActor that received the signal
6898 * @color: the #ClutterColor to be used when picking
6900 * The ::pick signal is emitted each time an actor is being painted
6901 * in "pick mode". The pick mode is used to identify the actor during
6902 * the event handling phase, or by clutter_stage_get_actor_at_pos().
6903 * The actor should paint its shape using the passed @pick_color.
6905 * Subclasses of #ClutterActor should override the class signal handler
6906 * and paint themselves in that function.
6908 * It is possible to connect a handler to the ::pick signal in order
6909 * to set up some custom aspect of a paint in pick mode.
6913 actor_signals[PICK] =
6914 g_signal_new (I_("pick"),
6915 G_TYPE_FROM_CLASS (object_class),
6917 G_STRUCT_OFFSET (ClutterActorClass, pick),
6919 _clutter_marshal_VOID__BOXED,
6921 CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
6924 * ClutterActor::allocation-changed:
6925 * @actor: the #ClutterActor that emitted the signal
6926 * @box: a #ClutterActorBox with the new allocation
6927 * @flags: #ClutterAllocationFlags for the allocation
6929 * The ::allocation-changed signal is emitted when the
6930 * #ClutterActor:allocation property changes. Usually, application
6931 * code should just use the notifications for the :allocation property
6932 * but if you want to track the allocation flags as well, for instance
6933 * to know whether the absolute origin of @actor changed, then you might
6934 * want use this signal instead.
6938 actor_signals[ALLOCATION_CHANGED] =
6939 g_signal_new (I_("allocation-changed"),
6940 G_TYPE_FROM_CLASS (object_class),
6944 _clutter_marshal_VOID__BOXED_FLAGS,
6946 CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
6947 CLUTTER_TYPE_ALLOCATION_FLAGS);
6951 clutter_actor_init (ClutterActor *self)
6953 ClutterActorPrivate *priv;
6955 self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
6957 priv->id = _clutter_context_acquire_id (self);
6960 priv->opacity = 0xff;
6961 priv->show_on_set_parent = TRUE;
6963 priv->needs_width_request = TRUE;
6964 priv->needs_height_request = TRUE;
6965 priv->needs_allocation = TRUE;
6967 priv->cached_width_age = 1;
6968 priv->cached_height_age = 1;
6970 priv->opacity_override = -1;
6971 priv->enable_model_view_transform = TRUE;
6973 /* Initialize an empty paint volume to start with */
6974 _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
6975 priv->last_paint_volume_valid = TRUE;
6977 priv->transform_valid = FALSE;
6979 /* the default is to stretch the content, to match the
6980 * current behaviour of basically all actors. also, it's
6981 * the easiest thing to compute.
6983 priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
6984 priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
6985 priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
6989 * clutter_actor_new:
6991 * Creates a new #ClutterActor.
6993 * A newly created actor has a floating reference, which will be sunk
6994 * when it is added to another actor.
6996 * Return value: (transfer full): the newly created #ClutterActor
7001 clutter_actor_new (void)
7003 return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7007 * clutter_actor_destroy:
7008 * @self: a #ClutterActor
7010 * Destroys an actor. When an actor is destroyed, it will break any
7011 * references it holds to other objects. If the actor is inside a
7012 * container, the actor will be removed.
7014 * When you destroy a container, its children will be destroyed as well.
7016 * Note: you cannot destroy the #ClutterStage returned by
7017 * clutter_stage_get_default().
7020 clutter_actor_destroy (ClutterActor *self)
7022 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7024 g_object_ref (self);
7026 /* avoid recursion while destroying */
7027 if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7029 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7031 g_object_run_dispose (G_OBJECT (self));
7033 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7036 g_object_unref (self);
7040 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7041 ClutterPaintVolume *clip)
7043 ClutterActorPrivate *priv = self->priv;
7044 ClutterPaintVolume *pv;
7047 /* Remove queue entry early in the process, otherwise a new
7048 queue_redraw() during signal handling could put back this
7049 object in the stage redraw list (but the entry is freed as
7050 soon as we return from this function, causing a segfault
7053 priv->queue_redraw_entry = NULL;
7055 /* If we've been explicitly passed a clip volume then there's
7056 * nothing more to calculate, but otherwise the only thing we know
7057 * is that the change is constrained to the given actor.
7059 * The idea is that if we know the paint volume for where the actor
7060 * was last drawn (in eye coordinates) and we also have the paint
7061 * volume for where it will be drawn next (in actor coordinates)
7062 * then if we queue a redraw for both these volumes that will cover
7063 * everything that needs to be redrawn to clear the old view and
7064 * show the latest view of the actor.
7066 * Don't clip this redraw if we don't know what position we had for
7067 * the previous redraw since we don't know where to set the clip so
7068 * it will clear the actor as it is currently.
7072 _clutter_actor_set_queue_redraw_clip (self, clip);
7075 else if (G_LIKELY (priv->last_paint_volume_valid))
7077 pv = _clutter_actor_get_paint_volume_mutable (self);
7080 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7082 /* make sure we redraw the actors old position... */
7083 _clutter_actor_set_queue_redraw_clip (stage,
7084 &priv->last_paint_volume);
7085 _clutter_actor_signal_queue_redraw (stage, stage);
7086 _clutter_actor_set_queue_redraw_clip (stage, NULL);
7088 /* XXX: Ideally the redraw signal would take a clip volume
7089 * argument, but that would be an ABI break. Until we can
7090 * break the ABI we pass the argument out-of-band
7093 /* setup the clip for the actors new position... */
7094 _clutter_actor_set_queue_redraw_clip (self, pv);
7103 _clutter_actor_signal_queue_redraw (self, self);
7105 /* Just in case anyone is manually firing redraw signals without
7106 * using the public queue_redraw() API we are careful to ensure that
7107 * our out-of-band clip member is cleared before returning...
7109 * Note: A NULL clip denotes a full-stage, un-clipped redraw
7111 if (G_LIKELY (clipped))
7112 _clutter_actor_set_queue_redraw_clip (self, NULL);
7116 _clutter_actor_get_allocation_clip (ClutterActor *self,
7117 ClutterActorBox *clip)
7119 ClutterActorBox allocation;
7121 /* XXX: we don't care if we get an out of date allocation here
7122 * because clutter_actor_queue_redraw_with_clip knows to ignore
7123 * the clip if the actor's allocation is invalid.
7125 * This is noted because clutter_actor_get_allocation_box does some
7126 * unnecessary work to support buggy code with a comment suggesting
7127 * that it could be changed later which would be good for this use
7130 clutter_actor_get_allocation_box (self, &allocation);
7132 /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7133 * actor's own coordinate space but the allocation is in parent
7137 clip->x2 = allocation.x2 - allocation.x1;
7138 clip->y2 = allocation.y2 - allocation.y1;
7142 _clutter_actor_queue_redraw_full (ClutterActor *self,
7143 ClutterRedrawFlags flags,
7144 ClutterPaintVolume *volume,
7145 ClutterEffect *effect)
7147 ClutterActorPrivate *priv = self->priv;
7148 ClutterPaintVolume allocation_pv;
7149 ClutterPaintVolume *pv;
7150 gboolean should_free_pv;
7151 ClutterActor *stage;
7153 /* Here's an outline of the actor queue redraw mechanism:
7155 * The process starts in one of the following two functions which
7156 * are wrappers for this function:
7157 * clutter_actor_queue_redraw
7158 * _clutter_actor_queue_redraw_with_clip
7160 * additionally, an effect can queue a redraw by wrapping this
7161 * function in clutter_effect_queue_rerun
7163 * This functions queues an entry in a list associated with the
7164 * stage which is a list of actors that queued a redraw while
7165 * updating the timelines, performing layouting and processing other
7166 * mainloop sources before the next paint starts.
7168 * We aim to minimize the processing done at this point because
7169 * there is a good chance other events will happen while updating
7170 * the scenegraph that would invalidate any expensive work we might
7171 * otherwise try to do here. For example we don't try and resolve
7172 * the screen space bounding box of an actor at this stage so as to
7173 * minimize how much of the screen redraw because it's possible
7174 * something else will happen which will force a full redraw anyway.
7176 * When all updates are complete and we come to paint the stage then
7177 * we iterate this list and actually emit the "queue-redraw" signals
7178 * for each of the listed actors which will bubble up to the stage
7179 * for each actor and at that point we will transform the actors
7180 * paint volume into screen coordinates to determine the clip region
7181 * for what needs to be redrawn in the next paint.
7183 * Besides minimizing redundant work another reason for this
7184 * deferred design is that it's more likely we will be able to
7185 * determine the paint volume of an actor once we've finished
7186 * updating the scenegraph because its allocation should be up to
7187 * date. NB: If we can't determine an actors paint volume then we
7188 * can't automatically queue a clipped redraw which can make a big
7189 * difference to performance.
7191 * So the control flow goes like this:
7192 * One of clutter_actor_queue_redraw,
7193 * _clutter_actor_queue_redraw_with_clip
7194 * or clutter_effect_queue_rerun
7196 * then control moves to:
7197 * _clutter_stage_queue_actor_redraw
7199 * later during _clutter_stage_do_update, once relayouting is done
7200 * and the scenegraph has been updated we will call:
7201 * _clutter_stage_finish_queue_redraws
7203 * _clutter_stage_finish_queue_redraws will call
7204 * _clutter_actor_finish_queue_redraw for each listed actor.
7205 * Note: actors *are* allowed to queue further redraws during this
7206 * process (considering clone actors or texture_new_from_actor which
7207 * respond to their source queueing a redraw by queuing a redraw
7208 * themselves). We repeat the process until the list is empty.
7210 * This will result in the "queue-redraw" signal being fired for
7211 * each actor which will pass control to the default signal handler:
7212 * clutter_actor_real_queue_redraw
7214 * This will bubble up to the stages handler:
7215 * clutter_stage_real_queue_redraw
7217 * clutter_stage_real_queue_redraw will transform the actors paint
7218 * volume into screen space and add it as a clip region for the next
7222 /* ignore queueing a redraw for actors being destroyed */
7223 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7226 stage = _clutter_actor_get_stage_internal (self);
7228 /* Ignore queueing a redraw for actors not descended from a stage */
7232 /* ignore queueing a redraw on stages that are being destroyed */
7233 if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7236 if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7238 ClutterActorBox allocation_clip;
7239 ClutterVertex origin;
7241 /* If the actor doesn't have a valid allocation then we will
7242 * queue a full stage redraw. */
7243 if (priv->needs_allocation)
7245 /* NB: NULL denotes an undefined clip which will result in a
7247 _clutter_actor_set_queue_redraw_clip (self, NULL);
7248 _clutter_actor_signal_queue_redraw (self, self);
7252 _clutter_paint_volume_init_static (&allocation_pv, self);
7253 pv = &allocation_pv;
7255 _clutter_actor_get_allocation_clip (self, &allocation_clip);
7257 origin.x = allocation_clip.x1;
7258 origin.y = allocation_clip.y1;
7260 clutter_paint_volume_set_origin (pv, &origin);
7261 clutter_paint_volume_set_width (pv,
7262 allocation_clip.x2 - allocation_clip.x1);
7263 clutter_paint_volume_set_height (pv,
7264 allocation_clip.y2 -
7265 allocation_clip.y1);
7266 should_free_pv = TRUE;
7271 should_free_pv = FALSE;
7274 self->priv->queue_redraw_entry =
7275 _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7276 priv->queue_redraw_entry,
7281 clutter_paint_volume_free (pv);
7283 /* If this is the first redraw queued then we can directly use the
7285 if (!priv->is_dirty)
7286 priv->effect_to_redraw = effect;
7287 /* Otherwise we need to merge it with the existing effect parameter */
7288 else if (effect != NULL)
7290 /* If there's already an effect then we need to use whichever is
7291 later in the chain of actors. Otherwise a full redraw has
7292 already been queued on the actor so we need to ignore the
7294 if (priv->effect_to_redraw != NULL)
7296 if (priv->effects == NULL)
7297 g_warning ("Redraw queued with an effect that is "
7298 "not applied to the actor");
7303 for (l = _clutter_meta_group_peek_metas (priv->effects);
7307 if (l->data == priv->effect_to_redraw ||
7309 priv->effect_to_redraw = l->data;
7316 /* If no effect is specified then we need to redraw the whole
7318 priv->effect_to_redraw = NULL;
7321 priv->is_dirty = TRUE;
7325 * clutter_actor_queue_redraw:
7326 * @self: A #ClutterActor
7328 * Queues up a redraw of an actor and any children. The redraw occurs
7329 * once the main loop becomes idle (after the current batch of events
7330 * has been processed, roughly).
7332 * Applications rarely need to call this, as redraws are handled
7333 * automatically by modification functions.
7335 * This function will not do anything if @self is not visible, or
7336 * if the actor is inside an invisible part of the scenegraph.
7338 * Also be aware that painting is a NOP for actors with an opacity of
7341 * When you are implementing a custom actor you must queue a redraw
7342 * whenever some private state changes that will affect painting or
7343 * picking of your actor.
7346 clutter_actor_queue_redraw (ClutterActor *self)
7348 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7350 _clutter_actor_queue_redraw_full (self,
7352 NULL, /* clip volume */
7357 * _clutter_actor_queue_redraw_with_clip:
7358 * @self: A #ClutterActor
7359 * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7360 * this queue redraw.
7361 * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7362 * redrawn or %NULL if you are just using a @flag to state your
7365 * Queues up a clipped redraw of an actor and any children. The redraw
7366 * occurs once the main loop becomes idle (after the current batch of
7367 * events has been processed, roughly).
7369 * If no flags are given the clip volume is defined by @volume
7370 * specified in actor coordinates and tells Clutter that only content
7371 * within this volume has been changed so Clutter can optionally
7372 * optimize the redraw.
7374 * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7375 * should be %NULL and this tells Clutter to use the actor's current
7376 * allocation as a clip box. This flag can only be used for 2D actors,
7377 * because any actor with depth may be projected outside its
7380 * Applications rarely need to call this, as redraws are handled
7381 * automatically by modification functions.
7383 * This function will not do anything if @self is not visible, or if
7384 * the actor is inside an invisible part of the scenegraph.
7386 * Also be aware that painting is a NOP for actors with an opacity of
7389 * When you are implementing a custom actor you must queue a redraw
7390 * whenever some private state changes that will affect painting or
7391 * picking of your actor.
7394 _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7395 ClutterRedrawFlags flags,
7396 ClutterPaintVolume *volume)
7398 _clutter_actor_queue_redraw_full (self,
7400 volume, /* clip volume */
7405 _clutter_actor_queue_only_relayout (ClutterActor *self)
7407 ClutterActorPrivate *priv = self->priv;
7409 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7412 if (priv->needs_width_request &&
7413 priv->needs_height_request &&
7414 priv->needs_allocation)
7415 return; /* save some cpu cycles */
7417 #if CLUTTER_ENABLE_DEBUG
7418 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7420 g_warning ("The actor '%s' is currently inside an allocation "
7421 "cycle; calling clutter_actor_queue_relayout() is "
7423 _clutter_actor_get_debug_name (self));
7425 #endif /* CLUTTER_ENABLE_DEBUG */
7427 g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7431 * clutter_actor_queue_redraw_with_clip:
7432 * @self: a #ClutterActor
7433 * @clip: (allow-none): a rectangular clip region, or %NULL
7435 * Queues a redraw on @self limited to a specific, actor-relative
7438 * If @clip is %NULL this function is equivalent to
7439 * clutter_actor_queue_redraw().
7444 clutter_actor_queue_redraw_with_clip (ClutterActor *self,
7445 const cairo_rectangle_int_t *clip)
7447 ClutterPaintVolume volume;
7448 ClutterVertex origin;
7450 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7454 clutter_actor_queue_redraw (self);
7458 _clutter_paint_volume_init_static (&volume, self);
7464 clutter_paint_volume_set_origin (&volume, &origin);
7465 clutter_paint_volume_set_width (&volume, clip->width);
7466 clutter_paint_volume_set_height (&volume, clip->height);
7468 _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7470 clutter_paint_volume_free (&volume);
7474 * clutter_actor_queue_relayout:
7475 * @self: A #ClutterActor
7477 * Indicates that the actor's size request or other layout-affecting
7478 * properties may have changed. This function is used inside #ClutterActor
7479 * subclass implementations, not by applications directly.
7481 * Queueing a new layout automatically queues a redraw as well.
7486 clutter_actor_queue_relayout (ClutterActor *self)
7488 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7490 _clutter_actor_queue_only_relayout (self);
7491 clutter_actor_queue_redraw (self);
7495 * clutter_actor_get_preferred_size:
7496 * @self: a #ClutterActor
7497 * @min_width_p: (out) (allow-none): return location for the minimum
7499 * @min_height_p: (out) (allow-none): return location for the minimum
7501 * @natural_width_p: (out) (allow-none): return location for the natural
7503 * @natural_height_p: (out) (allow-none): return location for the natural
7506 * Computes the preferred minimum and natural size of an actor, taking into
7507 * account the actor's geometry management (either height-for-width
7508 * or width-for-height).
7510 * The width and height used to compute the preferred height and preferred
7511 * width are the actor's natural ones.
7513 * If you need to control the height for the preferred width, or the width for
7514 * the preferred height, you should use clutter_actor_get_preferred_width()
7515 * and clutter_actor_get_preferred_height(), and check the actor's preferred
7516 * geometry management using the #ClutterActor:request-mode property.
7521 clutter_actor_get_preferred_size (ClutterActor *self,
7522 gfloat *min_width_p,
7523 gfloat *min_height_p,
7524 gfloat *natural_width_p,
7525 gfloat *natural_height_p)
7527 ClutterActorPrivate *priv;
7528 gfloat min_width, min_height;
7529 gfloat natural_width, natural_height;
7531 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7535 min_width = min_height = 0;
7536 natural_width = natural_height = 0;
7538 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7540 CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7541 clutter_actor_get_preferred_width (self, -1,
7544 clutter_actor_get_preferred_height (self, natural_width,
7550 CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7551 clutter_actor_get_preferred_height (self, -1,
7554 clutter_actor_get_preferred_width (self, natural_height,
7560 *min_width_p = min_width;
7563 *min_height_p = min_height;
7565 if (natural_width_p)
7566 *natural_width_p = natural_width;
7568 if (natural_height_p)
7569 *natural_height_p = natural_height;
7574 * @align: a #ClutterActorAlign
7575 * @direction: a #ClutterTextDirection
7577 * Retrieves the correct alignment depending on the text direction
7579 * Return value: the effective alignment
7581 static ClutterActorAlign
7582 effective_align (ClutterActorAlign align,
7583 ClutterTextDirection direction)
7585 ClutterActorAlign res;
7589 case CLUTTER_ACTOR_ALIGN_START:
7590 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7591 ? CLUTTER_ACTOR_ALIGN_END
7592 : CLUTTER_ACTOR_ALIGN_START;
7595 case CLUTTER_ACTOR_ALIGN_END:
7596 res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7597 ? CLUTTER_ACTOR_ALIGN_START
7598 : CLUTTER_ACTOR_ALIGN_END;
7610 adjust_for_margin (float margin_start,
7612 float *minimum_size,
7613 float *natural_size,
7614 float *allocated_start,
7615 float *allocated_end)
7617 *minimum_size -= (margin_start + margin_end);
7618 *natural_size -= (margin_start + margin_end);
7619 *allocated_start += margin_start;
7620 *allocated_end -= margin_end;
7624 adjust_for_alignment (ClutterActorAlign alignment,
7626 float *allocated_start,
7627 float *allocated_end)
7629 float allocated_size = *allocated_end - *allocated_start;
7633 case CLUTTER_ACTOR_ALIGN_FILL:
7637 case CLUTTER_ACTOR_ALIGN_START:
7639 *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7642 case CLUTTER_ACTOR_ALIGN_END:
7643 if (allocated_size > natural_size)
7645 *allocated_start += (allocated_size - natural_size);
7646 *allocated_end = *allocated_start + natural_size;
7650 case CLUTTER_ACTOR_ALIGN_CENTER:
7651 if (allocated_size > natural_size)
7653 *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7654 *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7661 * clutter_actor_adjust_width:
7662 * @self: a #ClutterActor
7663 * @minimum_width: (inout): the actor's preferred minimum width, which
7664 * will be adjusted depending on the margin
7665 * @natural_width: (inout): the actor's preferred natural width, which
7666 * will be adjusted depending on the margin
7667 * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7668 * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7670 * Adjusts the preferred and allocated position and size of an actor,
7671 * depending on the margin and alignment properties.
7674 clutter_actor_adjust_width (ClutterActor *self,
7675 gfloat *minimum_width,
7676 gfloat *natural_width,
7677 gfloat *adjusted_x1,
7678 gfloat *adjusted_x2)
7680 ClutterTextDirection text_dir;
7681 const ClutterLayoutInfo *info;
7683 info = _clutter_actor_get_layout_info_or_defaults (self);
7684 text_dir = clutter_actor_get_text_direction (self);
7686 CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7688 /* this will tweak natural_width to remove the margin, so that
7689 * adjust_for_alignment() will use the correct size
7691 adjust_for_margin (info->margin.left, info->margin.right,
7692 minimum_width, natural_width,
7693 adjusted_x1, adjusted_x2);
7695 adjust_for_alignment (effective_align (info->x_align, text_dir),
7697 adjusted_x1, adjusted_x2);
7701 * clutter_actor_adjust_height:
7702 * @self: a #ClutterActor
7703 * @minimum_height: (inout): the actor's preferred minimum height, which
7704 * will be adjusted depending on the margin
7705 * @natural_height: (inout): the actor's preferred natural height, which
7706 * will be adjusted depending on the margin
7707 * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7708 * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7710 * Adjusts the preferred and allocated position and size of an actor,
7711 * depending on the margin and alignment properties.
7714 clutter_actor_adjust_height (ClutterActor *self,
7715 gfloat *minimum_height,
7716 gfloat *natural_height,
7717 gfloat *adjusted_y1,
7718 gfloat *adjusted_y2)
7720 const ClutterLayoutInfo *info;
7722 info = _clutter_actor_get_layout_info_or_defaults (self);
7724 CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7726 /* this will tweak natural_height to remove the margin, so that
7727 * adjust_for_alignment() will use the correct size
7729 adjust_for_margin (info->margin.top, info->margin.bottom,
7730 minimum_height, natural_height,
7734 /* we don't use effective_align() here, because text direction
7735 * only affects the horizontal axis
7737 adjust_for_alignment (info->y_align,
7744 /* looks for a cached size request for this for_size. If not
7745 * found, returns the oldest entry so it can be overwritten */
7747 _clutter_actor_get_cached_size_request (gfloat for_size,
7748 SizeRequest *cached_size_requests,
7749 SizeRequest **result)
7753 *result = &cached_size_requests[0];
7755 for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7759 sr = &cached_size_requests[i];
7762 sr->for_size == for_size)
7764 CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7768 else if (sr->age < (*result)->age)
7774 CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7780 * clutter_actor_get_preferred_width:
7781 * @self: A #ClutterActor
7782 * @for_height: available height when computing the preferred width,
7783 * or a negative value to indicate that no height is defined
7784 * @min_width_p: (out) (allow-none): return location for minimum width,
7786 * @natural_width_p: (out) (allow-none): return location for the natural
7789 * Computes the requested minimum and natural widths for an actor,
7790 * optionally depending on the specified height, or if they are
7791 * already computed, returns the cached values.
7793 * An actor may not get its request - depending on the layout
7794 * manager that's in effect.
7796 * A request should not incorporate the actor's scale or anchor point;
7797 * those transformations do not affect layout, only rendering.
7802 clutter_actor_get_preferred_width (ClutterActor *self,
7804 gfloat *min_width_p,
7805 gfloat *natural_width_p)
7807 float request_min_width, request_natural_width;
7808 SizeRequest *cached_size_request;
7809 const ClutterLayoutInfo *info;
7810 ClutterActorPrivate *priv;
7811 gboolean found_in_cache;
7813 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7817 info = _clutter_actor_get_layout_info_or_defaults (self);
7819 /* we shortcircuit the case of a fixed size set using set_width() */
7820 if (priv->min_width_set && priv->natural_width_set)
7822 if (min_width_p != NULL)
7823 *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7825 if (natural_width_p != NULL)
7826 *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7831 /* the remaining cases are:
7833 * - either min_width or natural_width have been set
7834 * - neither min_width or natural_width have been set
7836 * in both cases, we go through the cache (and through the actor in case
7837 * of cache misses) and determine the authoritative value depending on
7841 if (!priv->needs_width_request)
7844 _clutter_actor_get_cached_size_request (for_height,
7845 priv->width_requests,
7846 &cached_size_request);
7850 /* if the actor needs a width request we use the first slot */
7851 found_in_cache = FALSE;
7852 cached_size_request = &priv->width_requests[0];
7855 if (!found_in_cache)
7857 gfloat minimum_width, natural_width;
7858 ClutterActorClass *klass;
7860 minimum_width = natural_width = 0;
7862 /* adjust for the margin */
7863 if (for_height >= 0)
7865 for_height -= (info->margin.top + info->margin.bottom);
7870 CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7872 klass = CLUTTER_ACTOR_GET_CLASS (self);
7873 klass->get_preferred_width (self, for_height,
7877 /* adjust for the margin */
7878 minimum_width += (info->margin.left + info->margin.right);
7879 natural_width += (info->margin.left + info->margin.right);
7881 /* Due to accumulated float errors, it's better not to warn
7882 * on this, but just fix it.
7884 if (natural_width < minimum_width)
7885 natural_width = minimum_width;
7887 cached_size_request->min_size = minimum_width;
7888 cached_size_request->natural_size = natural_width;
7889 cached_size_request->for_size = for_height;
7890 cached_size_request->age = priv->cached_width_age;
7892 priv->cached_width_age += 1;
7893 priv->needs_width_request = FALSE;
7896 if (!priv->min_width_set)
7897 request_min_width = cached_size_request->min_size;
7899 request_min_width = info->min_width;
7901 if (!priv->natural_width_set)
7902 request_natural_width = cached_size_request->natural_size;
7904 request_natural_width = info->natural_width;
7907 *min_width_p = request_min_width;
7909 if (natural_width_p)
7910 *natural_width_p = request_natural_width;
7914 * clutter_actor_get_preferred_height:
7915 * @self: A #ClutterActor
7916 * @for_width: available width to assume in computing desired height,
7917 * or a negative value to indicate that no width is defined
7918 * @min_height_p: (out) (allow-none): return location for minimum height,
7920 * @natural_height_p: (out) (allow-none): return location for natural
7923 * Computes the requested minimum and natural heights for an actor,
7924 * or if they are already computed, returns the cached values.
7926 * An actor may not get its request - depending on the layout
7927 * manager that's in effect.
7929 * A request should not incorporate the actor's scale or anchor point;
7930 * those transformations do not affect layout, only rendering.
7935 clutter_actor_get_preferred_height (ClutterActor *self,
7937 gfloat *min_height_p,
7938 gfloat *natural_height_p)
7940 float request_min_height, request_natural_height;
7941 SizeRequest *cached_size_request;
7942 const ClutterLayoutInfo *info;
7943 ClutterActorPrivate *priv;
7944 gboolean found_in_cache;
7946 g_return_if_fail (CLUTTER_IS_ACTOR (self));
7950 info = _clutter_actor_get_layout_info_or_defaults (self);
7952 /* we shortcircuit the case of a fixed size set using set_height() */
7953 if (priv->min_height_set && priv->natural_height_set)
7955 if (min_height_p != NULL)
7956 *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
7958 if (natural_height_p != NULL)
7959 *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
7964 /* the remaining cases are:
7966 * - either min_height or natural_height have been set
7967 * - neither min_height or natural_height have been set
7969 * in both cases, we go through the cache (and through the actor in case
7970 * of cache misses) and determine the authoritative value depending on
7974 if (!priv->needs_height_request)
7977 _clutter_actor_get_cached_size_request (for_width,
7978 priv->height_requests,
7979 &cached_size_request);
7983 found_in_cache = FALSE;
7984 cached_size_request = &priv->height_requests[0];
7987 if (!found_in_cache)
7989 gfloat minimum_height, natural_height;
7990 ClutterActorClass *klass;
7992 minimum_height = natural_height = 0;
7994 CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
7996 /* adjust for margin */
7999 for_width -= (info->margin.left + info->margin.right);
8004 klass = CLUTTER_ACTOR_GET_CLASS (self);
8005 klass->get_preferred_height (self, for_width,
8009 /* adjust for margin */
8010 minimum_height += (info->margin.top + info->margin.bottom);
8011 natural_height += (info->margin.top + info->margin.bottom);
8013 /* Due to accumulated float errors, it's better not to warn
8014 * on this, but just fix it.
8016 if (natural_height < minimum_height)
8017 natural_height = minimum_height;
8019 cached_size_request->min_size = minimum_height;
8020 cached_size_request->natural_size = natural_height;
8021 cached_size_request->for_size = for_width;
8022 cached_size_request->age = priv->cached_height_age;
8024 priv->cached_height_age += 1;
8025 priv->needs_height_request = FALSE;
8028 if (!priv->min_height_set)
8029 request_min_height = cached_size_request->min_size;
8031 request_min_height = info->min_height;
8033 if (!priv->natural_height_set)
8034 request_natural_height = cached_size_request->natural_size;
8036 request_natural_height = info->natural_height;
8039 *min_height_p = request_min_height;
8041 if (natural_height_p)
8042 *natural_height_p = request_natural_height;
8046 * clutter_actor_get_allocation_box:
8047 * @self: A #ClutterActor
8048 * @box: (out): the function fills this in with the actor's allocation
8050 * Gets the layout box an actor has been assigned. The allocation can
8051 * only be assumed valid inside a paint() method; anywhere else, it
8052 * may be out-of-date.
8054 * An allocation does not incorporate the actor's scale or anchor point;
8055 * those transformations do not affect layout, only rendering.
8057 * <note>Do not call any of the clutter_actor_get_allocation_*() family
8058 * of functions inside the implementation of the get_preferred_width()
8059 * or get_preferred_height() virtual functions.</note>
8064 clutter_actor_get_allocation_box (ClutterActor *self,
8065 ClutterActorBox *box)
8067 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8069 /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8070 * which limits calling get_allocation to inside paint() basically; or
8071 * we can 2) force a layout, which could be expensive if someone calls
8072 * get_allocation somewhere silly; or we can 3) just return the latest
8073 * value, allowing it to be out-of-date, and assume people know what
8076 * The least-surprises approach that keeps existing code working is
8077 * likely to be 2). People can end up doing some inefficient things,
8078 * though, and in general code that requires 2) is probably broken.
8081 /* this implements 2) */
8082 if (G_UNLIKELY (self->priv->needs_allocation))
8084 ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8086 /* do not queue a relayout on an unparented actor */
8088 _clutter_stage_maybe_relayout (stage);
8091 /* commenting out the code above and just keeping this assigment
8094 *box = self->priv->allocation;
8098 * clutter_actor_get_allocation_geometry:
8099 * @self: A #ClutterActor
8100 * @geom: (out): allocation geometry in pixels
8102 * Gets the layout box an actor has been assigned. The allocation can
8103 * only be assumed valid inside a paint() method; anywhere else, it
8104 * may be out-of-date.
8106 * An allocation does not incorporate the actor's scale or anchor point;
8107 * those transformations do not affect layout, only rendering.
8109 * The returned rectangle is in pixels.
8114 clutter_actor_get_allocation_geometry (ClutterActor *self,
8115 ClutterGeometry *geom)
8117 ClutterActorBox box;
8119 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8120 g_return_if_fail (geom != NULL);
8122 clutter_actor_get_allocation_box (self, &box);
8124 geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8125 geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8126 geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8127 geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8131 clutter_actor_update_constraints (ClutterActor *self,
8132 ClutterActorBox *allocation)
8134 ClutterActorPrivate *priv = self->priv;
8135 const GList *constraints, *l;
8137 if (priv->constraints == NULL)
8140 constraints = _clutter_meta_group_peek_metas (priv->constraints);
8141 for (l = constraints; l != NULL; l = l->next)
8143 ClutterConstraint *constraint = l->data;
8144 ClutterActorMeta *meta = l->data;
8146 if (clutter_actor_meta_get_enabled (meta))
8148 _clutter_constraint_update_allocation (constraint,
8152 CLUTTER_NOTE (LAYOUT,
8153 "Allocation of '%s' after constraint '%s': "
8154 "{ %.2f, %.2f, %.2f, %.2f }",
8155 _clutter_actor_get_debug_name (self),
8156 _clutter_actor_meta_get_debug_name (meta),
8166 * clutter_actor_adjust_allocation:
8167 * @self: a #ClutterActor
8168 * @allocation: (inout): the allocation to adjust
8170 * Adjusts the passed allocation box taking into account the actor's
8171 * layout information, like alignment, expansion, and margin.
8174 clutter_actor_adjust_allocation (ClutterActor *self,
8175 ClutterActorBox *allocation)
8177 ClutterActorBox adj_allocation;
8178 float alloc_width, alloc_height;
8179 float min_width, min_height;
8180 float nat_width, nat_height;
8181 ClutterRequestMode req_mode;
8183 adj_allocation = *allocation;
8185 clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8187 /* we want to hit the cache, so we use the public API */
8188 req_mode = clutter_actor_get_request_mode (self);
8190 if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8192 clutter_actor_get_preferred_width (self, -1,
8195 clutter_actor_get_preferred_height (self, alloc_width,
8199 else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8201 clutter_actor_get_preferred_height (self, -1,
8204 clutter_actor_get_preferred_height (self, alloc_height,
8209 #ifdef CLUTTER_ENABLE_DEBUG
8210 /* warn about underallocations */
8211 if (_clutter_diagnostic_enabled () &&
8212 (floorf (min_width - alloc_width) > 0 ||
8213 floorf (min_height - alloc_height) > 0))
8215 ClutterActor *parent = clutter_actor_get_parent (self);
8217 /* the only actors that are allowed to be underallocated are the Stage,
8218 * as it doesn't have an implicit size, and Actors that specifically
8219 * told us that they want to opt-out from layout control mechanisms
8220 * through the NO_LAYOUT escape hatch.
8222 if (parent != NULL &&
8223 !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8225 g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8226 "of %.2f x %.2f from its parent actor '%s', but its "
8227 "requested minimum size is of %.2f x %.2f",
8228 _clutter_actor_get_debug_name (self),
8229 alloc_width, alloc_height,
8230 _clutter_actor_get_debug_name (parent),
8231 min_width, min_height);
8236 clutter_actor_adjust_width (self,
8240 &adj_allocation.x2);
8242 clutter_actor_adjust_height (self,
8246 &adj_allocation.y2);
8248 /* we maintain the invariant that an allocation cannot be adjusted
8249 * to be outside the parent-given box
8251 if (adj_allocation.x1 < allocation->x1 ||
8252 adj_allocation.y1 < allocation->y1 ||
8253 adj_allocation.x2 > allocation->x2 ||
8254 adj_allocation.y2 > allocation->y2)
8256 g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8257 "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8258 "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8259 _clutter_actor_get_debug_name (self),
8260 adj_allocation.x1, adj_allocation.y1,
8261 adj_allocation.x2 - adj_allocation.x1,
8262 adj_allocation.y2 - adj_allocation.y1,
8263 allocation->x1, allocation->y1,
8264 allocation->x2 - allocation->x1,
8265 allocation->y2 - allocation->y1);
8269 *allocation = adj_allocation;
8273 * clutter_actor_allocate:
8274 * @self: A #ClutterActor
8275 * @box: new allocation of the actor, in parent-relative coordinates
8276 * @flags: flags that control the allocation
8278 * Called by the parent of an actor to assign the actor its size.
8279 * Should never be called by applications (except when implementing
8280 * a container or layout manager).
8282 * Actors can know from their allocation box whether they have moved
8283 * with respect to their parent actor. The @flags parameter describes
8284 * additional information about the allocation, for instance whether
8285 * the parent has moved with respect to the stage, for example because
8286 * a grandparent's origin has moved.
8291 clutter_actor_allocate (ClutterActor *self,
8292 const ClutterActorBox *box,
8293 ClutterAllocationFlags flags)
8295 ClutterActorPrivate *priv;
8296 ClutterActorClass *klass;
8297 ClutterActorBox old_allocation, real_allocation;
8298 gboolean origin_changed, child_moved, size_changed;
8299 gboolean stage_allocation_changed;
8301 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8302 if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8304 g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8305 "which isn't a descendent of the stage!\n",
8306 self, _clutter_actor_get_debug_name (self));
8312 old_allocation = priv->allocation;
8313 real_allocation = *box;
8315 /* constraints are allowed to modify the allocation only here; we do
8316 * this prior to all the other checks so that we can bail out if the
8317 * allocation did not change
8319 clutter_actor_update_constraints (self, &real_allocation);
8321 /* adjust the allocation depending on the align/margin properties */
8322 clutter_actor_adjust_allocation (self, &real_allocation);
8324 if (real_allocation.x2 < real_allocation.x1 ||
8325 real_allocation.y2 < real_allocation.y1)
8327 g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8328 _clutter_actor_get_debug_name (self),
8329 real_allocation.x2 - real_allocation.x1,
8330 real_allocation.y2 - real_allocation.y1);
8333 /* we allow 0-sized actors, but not negative-sized ones */
8334 real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8335 real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8337 origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8339 child_moved = (real_allocation.x1 != old_allocation.x1 ||
8340 real_allocation.y1 != old_allocation.y1);
8342 size_changed = (real_allocation.x2 != old_allocation.x2 ||
8343 real_allocation.y2 != old_allocation.y2);
8345 if (origin_changed || child_moved || size_changed)
8346 stage_allocation_changed = TRUE;
8348 stage_allocation_changed = FALSE;
8350 /* If we get an allocation "out of the blue"
8351 * (we did not queue relayout), then we want to
8352 * ignore it. But if we have needs_allocation set,
8353 * we want to guarantee that allocate() virtual
8354 * method is always called, i.e. that queue_relayout()
8355 * always results in an allocate() invocation on
8358 * The optimization here is to avoid re-allocating
8359 * actors that did not queue relayout and were
8362 if (!priv->needs_allocation && !stage_allocation_changed)
8364 CLUTTER_NOTE (LAYOUT, "No allocation needed");
8368 /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8369 * clutter_actor_allocate(), it indicates whether the parent has its
8370 * absolute origin moved; when passed in to ClutterActor::allocate()
8371 * virtual method though, it indicates whether the child has its
8372 * absolute origin moved. So we set it when child_moved is TRUE
8375 flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8377 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8379 CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8380 _clutter_actor_get_debug_name (self));
8382 klass = CLUTTER_ACTOR_GET_CLASS (self);
8383 klass->allocate (self, &real_allocation, flags);
8385 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8387 if (stage_allocation_changed)
8388 clutter_actor_queue_redraw (self);
8392 * clutter_actor_set_allocation:
8393 * @self: a #ClutterActor
8394 * @box: a #ClutterActorBox
8395 * @flags: allocation flags
8397 * Stores the allocation of @self as defined by @box.
8399 * This function can only be called from within the implementation of
8400 * the #ClutterActorClass.allocate() virtual function.
8402 * The allocation should have been adjusted to take into account constraints,
8403 * alignment, and margin properties. If you are implementing a #ClutterActor
8404 * subclass that provides its own layout management policy for its children
8405 * instead of using a #ClutterLayoutManager delegate, you should not call
8406 * this function on the children of @self; instead, you should call
8407 * clutter_actor_allocate(), which will adjust the allocation box for
8410 * This function should only be used by subclasses of #ClutterActor
8411 * that wish to store their allocation but cannot chain up to the
8412 * parent's implementation; the default implementation of the
8413 * #ClutterActorClass.allocate() virtual function will call this
8416 * It is important to note that, while chaining up was the recommended
8417 * behaviour for #ClutterActor subclasses prior to the introduction of
8418 * this function, it is recommended to call clutter_actor_set_allocation()
8421 * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8422 * to handle the allocation of its children, this function will call
8423 * the clutter_layout_manager_allocate() function only if the
8424 * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8425 * expected that the subclass will call clutter_layout_manager_allocate()
8426 * by itself. For instance, the following code:
8430 * my_actor_allocate (ClutterActor *actor,
8431 * const ClutterActorBox *allocation,
8432 * ClutterAllocationFlags flags)
8434 * ClutterActorBox new_alloc;
8435 * ClutterAllocationFlags new_flags;
8437 * adjust_allocation (allocation, &new_alloc);
8439 * new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8441 * /* this will use the layout manager set on the actor */
8442 * clutter_actor_set_allocation (actor, &new_alloc, new_flags);
8446 * is equivalent to this:
8450 * my_actor_allocate (ClutterActor *actor,
8451 * const ClutterActorBox *allocation,
8452 * ClutterAllocationFlags flags)
8454 * ClutterLayoutManager *layout;
8455 * ClutterActorBox new_alloc;
8457 * adjust_allocation (allocation, &new_alloc);
8459 * clutter_actor_set_allocation (actor, &new_alloc, flags);
8461 * layout = clutter_actor_get_layout_manager (actor);
8462 * clutter_layout_manager_allocate (layout,
8463 * CLUTTER_CONTAINER (actor),
8472 clutter_actor_set_allocation (ClutterActor *self,
8473 const ClutterActorBox *box,
8474 ClutterAllocationFlags flags)
8476 ClutterActorPrivate *priv;
8479 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8480 g_return_if_fail (box != NULL);
8482 if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8484 g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8485 "can only be called from within the implementation of "
8486 "the ClutterActor::allocate() virtual function.");
8492 g_object_freeze_notify (G_OBJECT (self));
8494 changed = clutter_actor_set_allocation_internal (self, box, flags);
8496 /* we allocate our children before we notify changes in our geometry,
8497 * so that people connecting to properties will be able to get valid
8498 * data out of the sub-tree of the scene graph that has this actor at
8501 clutter_actor_maybe_layout_children (self, box, flags);
8505 ClutterActorBox signal_box = priv->allocation;
8506 ClutterAllocationFlags signal_flags = priv->allocation_flags;
8508 g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8513 g_object_thaw_notify (G_OBJECT (self));
8517 * clutter_actor_set_geometry:
8518 * @self: A #ClutterActor
8519 * @geometry: A #ClutterGeometry
8521 * Sets the actor's fixed position and forces its minimum and natural
8522 * size, in pixels. This means the untransformed actor will have the
8523 * given geometry. This is the same as calling clutter_actor_set_position()
8524 * and clutter_actor_set_size().
8526 * Deprecated: 1.10: Use clutter_actor_set_position() and
8527 * clutter_actor_set_size() instead.
8530 clutter_actor_set_geometry (ClutterActor *self,
8531 const ClutterGeometry *geometry)
8533 g_object_freeze_notify (G_OBJECT (self));
8535 clutter_actor_set_position (self, geometry->x, geometry->y);
8536 clutter_actor_set_size (self, geometry->width, geometry->height);
8538 g_object_thaw_notify (G_OBJECT (self));
8542 * clutter_actor_get_geometry:
8543 * @self: A #ClutterActor
8544 * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8546 * Gets the size and position of an actor relative to its parent
8547 * actor. This is the same as calling clutter_actor_get_position() and
8548 * clutter_actor_get_size(). It tries to "do what you mean" and get the
8549 * requested size and position if the actor's allocation is invalid.
8551 * Deprecated: 1.10: Use clutter_actor_get_position() and
8552 * clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8556 clutter_actor_get_geometry (ClutterActor *self,
8557 ClutterGeometry *geometry)
8559 gfloat x, y, width, height;
8561 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8562 g_return_if_fail (geometry != NULL);
8564 clutter_actor_get_position (self, &x, &y);
8565 clutter_actor_get_size (self, &width, &height);
8567 geometry->x = (int) x;
8568 geometry->y = (int) y;
8569 geometry->width = (int) width;
8570 geometry->height = (int) height;
8574 * clutter_actor_set_position:
8575 * @self: A #ClutterActor
8576 * @x: New left position of actor in pixels.
8577 * @y: New top position of actor in pixels.
8579 * Sets the actor's fixed position in pixels relative to any parent
8582 * If a layout manager is in use, this position will override the
8583 * layout manager and force a fixed position.
8586 clutter_actor_set_position (ClutterActor *self,
8590 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8592 g_object_freeze_notify (G_OBJECT (self));
8594 clutter_actor_set_x (self, x);
8595 clutter_actor_set_y (self, y);
8597 g_object_thaw_notify (G_OBJECT (self));
8601 * clutter_actor_get_fixed_position_set:
8602 * @self: A #ClutterActor
8604 * Checks whether an actor has a fixed position set (and will thus be
8605 * unaffected by any layout manager).
8607 * Return value: %TRUE if the fixed position is set on the actor
8612 clutter_actor_get_fixed_position_set (ClutterActor *self)
8614 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8616 return self->priv->position_set;
8620 * clutter_actor_set_fixed_position_set:
8621 * @self: A #ClutterActor
8622 * @is_set: whether to use fixed position
8624 * Sets whether an actor has a fixed position set (and will thus be
8625 * unaffected by any layout manager).
8630 clutter_actor_set_fixed_position_set (ClutterActor *self,
8633 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8635 if (self->priv->position_set == (is_set != FALSE))
8638 self->priv->position_set = is_set != FALSE;
8639 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8641 clutter_actor_queue_relayout (self);
8645 * clutter_actor_move_by:
8646 * @self: A #ClutterActor
8647 * @dx: Distance to move Actor on X axis.
8648 * @dy: Distance to move Actor on Y axis.
8650 * Moves an actor by the specified distance relative to its current
8651 * position in pixels.
8653 * This function modifies the fixed position of an actor and thus removes
8654 * it from any layout management. Another way to move an actor is with an
8655 * anchor point, see clutter_actor_set_anchor_point().
8660 clutter_actor_move_by (ClutterActor *self,
8664 const ClutterLayoutInfo *info;
8667 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8669 info = _clutter_actor_get_layout_info_or_defaults (self);
8673 clutter_actor_set_position (self, x + dx, y + dy);
8677 clutter_actor_set_min_width (ClutterActor *self,
8680 ClutterActorPrivate *priv = self->priv;
8681 ClutterActorBox old = { 0, };
8682 ClutterLayoutInfo *info;
8684 /* if we are setting the size on a top-level actor and the
8685 * backend only supports static top-levels (e.g. framebuffers)
8686 * then we ignore the passed value and we override it with
8687 * the stage implementation's preferred size.
8689 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8690 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8693 info = _clutter_actor_get_layout_info (self);
8695 if (priv->min_width_set && min_width == info->min_width)
8698 g_object_freeze_notify (G_OBJECT (self));
8700 clutter_actor_store_old_geometry (self, &old);
8702 info->min_width = min_width;
8703 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8704 clutter_actor_set_min_width_set (self, TRUE);
8706 clutter_actor_notify_if_geometry_changed (self, &old);
8708 g_object_thaw_notify (G_OBJECT (self));
8710 clutter_actor_queue_relayout (self);
8714 clutter_actor_set_min_height (ClutterActor *self,
8718 ClutterActorPrivate *priv = self->priv;
8719 ClutterActorBox old = { 0, };
8720 ClutterLayoutInfo *info;
8722 /* if we are setting the size on a top-level actor and the
8723 * backend only supports static top-levels (e.g. framebuffers)
8724 * then we ignore the passed value and we override it with
8725 * the stage implementation's preferred size.
8727 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8728 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8731 info = _clutter_actor_get_layout_info (self);
8733 if (priv->min_height_set && min_height == info->min_height)
8736 g_object_freeze_notify (G_OBJECT (self));
8738 clutter_actor_store_old_geometry (self, &old);
8740 info->min_height = min_height;
8741 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8742 clutter_actor_set_min_height_set (self, TRUE);
8744 clutter_actor_notify_if_geometry_changed (self, &old);
8746 g_object_thaw_notify (G_OBJECT (self));
8748 clutter_actor_queue_relayout (self);
8752 clutter_actor_set_natural_width (ClutterActor *self,
8753 gfloat natural_width)
8755 ClutterActorPrivate *priv = self->priv;
8756 ClutterActorBox old = { 0, };
8757 ClutterLayoutInfo *info;
8759 /* if we are setting the size on a top-level actor and the
8760 * backend only supports static top-levels (e.g. framebuffers)
8761 * then we ignore the passed value and we override it with
8762 * the stage implementation's preferred size.
8764 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8765 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8768 info = _clutter_actor_get_layout_info (self);
8770 if (priv->natural_width_set && natural_width == info->natural_width)
8773 g_object_freeze_notify (G_OBJECT (self));
8775 clutter_actor_store_old_geometry (self, &old);
8777 info->natural_width = natural_width;
8778 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8779 clutter_actor_set_natural_width_set (self, TRUE);
8781 clutter_actor_notify_if_geometry_changed (self, &old);
8783 g_object_thaw_notify (G_OBJECT (self));
8785 clutter_actor_queue_relayout (self);
8789 clutter_actor_set_natural_height (ClutterActor *self,
8790 gfloat natural_height)
8792 ClutterActorPrivate *priv = self->priv;
8793 ClutterActorBox old = { 0, };
8794 ClutterLayoutInfo *info;
8796 /* if we are setting the size on a top-level actor and the
8797 * backend only supports static top-levels (e.g. framebuffers)
8798 * then we ignore the passed value and we override it with
8799 * the stage implementation's preferred size.
8801 if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8802 clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8805 info = _clutter_actor_get_layout_info (self);
8807 if (priv->natural_height_set && natural_height == info->natural_height)
8810 g_object_freeze_notify (G_OBJECT (self));
8812 clutter_actor_store_old_geometry (self, &old);
8814 info->natural_height = natural_height;
8815 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8816 clutter_actor_set_natural_height_set (self, TRUE);
8818 clutter_actor_notify_if_geometry_changed (self, &old);
8820 g_object_thaw_notify (G_OBJECT (self));
8822 clutter_actor_queue_relayout (self);
8826 clutter_actor_set_min_width_set (ClutterActor *self,
8827 gboolean use_min_width)
8829 ClutterActorPrivate *priv = self->priv;
8830 ClutterActorBox old = { 0, };
8832 if (priv->min_width_set == (use_min_width != FALSE))
8835 clutter_actor_store_old_geometry (self, &old);
8837 priv->min_width_set = use_min_width != FALSE;
8838 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8840 clutter_actor_notify_if_geometry_changed (self, &old);
8842 clutter_actor_queue_relayout (self);
8846 clutter_actor_set_min_height_set (ClutterActor *self,
8847 gboolean use_min_height)
8849 ClutterActorPrivate *priv = self->priv;
8850 ClutterActorBox old = { 0, };
8852 if (priv->min_height_set == (use_min_height != FALSE))
8855 clutter_actor_store_old_geometry (self, &old);
8857 priv->min_height_set = use_min_height != FALSE;
8858 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8860 clutter_actor_notify_if_geometry_changed (self, &old);
8862 clutter_actor_queue_relayout (self);
8866 clutter_actor_set_natural_width_set (ClutterActor *self,
8867 gboolean use_natural_width)
8869 ClutterActorPrivate *priv = self->priv;
8870 ClutterActorBox old = { 0, };
8872 if (priv->natural_width_set == (use_natural_width != FALSE))
8875 clutter_actor_store_old_geometry (self, &old);
8877 priv->natural_width_set = use_natural_width != FALSE;
8878 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8880 clutter_actor_notify_if_geometry_changed (self, &old);
8882 clutter_actor_queue_relayout (self);
8886 clutter_actor_set_natural_height_set (ClutterActor *self,
8887 gboolean use_natural_height)
8889 ClutterActorPrivate *priv = self->priv;
8890 ClutterActorBox old = { 0, };
8892 if (priv->natural_height_set == (use_natural_height != FALSE))
8895 clutter_actor_store_old_geometry (self, &old);
8897 priv->natural_height_set = use_natural_height != FALSE;
8898 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
8900 clutter_actor_notify_if_geometry_changed (self, &old);
8902 clutter_actor_queue_relayout (self);
8906 * clutter_actor_set_request_mode:
8907 * @self: a #ClutterActor
8908 * @mode: the request mode
8910 * Sets the geometry request mode of @self.
8912 * The @mode determines the order for invoking
8913 * clutter_actor_get_preferred_width() and
8914 * clutter_actor_get_preferred_height()
8919 clutter_actor_set_request_mode (ClutterActor *self,
8920 ClutterRequestMode mode)
8922 ClutterActorPrivate *priv;
8924 g_return_if_fail (CLUTTER_IS_ACTOR (self));
8928 if (priv->request_mode == mode)
8931 priv->request_mode = mode;
8933 priv->needs_width_request = TRUE;
8934 priv->needs_height_request = TRUE;
8936 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
8938 clutter_actor_queue_relayout (self);
8942 * clutter_actor_get_request_mode:
8943 * @self: a #ClutterActor
8945 * Retrieves the geometry request mode of @self
8947 * Return value: the request mode for the actor
8952 clutter_actor_get_request_mode (ClutterActor *self)
8954 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
8955 CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
8957 return self->priv->request_mode;
8960 /* variant of set_width() without checks and without notification
8961 * freeze+thaw, for internal usage only
8964 clutter_actor_set_width_internal (ClutterActor *self,
8969 /* the Stage will use the :min-width to control the minimum
8970 * width to be resized to, so we should not be setting it
8971 * along with the :natural-width
8973 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8974 clutter_actor_set_min_width (self, width);
8976 clutter_actor_set_natural_width (self, width);
8980 /* we only unset the :natural-width for the Stage */
8981 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8982 clutter_actor_set_min_width_set (self, FALSE);
8984 clutter_actor_set_natural_width_set (self, FALSE);
8988 /* variant of set_height() without checks and without notification
8989 * freeze+thaw, for internal usage only
8992 clutter_actor_set_height_internal (ClutterActor *self,
8997 /* see the comment above in set_width_internal() */
8998 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
8999 clutter_actor_set_min_height (self, height);
9001 clutter_actor_set_natural_height (self, height);
9005 /* see the comment above in set_width_internal() */
9006 if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9007 clutter_actor_set_min_height_set (self, FALSE);
9009 clutter_actor_set_natural_height_set (self, FALSE);
9014 * clutter_actor_set_size:
9015 * @self: A #ClutterActor
9016 * @width: New width of actor in pixels, or -1
9017 * @height: New height of actor in pixels, or -1
9019 * Sets the actor's size request in pixels. This overrides any
9020 * "normal" size request the actor would have. For example
9021 * a text actor might normally request the size of the text;
9022 * this function would force a specific size instead.
9024 * If @width and/or @height are -1 the actor will use its
9025 * "normal" size request instead of overriding it, i.e.
9026 * you can "unset" the size with -1.
9028 * This function sets or unsets both the minimum and natural size.
9031 clutter_actor_set_size (ClutterActor *self,
9035 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9037 g_object_freeze_notify (G_OBJECT (self));
9039 clutter_actor_set_width (self, width);
9040 clutter_actor_set_height (self, height);
9042 g_object_thaw_notify (G_OBJECT (self));
9046 * clutter_actor_get_size:
9047 * @self: A #ClutterActor
9048 * @width: (out) (allow-none): return location for the width, or %NULL.
9049 * @height: (out) (allow-none): return location for the height, or %NULL.
9051 * This function tries to "do what you mean" and return
9052 * the size an actor will have. If the actor has a valid
9053 * allocation, the allocation will be returned; otherwise,
9054 * the actors natural size request will be returned.
9056 * If you care whether you get the request vs. the allocation, you
9057 * should probably call a different function like
9058 * clutter_actor_get_allocation_box() or
9059 * clutter_actor_get_preferred_width().
9064 clutter_actor_get_size (ClutterActor *self,
9068 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9071 *width = clutter_actor_get_width (self);
9074 *height = clutter_actor_get_height (self);
9078 * clutter_actor_get_position:
9079 * @self: a #ClutterActor
9080 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9081 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9083 * This function tries to "do what you mean" and tell you where the
9084 * actor is, prior to any transformations. Retrieves the fixed
9085 * position of an actor in pixels, if one has been set; otherwise, if
9086 * the allocation is valid, returns the actor's allocated position;
9087 * otherwise, returns 0,0.
9089 * The returned position is in pixels.
9094 clutter_actor_get_position (ClutterActor *self,
9098 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9101 *x = clutter_actor_get_x (self);
9104 *y = clutter_actor_get_y (self);
9108 * clutter_actor_get_transformed_position:
9109 * @self: A #ClutterActor
9110 * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9111 * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9113 * Gets the absolute position of an actor, in pixels relative to the stage.
9118 clutter_actor_get_transformed_position (ClutterActor *self,
9125 v1.x = v1.y = v1.z = 0;
9126 clutter_actor_apply_transform_to_point (self, &v1, &v2);
9136 * clutter_actor_get_transformed_size:
9137 * @self: A #ClutterActor
9138 * @width: (out) (allow-none): return location for the width, or %NULL
9139 * @height: (out) (allow-none): return location for the height, or %NULL
9141 * Gets the absolute size of an actor in pixels, taking into account the
9144 * If the actor has a valid allocation, the allocated size will be used.
9145 * If the actor has not a valid allocation then the preferred size will
9146 * be transformed and returned.
9148 * If you want the transformed allocation, see
9149 * clutter_actor_get_abs_allocation_vertices() instead.
9151 * <note>When the actor (or one of its ancestors) is rotated around the
9152 * X or Y axis, it no longer appears as on the stage as a rectangle, but
9153 * as a generic quadrangle; in that case this function returns the size
9154 * of the smallest rectangle that encapsulates the entire quad. Please
9155 * note that in this case no assumptions can be made about the relative
9156 * position of this envelope to the absolute position of the actor, as
9157 * returned by clutter_actor_get_transformed_position(); if you need this
9158 * information, you need to use clutter_actor_get_abs_allocation_vertices()
9159 * to get the coords of the actual quadrangle.</note>
9164 clutter_actor_get_transformed_size (ClutterActor *self,
9168 ClutterActorPrivate *priv;
9170 gfloat x_min, x_max, y_min, y_max;
9173 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9177 /* if the actor hasn't been allocated yet, get the preferred
9178 * size and transform that
9180 if (priv->needs_allocation)
9182 gfloat natural_width, natural_height;
9183 ClutterActorBox box;
9185 /* Make a fake allocation to transform.
9187 * NB: _clutter_actor_transform_and_project_box expects a box in
9188 * the actor's coordinate space... */
9193 natural_width = natural_height = 0;
9194 clutter_actor_get_preferred_size (self, NULL, NULL,
9198 box.x2 = natural_width;
9199 box.y2 = natural_height;
9201 _clutter_actor_transform_and_project_box (self, &box, v);
9204 clutter_actor_get_abs_allocation_vertices (self, v);
9206 x_min = x_max = v[0].x;
9207 y_min = y_max = v[0].y;
9209 for (i = 1; i < G_N_ELEMENTS (v); ++i)
9225 *width = x_max - x_min;
9228 *height = y_max - y_min;
9232 * clutter_actor_get_width:
9233 * @self: A #ClutterActor
9235 * Retrieves the width of a #ClutterActor.
9237 * If the actor has a valid allocation, this function will return the
9238 * width of the allocated area given to the actor.
9240 * If the actor does not have a valid allocation, this function will
9241 * return the actor's natural width, that is the preferred width of
9244 * If you care whether you get the preferred width or the width that
9245 * has been assigned to the actor, you should probably call a different
9246 * function like clutter_actor_get_allocation_box() to retrieve the
9247 * allocated size or clutter_actor_get_preferred_width() to retrieve the
9250 * If an actor has a fixed width, for instance a width that has been
9251 * assigned using clutter_actor_set_width(), the width returned will
9252 * be the same value.
9254 * Return value: the width of the actor, in pixels
9257 clutter_actor_get_width (ClutterActor *self)
9259 ClutterActorPrivate *priv;
9261 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9265 if (priv->needs_allocation)
9267 gfloat natural_width = 0;
9269 if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9270 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9273 gfloat natural_height = 0;
9275 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9276 clutter_actor_get_preferred_width (self, natural_height,
9281 return natural_width;
9284 return priv->allocation.x2 - priv->allocation.x1;
9288 * clutter_actor_get_height:
9289 * @self: A #ClutterActor
9291 * Retrieves the height of a #ClutterActor.
9293 * If the actor has a valid allocation, this function will return the
9294 * height of the allocated area given to the actor.
9296 * If the actor does not have a valid allocation, this function will
9297 * return the actor's natural height, that is the preferred height of
9300 * If you care whether you get the preferred height or the height that
9301 * has been assigned to the actor, you should probably call a different
9302 * function like clutter_actor_get_allocation_box() to retrieve the
9303 * allocated size or clutter_actor_get_preferred_height() to retrieve the
9306 * If an actor has a fixed height, for instance a height that has been
9307 * assigned using clutter_actor_set_height(), the height returned will
9308 * be the same value.
9310 * Return value: the height of the actor, in pixels
9313 clutter_actor_get_height (ClutterActor *self)
9315 ClutterActorPrivate *priv;
9317 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9321 if (priv->needs_allocation)
9323 gfloat natural_height = 0;
9325 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9327 gfloat natural_width = 0;
9329 clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9330 clutter_actor_get_preferred_height (self, natural_width,
9331 NULL, &natural_height);
9334 clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9336 return natural_height;
9339 return priv->allocation.y2 - priv->allocation.y1;
9343 * clutter_actor_set_width:
9344 * @self: A #ClutterActor
9345 * @width: Requested new width for the actor, in pixels, or -1
9347 * Forces a width on an actor, causing the actor's preferred width
9348 * and height (if any) to be ignored.
9350 * If @width is -1 the actor will use its preferred width request
9351 * instead of overriding it, i.e. you can "unset" the width with -1.
9353 * This function sets both the minimum and natural size of the actor.
9358 clutter_actor_set_width (ClutterActor *self,
9361 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9363 if (clutter_actor_get_easing_duration (self) != 0)
9365 ClutterTransition *transition;
9367 transition = _clutter_actor_get_transition (self, obj_props[PROP_WIDTH]);
9368 if (transition == NULL)
9370 float old_width = clutter_actor_get_width (self);
9372 transition = _clutter_actor_create_transition (self,
9373 obj_props[PROP_WIDTH],
9376 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9379 _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9381 clutter_actor_queue_relayout (self);
9385 g_object_freeze_notify (G_OBJECT (self));
9387 clutter_actor_set_width_internal (self, width);
9389 g_object_thaw_notify (G_OBJECT (self));
9394 * clutter_actor_set_height:
9395 * @self: A #ClutterActor
9396 * @height: Requested new height for the actor, in pixels, or -1
9398 * Forces a height on an actor, causing the actor's preferred width
9399 * and height (if any) to be ignored.
9401 * If @height is -1 the actor will use its preferred height instead of
9402 * overriding it, i.e. you can "unset" the height with -1.
9404 * This function sets both the minimum and natural size of the actor.
9409 clutter_actor_set_height (ClutterActor *self,
9412 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9414 if (clutter_actor_get_easing_duration (self) != 0)
9416 ClutterTransition *transition;
9418 transition = _clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]);
9419 if (transition == NULL)
9421 float old_height = clutter_actor_get_height (self);
9423 transition = _clutter_actor_create_transition (self,
9424 obj_props[PROP_HEIGHT],
9427 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9430 _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9432 clutter_actor_queue_relayout (self);
9436 g_object_freeze_notify (G_OBJECT (self));
9438 clutter_actor_set_height_internal (self, height);
9440 g_object_thaw_notify (G_OBJECT (self));
9445 clutter_actor_set_x_internal (ClutterActor *self,
9448 ClutterActorPrivate *priv = self->priv;
9449 ClutterLayoutInfo *linfo;
9450 ClutterActorBox old = { 0, };
9452 linfo = _clutter_actor_get_layout_info (self);
9454 if (priv->position_set && linfo->fixed_x == x)
9457 clutter_actor_store_old_geometry (self, &old);
9460 clutter_actor_set_fixed_position_set (self, TRUE);
9462 clutter_actor_notify_if_geometry_changed (self, &old);
9464 clutter_actor_queue_relayout (self);
9468 clutter_actor_set_y_internal (ClutterActor *self,
9471 ClutterActorPrivate *priv = self->priv;
9472 ClutterLayoutInfo *linfo;
9473 ClutterActorBox old = { 0, };
9475 linfo = _clutter_actor_get_layout_info (self);
9477 if (priv->position_set && linfo->fixed_y == y)
9480 clutter_actor_store_old_geometry (self, &old);
9483 clutter_actor_set_fixed_position_set (self, TRUE);
9485 clutter_actor_notify_if_geometry_changed (self, &old);
9487 clutter_actor_queue_relayout (self);
9491 * clutter_actor_set_x:
9492 * @self: a #ClutterActor
9493 * @x: the actor's position on the X axis
9495 * Sets the actor's X coordinate, relative to its parent, in pixels.
9497 * Overrides any layout manager and forces a fixed position for
9500 * The #ClutterActor:x property is animatable.
9505 clutter_actor_set_x (ClutterActor *self,
9508 const ClutterLayoutInfo *linfo;
9510 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9512 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9514 if (clutter_actor_get_easing_duration (self) != 0)
9516 ClutterTransition *transition;
9518 transition = _clutter_actor_get_transition (self, obj_props[PROP_X]);
9519 if (transition == NULL)
9521 transition = _clutter_actor_create_transition (self,
9526 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9529 _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9531 clutter_actor_queue_relayout (self);
9534 clutter_actor_set_x_internal (self, x);
9538 * clutter_actor_set_y:
9539 * @self: a #ClutterActor
9540 * @y: the actor's position on the Y axis
9542 * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9544 * Overrides any layout manager and forces a fixed position for
9547 * The #ClutterActor:y property is animatable.
9552 clutter_actor_set_y (ClutterActor *self,
9555 const ClutterLayoutInfo *linfo;
9557 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9559 linfo = _clutter_actor_get_layout_info_or_defaults (self);
9561 if (clutter_actor_get_easing_duration (self) != 0)
9563 ClutterTransition *transition;
9565 transition = _clutter_actor_get_transition (self, obj_props[PROP_Y]);
9566 if (transition == NULL)
9568 transition = _clutter_actor_create_transition (self,
9573 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9576 _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9578 clutter_actor_queue_relayout (self);
9581 clutter_actor_set_y_internal (self, y);
9583 clutter_actor_queue_relayout (self);
9587 * clutter_actor_get_x:
9588 * @self: A #ClutterActor
9590 * Retrieves the X coordinate of a #ClutterActor.
9592 * This function tries to "do what you mean", by returning the
9593 * correct value depending on the actor's state.
9595 * If the actor has a valid allocation, this function will return
9596 * the X coordinate of the origin of the allocation box.
9598 * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9599 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9600 * function will return that coordinate.
9602 * If both the allocation and a fixed position are missing, this function
9605 * Return value: the X coordinate, in pixels, ignoring any
9606 * transformation (i.e. scaling, rotation)
9609 clutter_actor_get_x (ClutterActor *self)
9611 ClutterActorPrivate *priv;
9613 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9617 if (priv->needs_allocation)
9619 if (priv->position_set)
9621 const ClutterLayoutInfo *info;
9623 info = _clutter_actor_get_layout_info_or_defaults (self);
9625 return info->fixed_x;
9631 return priv->allocation.x1;
9635 * clutter_actor_get_y:
9636 * @self: A #ClutterActor
9638 * Retrieves the Y coordinate of a #ClutterActor.
9640 * This function tries to "do what you mean", by returning the
9641 * correct value depending on the actor's state.
9643 * If the actor has a valid allocation, this function will return
9644 * the Y coordinate of the origin of the allocation box.
9646 * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9647 * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9648 * function will return that coordinate.
9650 * If both the allocation and a fixed position are missing, this function
9653 * Return value: the Y coordinate, in pixels, ignoring any
9654 * transformation (i.e. scaling, rotation)
9657 clutter_actor_get_y (ClutterActor *self)
9659 ClutterActorPrivate *priv;
9661 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9665 if (priv->needs_allocation)
9667 if (priv->position_set)
9669 const ClutterLayoutInfo *info;
9671 info = _clutter_actor_get_layout_info_or_defaults (self);
9673 return info->fixed_y;
9679 return priv->allocation.y1;
9683 * clutter_actor_set_scale:
9684 * @self: A #ClutterActor
9685 * @scale_x: double factor to scale actor by horizontally.
9686 * @scale_y: double factor to scale actor by vertically.
9688 * Scales an actor with the given factors. The scaling is relative to
9689 * the scale center and the anchor point. The scale center is
9690 * unchanged by this function and defaults to 0,0.
9692 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9698 clutter_actor_set_scale (ClutterActor *self,
9702 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9704 g_object_freeze_notify (G_OBJECT (self));
9706 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9707 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9709 g_object_thaw_notify (G_OBJECT (self));
9713 * clutter_actor_set_scale_full:
9714 * @self: A #ClutterActor
9715 * @scale_x: double factor to scale actor by horizontally.
9716 * @scale_y: double factor to scale actor by vertically.
9717 * @center_x: X coordinate of the center of the scale.
9718 * @center_y: Y coordinate of the center of the scale
9720 * Scales an actor with the given factors around the given center
9721 * point. The center point is specified in pixels relative to the
9722 * anchor point (usually the top left corner of the actor).
9724 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9730 clutter_actor_set_scale_full (ClutterActor *self,
9736 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9738 g_object_freeze_notify (G_OBJECT (self));
9740 clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9741 clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9742 clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9743 clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9745 g_object_thaw_notify (G_OBJECT (self));
9749 * clutter_actor_set_scale_with_gravity:
9750 * @self: A #ClutterActor
9751 * @scale_x: double factor to scale actor by horizontally.
9752 * @scale_y: double factor to scale actor by vertically.
9753 * @gravity: the location of the scale center expressed as a compass
9756 * Scales an actor with the given factors around the given
9757 * center point. The center point is specified as one of the compass
9758 * directions in #ClutterGravity. For example, setting it to north
9759 * will cause the top of the actor to remain unchanged and the rest of
9760 * the actor to expand left, right and downwards.
9762 * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9768 clutter_actor_set_scale_with_gravity (ClutterActor *self,
9771 ClutterGravity gravity)
9773 ClutterTransformInfo *info;
9776 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9778 obj = G_OBJECT (self);
9780 g_object_freeze_notify (obj);
9782 info = _clutter_actor_get_transform_info (self);
9783 info->scale_x = scale_x;
9784 info->scale_y = scale_y;
9786 if (gravity == CLUTTER_GRAVITY_NONE)
9787 clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
9789 clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
9791 self->priv->transform_valid = FALSE;
9793 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_X]);
9794 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_Y]);
9795 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
9796 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
9797 g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
9799 clutter_actor_queue_redraw (self);
9801 g_object_thaw_notify (obj);
9805 * clutter_actor_get_scale:
9806 * @self: A #ClutterActor
9807 * @scale_x: (out) (allow-none): Location to store horizonal
9808 * scale factor, or %NULL.
9809 * @scale_y: (out) (allow-none): Location to store vertical
9810 * scale factor, or %NULL.
9812 * Retrieves an actors scale factors.
9817 clutter_actor_get_scale (ClutterActor *self,
9821 const ClutterTransformInfo *info;
9823 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9825 info = _clutter_actor_get_transform_info_or_defaults (self);
9828 *scale_x = info->scale_x;
9831 *scale_y = info->scale_y;
9835 * clutter_actor_get_scale_center:
9836 * @self: A #ClutterActor
9837 * @center_x: (out) (allow-none): Location to store the X position
9838 * of the scale center, or %NULL.
9839 * @center_y: (out) (allow-none): Location to store the Y position
9840 * of the scale center, or %NULL.
9842 * Retrieves the scale center coordinate in pixels relative to the top
9843 * left corner of the actor. If the scale center was specified using a
9844 * #ClutterGravity this will calculate the pixel offset using the
9845 * current size of the actor.
9850 clutter_actor_get_scale_center (ClutterActor *self,
9854 const ClutterTransformInfo *info;
9856 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9858 info = _clutter_actor_get_transform_info_or_defaults (self);
9860 clutter_anchor_coord_get_units (self, &info->scale_center,
9867 * clutter_actor_get_scale_gravity:
9868 * @self: A #ClutterActor
9870 * Retrieves the scale center as a compass direction. If the scale
9871 * center was specified in pixels or units this will return
9872 * %CLUTTER_GRAVITY_NONE.
9874 * Return value: the scale gravity
9879 clutter_actor_get_scale_gravity (ClutterActor *self)
9881 const ClutterTransformInfo *info;
9883 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9885 info = _clutter_actor_get_transform_info_or_defaults (self);
9887 return clutter_anchor_coord_get_gravity (&info->scale_center);
9891 clutter_actor_set_opacity_internal (ClutterActor *self,
9894 ClutterActorPrivate *priv = self->priv;
9896 if (priv->opacity != opacity)
9898 priv->opacity = opacity;
9900 /* Queue a redraw from the flatten effect so that it can use
9901 its cached image if available instead of having to redraw the
9902 actual actor. If it doesn't end up using the FBO then the
9903 effect is still able to continue the paint anyway. If there
9904 is no flatten effect yet then this is equivalent to queueing
9906 _clutter_actor_queue_redraw_full (self,
9909 priv->flatten_effect);
9911 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9916 * clutter_actor_set_opacity:
9917 * @self: A #ClutterActor
9918 * @opacity: New opacity value for the actor.
9920 * Sets the actor's opacity, with zero being completely transparent and
9921 * 255 (0xff) being fully opaque.
9923 * The #ClutterActor:opacity property is animatable.
9926 clutter_actor_set_opacity (ClutterActor *self,
9929 ClutterActorPrivate *priv;
9931 g_return_if_fail (CLUTTER_IS_ACTOR (self));
9935 if (clutter_actor_get_easing_duration (self) != 0)
9937 ClutterTransition *transition;
9939 transition = _clutter_actor_get_transition (self, obj_props[PROP_OPACITY]);
9940 if (transition == NULL)
9942 transition = _clutter_actor_create_transition (self,
9943 obj_props[PROP_OPACITY],
9946 clutter_timeline_start (CLUTTER_TIMELINE (transition));
9949 _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
9951 clutter_actor_queue_redraw (self);
9954 clutter_actor_set_opacity_internal (self, opacity);
9958 * clutter_actor_get_paint_opacity_internal:
9959 * @self: a #ClutterActor
9961 * Retrieves the absolute opacity of the actor, as it appears on the stage
9963 * This function does not do type checks
9965 * Return value: the absolute opacity of the actor
9968 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
9970 ClutterActorPrivate *priv = self->priv;
9971 ClutterActor *parent;
9973 /* override the top-level opacity to always be 255; even in
9974 * case of ClutterStage:use-alpha being TRUE we want the rest
9975 * of the scene to be painted
9977 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
9980 if (priv->opacity_override >= 0)
9981 return priv->opacity_override;
9983 parent = priv->parent;
9985 /* Factor in the actual actors opacity with parents */
9988 guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
9990 if (opacity != 0xff)
9991 return (opacity * priv->opacity) / 0xff;
9994 return priv->opacity;
9999 * clutter_actor_get_paint_opacity:
10000 * @self: A #ClutterActor
10002 * Retrieves the absolute opacity of the actor, as it appears on the stage.
10004 * This function traverses the hierarchy chain and composites the opacity of
10005 * the actor with that of its parents.
10007 * This function is intended for subclasses to use in the paint virtual
10008 * function, to paint themselves with the correct opacity.
10010 * Return value: The actor opacity value.
10015 clutter_actor_get_paint_opacity (ClutterActor *self)
10017 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10019 return clutter_actor_get_paint_opacity_internal (self);
10023 * clutter_actor_get_opacity:
10024 * @self: a #ClutterActor
10026 * Retrieves the opacity value of an actor, as set by
10027 * clutter_actor_set_opacity().
10029 * For retrieving the absolute opacity of the actor inside a paint
10030 * virtual function, see clutter_actor_get_paint_opacity().
10032 * Return value: the opacity of the actor
10035 clutter_actor_get_opacity (ClutterActor *self)
10037 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10039 return self->priv->opacity;
10043 * clutter_actor_set_offscreen_redirect:
10044 * @self: A #ClutterActor
10045 * @redirect: New offscreen redirect flags for the actor.
10047 * Defines the circumstances where the actor should be redirected into
10048 * an offscreen image. The offscreen image is used to flatten the
10049 * actor into a single image while painting for two main reasons.
10050 * Firstly, when the actor is painted a second time without any of its
10051 * contents changing it can simply repaint the cached image without
10052 * descending further down the actor hierarchy. Secondly, it will make
10053 * the opacity look correct even if there are overlapping primitives
10056 * Caching the actor could in some cases be a performance win and in
10057 * some cases be a performance lose so it is important to determine
10058 * which value is right for an actor before modifying this value. For
10059 * example, there is never any reason to flatten an actor that is just
10060 * a single texture (such as a #ClutterTexture) because it is
10061 * effectively already cached in an image so the offscreen would be
10062 * redundant. Also if the actor contains primitives that are far apart
10063 * with a large transparent area in the middle (such as a large
10064 * CluterGroup with a small actor in the top left and a small actor in
10065 * the bottom right) then the cached image will contain the entire
10066 * image of the large area and the paint will waste time blending all
10067 * of the transparent pixels in the middle.
10069 * The default method of implementing opacity on a container simply
10070 * forwards on the opacity to all of the children. If the children are
10071 * overlapping then it will appear as if they are two separate glassy
10072 * objects and there will be a break in the color where they
10073 * overlap. By redirecting to an offscreen buffer it will be as if the
10074 * two opaque objects are combined into one and then made transparent
10075 * which is usually what is expected.
10077 * The image below demonstrates the difference between redirecting and
10078 * not. The image shows two Clutter groups, each containing a red and
10079 * a green rectangle which overlap. The opacity on the group is set to
10080 * 128 (which is 50%). When the offscreen redirect is not used, the
10081 * red rectangle can be seen through the blue rectangle as if the two
10082 * rectangles were separately transparent. When the redirect is used
10083 * the group as a whole is transparent instead so the red rectangle is
10084 * not visible where they overlap.
10086 * <figure id="offscreen-redirect">
10087 * <title>Sample of using an offscreen redirect for transparency</title>
10088 * <graphic fileref="offscreen-redirect.png" format="PNG"/>
10091 * The default value for this property is 0, so we effectively will
10092 * never redirect an actor offscreen by default. This means that there
10093 * are times that transparent actors may look glassy as described
10094 * above. The reason this is the default is because there is a
10095 * performance trade off between quality and performance here. In many
10096 * cases the default form of glassy opacity looks good enough, but if
10097 * it's not you will need to set the
10098 * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10099 * redirection for opacity.
10101 * Custom actors that don't contain any overlapping primitives are
10102 * recommended to override the has_overlaps() virtual to return %FALSE
10103 * for maximum efficiency.
10108 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10109 ClutterOffscreenRedirect redirect)
10111 ClutterActorPrivate *priv;
10113 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10117 if (priv->offscreen_redirect != redirect)
10119 priv->offscreen_redirect = redirect;
10121 /* Queue a redraw from the effect so that it can use its cached
10122 image if available instead of having to redraw the actual
10123 actor. If it doesn't end up using the FBO then the effect is
10124 still able to continue the paint anyway. If there is no
10125 effect then this is equivalent to queuing a full redraw */
10126 _clutter_actor_queue_redraw_full (self,
10129 priv->flatten_effect);
10131 g_object_notify_by_pspec (G_OBJECT (self),
10132 obj_props[PROP_OFFSCREEN_REDIRECT]);
10137 * clutter_actor_get_offscreen_redirect:
10138 * @self: a #ClutterActor
10140 * Retrieves whether to redirect the actor to an offscreen buffer, as
10141 * set by clutter_actor_set_offscreen_redirect().
10143 * Return value: the value of the offscreen-redirect property of the actor
10147 ClutterOffscreenRedirect
10148 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10150 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10152 return self->priv->offscreen_redirect;
10156 * clutter_actor_set_name:
10157 * @self: A #ClutterActor
10158 * @name: Textual tag to apply to actor
10160 * Sets the given name to @self. The name can be used to identify
10164 clutter_actor_set_name (ClutterActor *self,
10167 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10169 g_free (self->priv->name);
10170 self->priv->name = g_strdup (name);
10172 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10176 * clutter_actor_get_name:
10177 * @self: A #ClutterActor
10179 * Retrieves the name of @self.
10181 * Return value: the name of the actor, or %NULL. The returned string is
10182 * owned by the actor and should not be modified or freed.
10185 clutter_actor_get_name (ClutterActor *self)
10187 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10189 return self->priv->name;
10193 * clutter_actor_get_gid:
10194 * @self: A #ClutterActor
10196 * Retrieves the unique id for @self.
10198 * Return value: Globally unique value for this object instance.
10202 * Deprecated: 1.8: The id is not used any longer.
10205 clutter_actor_get_gid (ClutterActor *self)
10207 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10209 return self->priv->id;
10213 clutter_actor_set_depth_internal (ClutterActor *self,
10216 ClutterTransformInfo *info;
10218 info = _clutter_actor_get_transform_info (self);
10220 if (info->depth != depth)
10222 /* Sets Z value - XXX 2.0: should we invert? */
10223 info->depth = depth;
10225 self->priv->transform_valid = FALSE;
10227 /* FIXME - remove this crap; sadly, there are still containers
10228 * in Clutter that depend on this utter brain damage
10230 clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10232 clutter_actor_queue_redraw (self);
10234 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10239 * clutter_actor_set_depth:
10240 * @self: a #ClutterActor
10243 * Sets the Z coordinate of @self to @depth.
10245 * The unit used by @depth is dependant on the perspective setup. See
10246 * also clutter_stage_set_perspective().
10249 clutter_actor_set_depth (ClutterActor *self,
10252 const ClutterTransformInfo *tinfo;
10254 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10256 tinfo = _clutter_actor_get_transform_info_or_defaults (self);
10258 if (clutter_actor_get_easing_duration (self) != 0)
10260 ClutterTransition *transition;
10262 transition = _clutter_actor_get_transition (self, obj_props[PROP_DEPTH]);
10263 if (transition == NULL)
10265 transition = _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10268 clutter_timeline_start (CLUTTER_TIMELINE (transition));
10271 _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10273 clutter_actor_queue_redraw (self);
10276 clutter_actor_set_depth_internal (self, depth);
10280 * clutter_actor_get_depth:
10281 * @self: a #ClutterActor
10283 * Retrieves the depth of @self.
10285 * Return value: the depth of the actor
10288 clutter_actor_get_depth (ClutterActor *self)
10290 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10292 return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10296 * clutter_actor_set_rotation:
10297 * @self: a #ClutterActor
10298 * @axis: the axis of rotation
10299 * @angle: the angle of rotation
10300 * @x: X coordinate of the rotation center
10301 * @y: Y coordinate of the rotation center
10302 * @z: Z coordinate of the rotation center
10304 * Sets the rotation angle of @self around the given axis.
10306 * The rotation center coordinates used depend on the value of @axis:
10308 * <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10309 * <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10310 * <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10313 * The rotation coordinates are relative to the anchor point of the
10314 * actor, set using clutter_actor_set_anchor_point(). If no anchor
10315 * point is set, the upper left corner is assumed as the origin.
10320 clutter_actor_set_rotation (ClutterActor *self,
10321 ClutterRotateAxis axis,
10329 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10335 g_object_freeze_notify (G_OBJECT (self));
10337 clutter_actor_set_rotation_angle (self, axis, angle);
10338 clutter_actor_set_rotation_center_internal (self, axis, &v);
10340 g_object_thaw_notify (G_OBJECT (self));
10344 * clutter_actor_set_z_rotation_from_gravity:
10345 * @self: a #ClutterActor
10346 * @angle: the angle of rotation
10347 * @gravity: the center point of the rotation
10349 * Sets the rotation angle of @self around the Z axis using the center
10350 * point specified as a compass point. For example to rotate such that
10351 * the center of the actor remains static you can use
10352 * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10353 * will move accordingly.
10358 clutter_actor_set_z_rotation_from_gravity (ClutterActor *self,
10360 ClutterGravity gravity)
10362 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10364 if (gravity == CLUTTER_GRAVITY_NONE)
10365 clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10368 GObject *obj = G_OBJECT (self);
10369 ClutterTransformInfo *info;
10371 info = _clutter_actor_get_transform_info (self);
10373 g_object_freeze_notify (obj);
10375 clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10377 clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10378 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10379 g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10381 g_object_thaw_notify (obj);
10386 * clutter_actor_get_rotation:
10387 * @self: a #ClutterActor
10388 * @axis: the axis of rotation
10389 * @x: (out): return value for the X coordinate of the center of rotation
10390 * @y: (out): return value for the Y coordinate of the center of rotation
10391 * @z: (out): return value for the Z coordinate of the center of rotation
10393 * Retrieves the angle and center of rotation on the given axis,
10394 * set using clutter_actor_set_rotation().
10396 * Return value: the angle of rotation
10401 clutter_actor_get_rotation (ClutterActor *self,
10402 ClutterRotateAxis axis,
10407 const ClutterTransformInfo *info;
10408 const AnchorCoord *anchor_coord;
10409 gdouble retval = 0;
10411 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10413 info = _clutter_actor_get_transform_info_or_defaults (self);
10417 case CLUTTER_X_AXIS:
10418 anchor_coord = &info->rx_center;
10419 retval = info->rx_angle;
10422 case CLUTTER_Y_AXIS:
10423 anchor_coord = &info->ry_center;
10424 retval = info->ry_angle;
10427 case CLUTTER_Z_AXIS:
10428 anchor_coord = &info->rz_center;
10429 retval = info->rz_angle;
10433 anchor_coord = NULL;
10438 clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10444 * clutter_actor_get_z_rotation_gravity:
10445 * @self: A #ClutterActor
10447 * Retrieves the center for the rotation around the Z axis as a
10448 * compass direction. If the center was specified in pixels or units
10449 * this will return %CLUTTER_GRAVITY_NONE.
10451 * Return value: the Z rotation center
10456 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10458 const ClutterTransformInfo *info;
10460 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10462 info = _clutter_actor_get_transform_info_or_defaults (self);
10464 return clutter_anchor_coord_get_gravity (&info->rz_center);
10468 * clutter_actor_set_clip:
10469 * @self: A #ClutterActor
10470 * @xoff: X offset of the clip rectangle
10471 * @yoff: Y offset of the clip rectangle
10472 * @width: Width of the clip rectangle
10473 * @height: Height of the clip rectangle
10475 * Sets clip area for @self. The clip area is always computed from the
10476 * upper left corner of the actor, even if the anchor point is set
10482 clutter_actor_set_clip (ClutterActor *self,
10488 ClutterActorPrivate *priv;
10490 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10494 if (priv->has_clip &&
10495 priv->clip.x == xoff &&
10496 priv->clip.y == yoff &&
10497 priv->clip.width == width &&
10498 priv->clip.height == height)
10501 priv->clip.x = xoff;
10502 priv->clip.y = yoff;
10503 priv->clip.width = width;
10504 priv->clip.height = height;
10506 priv->has_clip = TRUE;
10508 clutter_actor_queue_redraw (self);
10510 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10511 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10515 * clutter_actor_remove_clip:
10516 * @self: A #ClutterActor
10518 * Removes clip area from @self.
10521 clutter_actor_remove_clip (ClutterActor *self)
10523 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10525 if (!self->priv->has_clip)
10528 self->priv->has_clip = FALSE;
10530 clutter_actor_queue_redraw (self);
10532 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10536 * clutter_actor_has_clip:
10537 * @self: a #ClutterActor
10539 * Determines whether the actor has a clip area set or not.
10541 * Return value: %TRUE if the actor has a clip area set.
10546 clutter_actor_has_clip (ClutterActor *self)
10548 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10550 return self->priv->has_clip;
10554 * clutter_actor_get_clip:
10555 * @self: a #ClutterActor
10556 * @xoff: (out) (allow-none): return location for the X offset of
10557 * the clip rectangle, or %NULL
10558 * @yoff: (out) (allow-none): return location for the Y offset of
10559 * the clip rectangle, or %NULL
10560 * @width: (out) (allow-none): return location for the width of
10561 * the clip rectangle, or %NULL
10562 * @height: (out) (allow-none): return location for the height of
10563 * the clip rectangle, or %NULL
10565 * Gets the clip area for @self, if any is set
10570 clutter_actor_get_clip (ClutterActor *self,
10576 ClutterActorPrivate *priv;
10578 g_return_if_fail (CLUTTER_IS_ACTOR (self));
10582 if (!priv->has_clip)
10586 *xoff = priv->clip.x;
10589 *yoff = priv->clip.y;
10592 *width = priv->clip.width;
10594 if (height != NULL)
10595 *height = priv->clip.height;
10599 * clutter_actor_get_children:
10600 * @self: a #ClutterActor
10602 * Retrieves the list of children of @self.
10604 * Return value: (transfer container) (element-type ClutterActor): A newly
10605 * allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10611 clutter_actor_get_children (ClutterActor *self)
10613 ClutterActor *iter;
10616 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10618 /* we walk the list backward so that we can use prepend(),
10621 for (iter = self->priv->last_child, res = NULL;
10623 iter = iter->priv->prev_sibling)
10625 res = g_list_prepend (res, iter);
10632 * insert_child_at_depth:
10633 * @self: a #ClutterActor
10634 * @child: a #ClutterActor
10636 * Inserts @child inside the list of children held by @self, using
10637 * the depth as the insertion criteria.
10639 * This sadly makes the insertion not O(1), but we can keep the
10640 * list sorted so that the painters algorithm we use for painting
10641 * the children will work correctly.
10644 insert_child_at_depth (ClutterActor *self,
10645 ClutterActor *child,
10646 gpointer dummy G_GNUC_UNUSED)
10648 ClutterActor *iter;
10651 child->priv->parent = self;
10654 _clutter_actor_get_transform_info_or_defaults (child)->depth;
10656 /* special-case the first child */
10657 if (self->priv->n_children == 0)
10659 self->priv->first_child = child;
10660 self->priv->last_child = child;
10662 child->priv->next_sibling = NULL;
10663 child->priv->prev_sibling = NULL;
10668 /* Find the right place to insert the child so that it will still be
10669 sorted and the child will be after all of the actors at the same
10671 for (iter = self->priv->first_child;
10673 iter = iter->priv->next_sibling)
10678 _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10680 if (iter_depth > child_depth)
10686 ClutterActor *tmp = iter->priv->prev_sibling;
10689 tmp->priv->next_sibling = child;
10691 /* Insert the node before the found one */
10692 child->priv->prev_sibling = iter->priv->prev_sibling;
10693 child->priv->next_sibling = iter;
10694 iter->priv->prev_sibling = child;
10698 ClutterActor *tmp = self->priv->last_child;
10701 tmp->priv->next_sibling = child;
10703 /* insert the node at the end of the list */
10704 child->priv->prev_sibling = self->priv->last_child;
10705 child->priv->next_sibling = NULL;
10708 if (child->priv->prev_sibling == NULL)
10709 self->priv->first_child = child;
10711 if (child->priv->next_sibling == NULL)
10712 self->priv->last_child = child;
10716 insert_child_at_index (ClutterActor *self,
10717 ClutterActor *child,
10720 gint index_ = GPOINTER_TO_INT (data_);
10722 child->priv->parent = self;
10726 ClutterActor *tmp = self->priv->first_child;
10729 tmp->priv->prev_sibling = child;
10731 child->priv->prev_sibling = NULL;
10732 child->priv->next_sibling = tmp;
10734 else if (index_ < 0 || index_ >= self->priv->n_children)
10736 ClutterActor *tmp = self->priv->last_child;
10739 tmp->priv->next_sibling = child;
10741 child->priv->prev_sibling = tmp;
10742 child->priv->next_sibling = NULL;
10746 ClutterActor *iter;
10749 for (iter = self->priv->first_child, i = 0;
10751 iter = iter->priv->next_sibling, i += 1)
10755 ClutterActor *tmp = iter->priv->prev_sibling;
10757 child->priv->prev_sibling = tmp;
10758 child->priv->next_sibling = iter;
10760 iter->priv->prev_sibling = child;
10763 tmp->priv->next_sibling = child;
10770 if (child->priv->prev_sibling == NULL)
10771 self->priv->first_child = child;
10773 if (child->priv->next_sibling == NULL)
10774 self->priv->last_child = child;
10778 insert_child_above (ClutterActor *self,
10779 ClutterActor *child,
10782 ClutterActor *sibling = data;
10784 child->priv->parent = self;
10786 if (sibling == NULL)
10787 sibling = self->priv->last_child;
10789 child->priv->prev_sibling = sibling;
10791 if (sibling != NULL)
10793 ClutterActor *tmp = sibling->priv->next_sibling;
10795 child->priv->next_sibling = tmp;
10798 tmp->priv->prev_sibling = child;
10800 sibling->priv->next_sibling = child;
10803 child->priv->next_sibling = NULL;
10805 if (child->priv->prev_sibling == NULL)
10806 self->priv->first_child = child;
10808 if (child->priv->next_sibling == NULL)
10809 self->priv->last_child = child;
10813 insert_child_below (ClutterActor *self,
10814 ClutterActor *child,
10817 ClutterActor *sibling = data;
10819 child->priv->parent = self;
10821 if (sibling == NULL)
10822 sibling = self->priv->first_child;
10824 child->priv->next_sibling = sibling;
10826 if (sibling != NULL)
10828 ClutterActor *tmp = sibling->priv->prev_sibling;
10830 child->priv->prev_sibling = tmp;
10833 tmp->priv->next_sibling = child;
10835 sibling->priv->prev_sibling = child;
10838 child->priv->prev_sibling = NULL;
10840 if (child->priv->prev_sibling == NULL)
10841 self->priv->first_child = child;
10843 if (child->priv->next_sibling == NULL)
10844 self->priv->last_child = child;
10847 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10848 ClutterActor *child,
10852 ADD_CHILD_CREATE_META = 1 << 0,
10853 ADD_CHILD_EMIT_PARENT_SET = 1 << 1,
10854 ADD_CHILD_EMIT_ACTOR_ADDED = 1 << 2,
10855 ADD_CHILD_CHECK_STATE = 1 << 3,
10856 ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10858 /* default flags for public API */
10859 ADD_CHILD_DEFAULT_FLAGS = ADD_CHILD_CREATE_META |
10860 ADD_CHILD_EMIT_PARENT_SET |
10861 ADD_CHILD_EMIT_ACTOR_ADDED |
10862 ADD_CHILD_CHECK_STATE |
10863 ADD_CHILD_NOTIFY_FIRST_LAST,
10865 /* flags for legacy/deprecated API */
10866 ADD_CHILD_LEGACY_FLAGS = ADD_CHILD_EMIT_PARENT_SET |
10867 ADD_CHILD_CHECK_STATE |
10868 ADD_CHILD_NOTIFY_FIRST_LAST
10869 } ClutterActorAddChildFlags;
10872 * clutter_actor_add_child_internal:
10873 * @self: a #ClutterActor
10874 * @child: a #ClutterActor
10875 * @flags: control flags for actions
10876 * @add_func: delegate function
10877 * @data: (closure): data to pass to @add_func
10879 * Adds @child to the list of children of @self.
10881 * The actual insertion inside the list is delegated to @add_func: this
10882 * function will just set up the state, perform basic checks, and emit
10885 * The @flags argument is used to perform additional operations.
10888 clutter_actor_add_child_internal (ClutterActor *self,
10889 ClutterActor *child,
10890 ClutterActorAddChildFlags flags,
10891 ClutterActorAddChildFunc add_func,
10894 ClutterTextDirection text_dir;
10895 gboolean create_meta;
10896 gboolean emit_parent_set, emit_actor_added;
10897 gboolean check_state;
10898 gboolean notify_first_last;
10899 ClutterActor *old_first_child, *old_last_child;
10901 if (child->priv->parent != NULL)
10903 g_warning ("The actor '%s' already has a parent, '%s'. You must "
10904 "use clutter_actor_remove_child() first.",
10905 _clutter_actor_get_debug_name (child),
10906 _clutter_actor_get_debug_name (child->priv->parent));
10910 if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10912 g_warning ("The actor '%s' is a top-level actor, and cannot be "
10913 "a child of another actor.",
10914 _clutter_actor_get_debug_name (child));
10919 /* XXX - this check disallows calling methods that change the stacking
10920 * order within the destruction sequence, by triggering a critical
10921 * warning first, and leaving the actor in an undefined state, which
10922 * then ends up being caught by an assertion.
10924 * the reproducible sequence is:
10926 * - actor gets destroyed;
10927 * - another actor, linked to the first, will try to change the
10928 * stacking order of the first actor;
10929 * - changing the stacking order is a composite operation composed
10930 * by the following steps:
10931 * 1. ref() the child;
10932 * 2. remove_child_internal(), which removes the reference;
10933 * 3. add_child_internal(), which adds a reference;
10934 * - the state of the actor is not changed between (2) and (3), as
10935 * it could be an expensive recomputation;
10936 * - if (3) bails out, then the actor is in an undefined state, but
10938 * - the destruction sequence terminates, but the actor is unparented
10939 * while its state indicates being parented instead.
10940 * - assertion failure.
10942 * the obvious fix would be to decompose each set_child_*_sibling()
10943 * method into proper remove_child()/add_child(), with state validation;
10944 * this may cause excessive work, though, and trigger a cascade of other
10945 * bugs in code that assumes that a change in the stacking order is an
10946 * atomic operation.
10948 * another potential fix is to just remove this check here, and let
10949 * code doing stacking order changes inside the destruction sequence
10950 * of an actor continue doing the work.
10952 * the third fix is to silently bail out early from every
10953 * set_child_*_sibling() and set_child_at_index() method, and avoid
10956 * I have a preference for the second solution, since it involves the
10957 * least amount of work, and the least amount of code duplication.
10959 * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
10961 if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
10963 g_warning ("The actor '%s' is currently being destroyed, and "
10964 "cannot be added as a child of another actor.",
10965 _clutter_actor_get_debug_name (child));
10970 create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
10971 emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
10972 emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
10973 check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
10974 notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
10976 old_first_child = self->priv->first_child;
10977 old_last_child = self->priv->last_child;
10979 g_object_freeze_notify (G_OBJECT (self));
10982 clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
10984 g_object_ref_sink (child);
10985 child->priv->parent = NULL;
10986 child->priv->next_sibling = NULL;
10987 child->priv->prev_sibling = NULL;
10989 /* delegate the actual insertion */
10990 add_func (self, child, data);
10992 g_assert (child->priv->parent == self);
10994 self->priv->n_children += 1;
10996 self->priv->age += 1;
10998 /* if push_internal() has been called then we automatically set
10999 * the flag on the actor
11001 if (self->priv->internal_child)
11002 CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11004 /* clutter_actor_reparent() will emit ::parent-set for us */
11005 if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11006 g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11010 /* If parent is mapped or realized, we need to also be mapped or
11011 * realized once we're inside the parent.
11013 clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11015 /* propagate the parent's text direction to the child */
11016 text_dir = clutter_actor_get_text_direction (self);
11017 clutter_actor_set_text_direction (child, text_dir);
11020 if (child->priv->show_on_set_parent)
11021 clutter_actor_show (child);
11023 if (CLUTTER_ACTOR_IS_MAPPED (child))
11024 clutter_actor_queue_redraw (child);
11026 /* maintain the invariant that if an actor needs layout,
11027 * its parents do as well
11029 if (child->priv->needs_width_request ||
11030 child->priv->needs_height_request ||
11031 child->priv->needs_allocation)
11033 /* we work around the short-circuiting we do
11034 * in clutter_actor_queue_relayout() since we
11035 * want to force a relayout
11037 child->priv->needs_width_request = TRUE;
11038 child->priv->needs_height_request = TRUE;
11039 child->priv->needs_allocation = TRUE;
11041 clutter_actor_queue_relayout (child->priv->parent);
11044 if (emit_actor_added)
11045 g_signal_emit_by_name (self, "actor-added", child);
11047 if (notify_first_last)
11049 if (old_first_child != self->priv->first_child)
11050 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11052 if (old_last_child != self->priv->last_child)
11053 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11056 g_object_thaw_notify (G_OBJECT (self));
11060 * clutter_actor_add_child:
11061 * @self: a #ClutterActor
11062 * @child: a #ClutterActor
11064 * Adds @child to the children of @self.
11066 * This function will acquire a reference on @child that will only
11067 * be released when calling clutter_actor_remove_child().
11069 * This function will take into consideration the #ClutterActor:depth
11070 * of @child, and will keep the list of children sorted.
11072 * This function will emit the #ClutterContainer::actor-added signal
11078 clutter_actor_add_child (ClutterActor *self,
11079 ClutterActor *child)
11081 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11082 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11083 g_return_if_fail (self != child);
11084 g_return_if_fail (child->priv->parent == NULL);
11086 clutter_actor_add_child_internal (self, child,
11087 ADD_CHILD_DEFAULT_FLAGS,
11088 insert_child_at_depth,
11093 * clutter_actor_insert_child_at_index:
11094 * @self: a #ClutterActor
11095 * @child: a #ClutterActor
11096 * @index_: the index
11098 * Inserts @child into the list of children of @self, using the
11099 * given @index_. If @index_ is greater than the number of children
11100 * in @self, or is less than 0, then the new child is added at the end.
11102 * This function will acquire a reference on @child that will only
11103 * be released when calling clutter_actor_remove_child().
11105 * This function will not take into consideration the #ClutterActor:depth
11108 * This function will emit the #ClutterContainer::actor-added signal
11114 clutter_actor_insert_child_at_index (ClutterActor *self,
11115 ClutterActor *child,
11118 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11119 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11120 g_return_if_fail (self != child);
11121 g_return_if_fail (child->priv->parent == NULL);
11123 clutter_actor_add_child_internal (self, child,
11124 ADD_CHILD_DEFAULT_FLAGS,
11125 insert_child_at_index,
11126 GINT_TO_POINTER (index_));
11130 * clutter_actor_insert_child_above:
11131 * @self: a #ClutterActor
11132 * @child: a #ClutterActor
11133 * @sibling: (allow-none): a child of @self, or %NULL
11135 * Inserts @child into the list of children of @self, above another
11136 * child of @self or, if @sibling is %NULL, above all the children
11139 * This function will acquire a reference on @child that will only
11140 * be released when calling clutter_actor_remove_child().
11142 * This function will not take into consideration the #ClutterActor:depth
11145 * This function will emit the #ClutterContainer::actor-added signal
11151 clutter_actor_insert_child_above (ClutterActor *self,
11152 ClutterActor *child,
11153 ClutterActor *sibling)
11155 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11156 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11157 g_return_if_fail (self != child);
11158 g_return_if_fail (child != sibling);
11159 g_return_if_fail (child->priv->parent == NULL);
11160 g_return_if_fail (sibling == NULL ||
11161 (CLUTTER_IS_ACTOR (sibling) &&
11162 sibling->priv->parent == self));
11164 clutter_actor_add_child_internal (self, child,
11165 ADD_CHILD_DEFAULT_FLAGS,
11166 insert_child_above,
11171 * clutter_actor_insert_child_below:
11172 * @self: a #ClutterActor
11173 * @child: a #ClutterActor
11174 * @sibling: (allow-none): a child of @self, or %NULL
11176 * Inserts @child into the list of children of @self, below another
11177 * child of @self or, if @sibling is %NULL, below all the children
11180 * This function will acquire a reference on @child that will only
11181 * be released when calling clutter_actor_remove_child().
11183 * This function will not take into consideration the #ClutterActor:depth
11186 * This function will emit the #ClutterContainer::actor-added signal
11192 clutter_actor_insert_child_below (ClutterActor *self,
11193 ClutterActor *child,
11194 ClutterActor *sibling)
11196 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11197 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11198 g_return_if_fail (self != child);
11199 g_return_if_fail (child != sibling);
11200 g_return_if_fail (child->priv->parent == NULL);
11201 g_return_if_fail (sibling == NULL ||
11202 (CLUTTER_IS_ACTOR (sibling) &&
11203 sibling->priv->parent == self));
11205 clutter_actor_add_child_internal (self, child,
11206 ADD_CHILD_DEFAULT_FLAGS,
11207 insert_child_below,
11212 * clutter_actor_set_parent:
11213 * @self: A #ClutterActor
11214 * @parent: A new #ClutterActor parent
11216 * Sets the parent of @self to @parent.
11218 * This function will result in @parent acquiring a reference on @self,
11219 * eventually by sinking its floating reference first. The reference
11220 * will be released by clutter_actor_unparent().
11222 * This function should only be called by legacy #ClutterActor<!-- -->s
11223 * implementing the #ClutterContainer interface.
11225 * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11228 clutter_actor_set_parent (ClutterActor *self,
11229 ClutterActor *parent)
11231 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11232 g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11233 g_return_if_fail (self != parent);
11234 g_return_if_fail (self->priv->parent == NULL);
11236 /* as this function will be called inside ClutterContainer::add
11237 * implementations or when building up a composite actor, we have
11238 * to preserve the old behaviour, and not create child meta or
11239 * emit the ::actor-added signal, to avoid recursion or double
11242 clutter_actor_add_child_internal (parent, self,
11243 ADD_CHILD_LEGACY_FLAGS,
11244 insert_child_at_depth,
11249 * clutter_actor_get_parent:
11250 * @self: A #ClutterActor
11252 * Retrieves the parent of @self.
11254 * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11255 * if no parent is set
11258 clutter_actor_get_parent (ClutterActor *self)
11260 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11262 return self->priv->parent;
11266 * clutter_actor_get_paint_visibility:
11267 * @self: A #ClutterActor
11269 * Retrieves the 'paint' visibility of an actor recursively checking for non
11272 * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11274 * Return Value: %TRUE if the actor is visibile and will be painted.
11279 clutter_actor_get_paint_visibility (ClutterActor *actor)
11281 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11283 return CLUTTER_ACTOR_IS_MAPPED (actor);
11287 * clutter_actor_remove_child:
11288 * @self: a #ClutterActor
11289 * @child: a #ClutterActor
11291 * Removes @child from the children of @self.
11293 * This function will release the reference added by
11294 * clutter_actor_add_child(), so if you want to keep using @child
11295 * you will have to acquire a referenced on it before calling this
11298 * This function will emit the #ClutterContainer::actor-removed
11304 clutter_actor_remove_child (ClutterActor *self,
11305 ClutterActor *child)
11307 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11308 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11309 g_return_if_fail (self != child);
11310 g_return_if_fail (child->priv->parent != NULL);
11311 g_return_if_fail (child->priv->parent == self);
11313 clutter_actor_remove_child_internal (self, child,
11314 REMOVE_CHILD_DEFAULT_FLAGS);
11318 * clutter_actor_remove_all_children:
11319 * @self: a #ClutterActor
11321 * Removes all children of @self.
11323 * This function releases the reference added by inserting a child actor
11324 * in the list of children of @self.
11326 * If the reference count of a child drops to zero, the child will be
11327 * destroyed. If you want to ensure the destruction of all the children
11328 * of @self, use clutter_actor_destroy_all_children().
11333 clutter_actor_remove_all_children (ClutterActor *self)
11335 ClutterActorIter iter;
11337 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11339 if (self->priv->n_children == 0)
11342 g_object_freeze_notify (G_OBJECT (self));
11344 clutter_actor_iter_init (&iter, self);
11345 while (clutter_actor_iter_next (&iter, NULL))
11346 clutter_actor_iter_remove (&iter);
11348 g_object_thaw_notify (G_OBJECT (self));
11351 g_assert (self->priv->first_child == NULL);
11352 g_assert (self->priv->last_child == NULL);
11353 g_assert (self->priv->n_children == 0);
11357 * clutter_actor_destroy_all_children:
11358 * @self: a #ClutterActor
11360 * Destroys all children of @self.
11362 * This function releases the reference added by inserting a child
11363 * actor in the list of children of @self, and ensures that the
11364 * #ClutterActor::destroy signal is emitted on each child of the
11367 * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11368 * when its reference count drops to 0; the default handler of the
11369 * #ClutterActor::destroy signal will destroy all the children of an
11370 * actor. This function ensures that all children are destroyed, instead
11371 * of just removed from @self, unlike clutter_actor_remove_all_children()
11372 * which will merely release the reference and remove each child.
11374 * Unless you acquired an additional reference on each child of @self
11375 * prior to calling clutter_actor_remove_all_children() and want to reuse
11376 * the actors, you should use clutter_actor_destroy_all_children() in
11377 * order to make sure that children are destroyed and signal handlers
11378 * are disconnected even in cases where circular references prevent this
11379 * from automatically happening through reference counting alone.
11384 clutter_actor_destroy_all_children (ClutterActor *self)
11386 ClutterActorIter iter;
11388 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11390 if (self->priv->n_children == 0)
11393 g_object_freeze_notify (G_OBJECT (self));
11395 clutter_actor_iter_init (&iter, self);
11396 while (clutter_actor_iter_next (&iter, NULL))
11397 clutter_actor_iter_destroy (&iter);
11399 g_object_thaw_notify (G_OBJECT (self));
11402 g_assert (self->priv->first_child == NULL);
11403 g_assert (self->priv->last_child == NULL);
11404 g_assert (self->priv->n_children == 0);
11407 typedef struct _InsertBetweenData {
11408 ClutterActor *prev_sibling;
11409 ClutterActor *next_sibling;
11410 } InsertBetweenData;
11413 insert_child_between (ClutterActor *self,
11414 ClutterActor *child,
11417 InsertBetweenData *data = data_;
11418 ClutterActor *prev_sibling = data->prev_sibling;
11419 ClutterActor *next_sibling = data->next_sibling;
11421 child->priv->parent = self;
11422 child->priv->prev_sibling = prev_sibling;
11423 child->priv->next_sibling = next_sibling;
11425 if (prev_sibling != NULL)
11426 prev_sibling->priv->next_sibling = child;
11428 if (next_sibling != NULL)
11429 next_sibling->priv->prev_sibling = child;
11431 if (child->priv->prev_sibling == NULL)
11432 self->priv->first_child = child;
11434 if (child->priv->next_sibling == NULL)
11435 self->priv->last_child = child;
11439 * clutter_actor_replace_child:
11440 * @self: a #ClutterActor
11441 * @old_child: the child of @self to replace
11442 * @new_child: the #ClutterActor to replace @old_child
11444 * Replaces @old_child with @new_child in the list of children of @self.
11449 clutter_actor_replace_child (ClutterActor *self,
11450 ClutterActor *old_child,
11451 ClutterActor *new_child)
11453 ClutterActor *prev_sibling, *next_sibling;
11454 InsertBetweenData clos;
11456 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11457 g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11458 g_return_if_fail (old_child->priv->parent == self);
11459 g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11460 g_return_if_fail (old_child != new_child);
11461 g_return_if_fail (new_child != self);
11462 g_return_if_fail (new_child->priv->parent == NULL);
11464 prev_sibling = old_child->priv->prev_sibling;
11465 next_sibling = old_child->priv->next_sibling;
11466 clutter_actor_remove_child_internal (self, old_child,
11467 REMOVE_CHILD_DEFAULT_FLAGS);
11469 clos.prev_sibling = prev_sibling;
11470 clos.next_sibling = next_sibling;
11471 clutter_actor_add_child_internal (self, new_child,
11472 ADD_CHILD_DEFAULT_FLAGS,
11473 insert_child_between,
11478 * clutter_actor_unparent:
11479 * @self: a #ClutterActor
11481 * Removes the parent of @self.
11483 * This will cause the parent of @self to release the reference
11484 * acquired when calling clutter_actor_set_parent(), so if you
11485 * want to keep @self you will have to acquire a reference of
11486 * your own, through g_object_ref().
11488 * This function should only be called by legacy #ClutterActor<!-- -->s
11489 * implementing the #ClutterContainer interface.
11493 * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11496 clutter_actor_unparent (ClutterActor *self)
11498 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11500 if (self->priv->parent == NULL)
11503 clutter_actor_remove_child_internal (self->priv->parent, self,
11504 REMOVE_CHILD_LEGACY_FLAGS);
11508 * clutter_actor_reparent:
11509 * @self: a #ClutterActor
11510 * @new_parent: the new #ClutterActor parent
11512 * Resets the parent actor of @self.
11514 * This function is logically equivalent to calling clutter_actor_unparent()
11515 * and clutter_actor_set_parent(), but more efficiently implemented, as it
11516 * ensures the child is not finalized when unparented, and emits the
11517 * #ClutterActor::parent-set signal only once.
11519 * In reality, calling this function is less useful than it sounds, as some
11520 * application code may rely on changes in the intermediate state between
11521 * removal and addition of the actor from its old parent to the @new_parent.
11522 * Thus, it is strongly encouraged to avoid using this function in application
11527 * Deprecated: 1.10: Use clutter_actor_remove_child() and
11528 * clutter_actor_add_child() instead; remember to take a reference on
11529 * the actor being removed before calling clutter_actor_remove_child()
11530 * to avoid the reference count dropping to zero and the actor being
11534 clutter_actor_reparent (ClutterActor *self,
11535 ClutterActor *new_parent)
11537 ClutterActorPrivate *priv;
11539 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11540 g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11541 g_return_if_fail (self != new_parent);
11543 if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11545 g_warning ("Cannot set a parent on a toplevel actor");
11549 if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11551 g_warning ("Cannot set a parent currently being destroyed");
11557 if (priv->parent != new_parent)
11559 ClutterActor *old_parent;
11561 CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11563 old_parent = priv->parent;
11565 g_object_ref (self);
11567 if (old_parent != NULL)
11569 /* go through the Container implementation if this is a regular
11570 * child and not an internal one
11572 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11574 ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11576 /* this will have to call unparent() */
11577 clutter_container_remove_actor (parent, self);
11580 clutter_actor_remove_child_internal (old_parent, self,
11581 REMOVE_CHILD_LEGACY_FLAGS);
11584 /* Note, will call set_parent() */
11585 if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11586 clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11588 clutter_actor_add_child_internal (new_parent, self,
11589 ADD_CHILD_LEGACY_FLAGS,
11590 insert_child_at_depth,
11593 /* we emit the ::parent-set signal once */
11594 g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11596 CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11598 /* the IN_REPARENT flag suspends state updates */
11599 clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11601 g_object_unref (self);
11606 * clutter_actor_contains:
11607 * @self: A #ClutterActor
11608 * @descendant: A #ClutterActor, possibly contained in @self
11610 * Determines if @descendant is contained inside @self (either as an
11611 * immediate child, or as a deeper descendant). If @self and
11612 * @descendant point to the same actor then it will also return %TRUE.
11614 * Return value: whether @descendent is contained within @self
11619 clutter_actor_contains (ClutterActor *self,
11620 ClutterActor *descendant)
11622 ClutterActor *actor;
11624 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11625 g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11627 for (actor = descendant; actor; actor = actor->priv->parent)
11635 * clutter_actor_set_child_above_sibling:
11636 * @self: a #ClutterActor
11637 * @child: a #ClutterActor child of @self
11638 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11640 * Sets @child to be above @sibling in the list of children of @self.
11642 * If @sibling is %NULL, @child will be the new last child of @self.
11644 * This function is logically equivalent to removing @child and using
11645 * clutter_actor_insert_child_above(), but it will not emit signals
11646 * or change state on @child.
11651 clutter_actor_set_child_above_sibling (ClutterActor *self,
11652 ClutterActor *child,
11653 ClutterActor *sibling)
11655 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11656 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11657 g_return_if_fail (child->priv->parent == self);
11658 g_return_if_fail (child != sibling);
11659 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11661 if (sibling != NULL)
11662 g_return_if_fail (sibling->priv->parent == self);
11664 /* we don't want to change the state of child, or emit signals, or
11665 * regenerate ChildMeta instances here, but we still want to follow
11666 * the correct sequence of steps encoded in remove_child() and
11667 * add_child(), so that correctness is ensured, and we only go
11668 * through one known code path.
11670 g_object_ref (child);
11671 clutter_actor_remove_child_internal (self, child, 0);
11672 clutter_actor_add_child_internal (self, child,
11673 ADD_CHILD_NOTIFY_FIRST_LAST,
11674 insert_child_above,
11677 clutter_actor_queue_relayout (self);
11681 * clutter_actor_set_child_below_sibling:
11682 * @self: a #ClutterActor
11683 * @child: a #ClutterActor child of @self
11684 * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11686 * Sets @child to be below @sibling in the list of children of @self.
11688 * If @sibling is %NULL, @child will be the new first child of @self.
11690 * This function is logically equivalent to removing @self and using
11691 * clutter_actor_insert_child_below(), but it will not emit signals
11692 * or change state on @child.
11697 clutter_actor_set_child_below_sibling (ClutterActor *self,
11698 ClutterActor *child,
11699 ClutterActor *sibling)
11701 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11702 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11703 g_return_if_fail (child->priv->parent == self);
11704 g_return_if_fail (child != sibling);
11705 g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11707 if (sibling != NULL)
11708 g_return_if_fail (sibling->priv->parent == self);
11710 /* see the comment in set_child_above_sibling() */
11711 g_object_ref (child);
11712 clutter_actor_remove_child_internal (self, child, 0);
11713 clutter_actor_add_child_internal (self, child,
11714 ADD_CHILD_NOTIFY_FIRST_LAST,
11715 insert_child_below,
11718 clutter_actor_queue_relayout (self);
11722 * clutter_actor_set_child_at_index:
11723 * @self: a #ClutterActor
11724 * @child: a #ClutterActor child of @self
11725 * @index_: the new index for @child
11727 * Changes the index of @child in the list of children of @self.
11729 * This function is logically equivalent to removing @child and
11730 * calling clutter_actor_insert_child_at_index(), but it will not
11731 * emit signals or change state on @child.
11736 clutter_actor_set_child_at_index (ClutterActor *self,
11737 ClutterActor *child,
11740 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11741 g_return_if_fail (CLUTTER_IS_ACTOR (child));
11742 g_return_if_fail (child->priv->parent == self);
11743 g_return_if_fail (index_ <= self->priv->n_children);
11745 g_object_ref (child);
11746 clutter_actor_remove_child_internal (self, child, 0);
11747 clutter_actor_add_child_internal (self, child,
11748 ADD_CHILD_NOTIFY_FIRST_LAST,
11749 insert_child_at_index,
11750 GINT_TO_POINTER (index_));
11752 clutter_actor_queue_relayout (self);
11756 * clutter_actor_raise:
11757 * @self: A #ClutterActor
11758 * @below: (allow-none): A #ClutterActor to raise above.
11760 * Puts @self above @below.
11762 * Both actors must have the same parent, and the parent must implement
11763 * the #ClutterContainer interface
11765 * This function calls clutter_container_raise_child() internally.
11767 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11770 clutter_actor_raise (ClutterActor *self,
11771 ClutterActor *below)
11773 ClutterActor *parent;
11775 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11777 parent = clutter_actor_get_parent (self);
11778 if (parent == NULL)
11780 g_warning ("%s: Actor '%s' is not inside a container",
11782 _clutter_actor_get_debug_name (self));
11788 if (parent != clutter_actor_get_parent (below))
11790 g_warning ("%s Actor '%s' is not in the same container as "
11793 _clutter_actor_get_debug_name (self),
11794 _clutter_actor_get_debug_name (below));
11799 clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11803 * clutter_actor_lower:
11804 * @self: A #ClutterActor
11805 * @above: (allow-none): A #ClutterActor to lower below
11807 * Puts @self below @above.
11809 * Both actors must have the same parent, and the parent must implement
11810 * the #ClutterContainer interface.
11812 * This function calls clutter_container_lower_child() internally.
11814 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11817 clutter_actor_lower (ClutterActor *self,
11818 ClutterActor *above)
11820 ClutterActor *parent;
11822 g_return_if_fail (CLUTTER_IS_ACTOR (self));
11824 parent = clutter_actor_get_parent (self);
11825 if (parent == NULL)
11827 g_warning ("%s: Actor of type %s is not inside a container",
11829 _clutter_actor_get_debug_name (self));
11835 if (parent != clutter_actor_get_parent (above))
11837 g_warning ("%s: Actor '%s' is not in the same container as "
11840 _clutter_actor_get_debug_name (self),
11841 _clutter_actor_get_debug_name (above));
11846 clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11850 * clutter_actor_raise_top:
11851 * @self: A #ClutterActor
11853 * Raises @self to the top.
11855 * This function calls clutter_actor_raise() internally.
11857 * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11858 * a %NULL sibling, instead.
11861 clutter_actor_raise_top (ClutterActor *self)
11863 clutter_actor_raise (self, NULL);
11867 * clutter_actor_lower_bottom:
11868 * @self: A #ClutterActor
11870 * Lowers @self to the bottom.
11872 * This function calls clutter_actor_lower() internally.
11874 * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11875 * a %NULL sibling, instead.
11878 clutter_actor_lower_bottom (ClutterActor *self)
11880 clutter_actor_lower (self, NULL);
11888 * clutter_actor_event:
11889 * @actor: a #ClutterActor
11890 * @event: a #ClutterEvent
11891 * @capture: TRUE if event in in capture phase, FALSE otherwise.
11893 * This function is used to emit an event on the main stage.
11894 * You should rarely need to use this function, except for
11895 * synthetising events.
11897 * Return value: the return value from the signal emission: %TRUE
11898 * if the actor handled the event, or %FALSE if the event was
11904 clutter_actor_event (ClutterActor *actor,
11905 ClutterEvent *event,
11908 gboolean retval = FALSE;
11909 gint signal_num = -1;
11911 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11912 g_return_val_if_fail (event != NULL, FALSE);
11914 g_object_ref (actor);
11918 g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11924 g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11928 switch (event->type)
11930 case CLUTTER_NOTHING:
11932 case CLUTTER_BUTTON_PRESS:
11933 signal_num = BUTTON_PRESS_EVENT;
11935 case CLUTTER_BUTTON_RELEASE:
11936 signal_num = BUTTON_RELEASE_EVENT;
11938 case CLUTTER_SCROLL:
11939 signal_num = SCROLL_EVENT;
11941 case CLUTTER_KEY_PRESS:
11942 signal_num = KEY_PRESS_EVENT;
11944 case CLUTTER_KEY_RELEASE:
11945 signal_num = KEY_RELEASE_EVENT;
11947 case CLUTTER_MOTION:
11948 signal_num = MOTION_EVENT;
11950 case CLUTTER_ENTER:
11951 signal_num = ENTER_EVENT;
11953 case CLUTTER_LEAVE:
11954 signal_num = LEAVE_EVENT;
11956 case CLUTTER_DELETE:
11957 case CLUTTER_DESTROY_NOTIFY:
11958 case CLUTTER_CLIENT_MESSAGE:
11964 if (signal_num != -1)
11965 g_signal_emit (actor, actor_signals[signal_num], 0,
11970 g_object_unref (actor);
11976 * clutter_actor_set_reactive:
11977 * @actor: a #ClutterActor
11978 * @reactive: whether the actor should be reactive to events
11980 * Sets @actor as reactive. Reactive actors will receive events.
11985 clutter_actor_set_reactive (ClutterActor *actor,
11988 g_return_if_fail (CLUTTER_IS_ACTOR (actor));
11990 if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
11994 CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11996 CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
11998 g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12002 * clutter_actor_get_reactive:
12003 * @actor: a #ClutterActor
12005 * Checks whether @actor is marked as reactive.
12007 * Return value: %TRUE if the actor is reactive
12012 clutter_actor_get_reactive (ClutterActor *actor)
12014 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12016 return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12020 * clutter_actor_get_anchor_point:
12021 * @self: a #ClutterActor
12022 * @anchor_x: (out): return location for the X coordinate of the anchor point
12023 * @anchor_y: (out): return location for the Y coordinate of the anchor point
12025 * Gets the current anchor point of the @actor in pixels.
12030 clutter_actor_get_anchor_point (ClutterActor *self,
12034 const ClutterTransformInfo *info;
12036 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12038 info = _clutter_actor_get_transform_info_or_defaults (self);
12039 clutter_anchor_coord_get_units (self, &info->anchor,
12046 * clutter_actor_set_anchor_point:
12047 * @self: a #ClutterActor
12048 * @anchor_x: X coordinate of the anchor point
12049 * @anchor_y: Y coordinate of the anchor point
12051 * Sets an anchor point for @self. The anchor point is a point in the
12052 * coordinate space of an actor to which the actor position within its
12053 * parent is relative; the default is (0, 0), i.e. the top-left corner
12059 clutter_actor_set_anchor_point (ClutterActor *self,
12063 ClutterTransformInfo *info;
12064 ClutterActorPrivate *priv;
12065 gboolean changed = FALSE;
12066 gfloat old_anchor_x, old_anchor_y;
12069 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12071 obj = G_OBJECT (self);
12073 info = _clutter_actor_get_transform_info (self);
12075 g_object_freeze_notify (obj);
12077 clutter_anchor_coord_get_units (self, &info->anchor,
12082 if (info->anchor.is_fractional)
12083 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12085 if (old_anchor_x != anchor_x)
12087 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12091 if (old_anchor_y != anchor_y)
12093 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12097 clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12101 priv->transform_valid = FALSE;
12102 clutter_actor_queue_redraw (self);
12105 g_object_thaw_notify (obj);
12109 * clutter_actor_get_anchor_point_gravity:
12110 * @self: a #ClutterActor
12112 * Retrieves the anchor position expressed as a #ClutterGravity. If
12113 * the anchor point was specified using pixels or units this will
12114 * return %CLUTTER_GRAVITY_NONE.
12116 * Return value: the #ClutterGravity used by the anchor point
12121 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12123 const ClutterTransformInfo *info;
12125 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12127 info = _clutter_actor_get_transform_info_or_defaults (self);
12129 return clutter_anchor_coord_get_gravity (&info->anchor);
12133 * clutter_actor_move_anchor_point:
12134 * @self: a #ClutterActor
12135 * @anchor_x: X coordinate of the anchor point
12136 * @anchor_y: Y coordinate of the anchor point
12138 * Sets an anchor point for the actor, and adjusts the actor postion so that
12139 * the relative position of the actor toward its parent remains the same.
12144 clutter_actor_move_anchor_point (ClutterActor *self,
12148 gfloat old_anchor_x, old_anchor_y;
12149 const ClutterTransformInfo *info;
12151 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12153 info = _clutter_actor_get_transform_info (self);
12154 clutter_anchor_coord_get_units (self, &info->anchor,
12159 g_object_freeze_notify (G_OBJECT (self));
12161 clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12163 if (self->priv->position_set)
12164 clutter_actor_move_by (self,
12165 anchor_x - old_anchor_x,
12166 anchor_y - old_anchor_y);
12168 g_object_thaw_notify (G_OBJECT (self));
12172 * clutter_actor_move_anchor_point_from_gravity:
12173 * @self: a #ClutterActor
12174 * @gravity: #ClutterGravity.
12176 * Sets an anchor point on the actor based on the given gravity, adjusting the
12177 * actor postion so that its relative position within its parent remains
12180 * Since version 1.0 the anchor point will be stored as a gravity so
12181 * that if the actor changes size then the anchor point will move. For
12182 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12183 * and later double the size of the actor, the anchor point will move
12184 * to the bottom right.
12189 clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
12190 ClutterGravity gravity)
12192 gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12193 const ClutterTransformInfo *info;
12194 ClutterActorPrivate *priv;
12196 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12199 info = _clutter_actor_get_transform_info (self);
12201 g_object_freeze_notify (G_OBJECT (self));
12203 clutter_anchor_coord_get_units (self, &info->anchor,
12207 clutter_actor_set_anchor_point_from_gravity (self, gravity);
12208 clutter_anchor_coord_get_units (self, &info->anchor,
12213 if (priv->position_set)
12214 clutter_actor_move_by (self,
12215 new_anchor_x - old_anchor_x,
12216 new_anchor_y - old_anchor_y);
12218 g_object_thaw_notify (G_OBJECT (self));
12222 * clutter_actor_set_anchor_point_from_gravity:
12223 * @self: a #ClutterActor
12224 * @gravity: #ClutterGravity.
12226 * Sets an anchor point on the actor, based on the given gravity (this is a
12227 * convenience function wrapping clutter_actor_set_anchor_point()).
12229 * Since version 1.0 the anchor point will be stored as a gravity so
12230 * that if the actor changes size then the anchor point will move. For
12231 * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12232 * and later double the size of the actor, the anchor point will move
12233 * to the bottom right.
12238 clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
12239 ClutterGravity gravity)
12241 g_return_if_fail (CLUTTER_IS_ACTOR (self));
12243 if (gravity == CLUTTER_GRAVITY_NONE)
12244 clutter_actor_set_anchor_point (self, 0, 0);
12247 GObject *obj = G_OBJECT (self);
12248 ClutterTransformInfo *info;
12250 g_object_freeze_notify (obj);
12252 info = _clutter_actor_get_transform_info (self);
12253 clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12255 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12256 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12257 g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12259 self->priv->transform_valid = FALSE;
12261 clutter_actor_queue_redraw (self);
12263 g_object_thaw_notify (obj);
12268 clutter_container_iface_init (ClutterContainerIface *iface)
12270 /* we don't override anything, as ClutterContainer already has a default
12271 * implementation that we can use, and which calls into our own API.
12286 parse_units (ClutterActor *self,
12287 ParseDimension dimension,
12290 GValue value = { 0, };
12293 if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12296 json_node_get_value (node, &value);
12298 if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12300 retval = (gfloat) g_value_get_int64 (&value);
12302 else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12304 retval = g_value_get_double (&value);
12306 else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12308 ClutterUnits units;
12311 res = clutter_units_from_string (&units, g_value_get_string (&value));
12313 retval = clutter_units_to_pixels (&units);
12316 g_warning ("Invalid value '%s': integers, strings or floating point "
12317 "values can be used for the x, y, width and height "
12318 "properties. Valid modifiers for strings are 'px', 'mm', "
12320 g_value_get_string (&value));
12326 g_warning ("Invalid value of type '%s': integers, strings of floating "
12327 "point values can be used for the x, y, width, height "
12328 "anchor-x and anchor-y properties.",
12329 g_type_name (G_VALUE_TYPE (&value)));
12332 g_value_unset (&value);
12338 ClutterRotateAxis axis;
12347 static inline gboolean
12348 parse_rotation_array (ClutterActor *actor,
12350 RotationInfo *info)
12354 if (json_array_get_length (array) != 2)
12358 element = json_array_get_element (array, 0);
12359 if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12360 info->angle = json_node_get_double (element);
12365 element = json_array_get_element (array, 1);
12366 if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12368 JsonArray *center = json_node_get_array (element);
12370 if (json_array_get_length (center) != 2)
12373 switch (info->axis)
12375 case CLUTTER_X_AXIS:
12376 info->center_y = parse_units (actor, PARSE_Y,
12377 json_array_get_element (center, 0));
12378 info->center_z = parse_units (actor, PARSE_Y,
12379 json_array_get_element (center, 1));
12382 case CLUTTER_Y_AXIS:
12383 info->center_x = parse_units (actor, PARSE_X,
12384 json_array_get_element (center, 0));
12385 info->center_z = parse_units (actor, PARSE_X,
12386 json_array_get_element (center, 1));
12389 case CLUTTER_Z_AXIS:
12390 info->center_x = parse_units (actor, PARSE_X,
12391 json_array_get_element (center, 0));
12392 info->center_y = parse_units (actor, PARSE_Y,
12393 json_array_get_element (center, 1));
12402 parse_rotation (ClutterActor *actor,
12404 RotationInfo *info)
12408 gboolean retval = FALSE;
12410 if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12412 g_warning ("Invalid node of type '%s' found, expecting an array",
12413 json_node_type_name (node));
12417 array = json_node_get_array (node);
12418 len = json_array_get_length (array);
12420 for (i = 0; i < len; i++)
12422 JsonNode *element = json_array_get_element (array, i);
12423 JsonObject *object;
12426 if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12428 g_warning ("Invalid node of type '%s' found, expecting an object",
12429 json_node_type_name (element));
12433 object = json_node_get_object (element);
12435 if (json_object_has_member (object, "x-axis"))
12437 member = json_object_get_member (object, "x-axis");
12439 info->axis = CLUTTER_X_AXIS;
12441 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12443 info->angle = json_node_get_double (member);
12446 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12447 retval = parse_rotation_array (actor,
12448 json_node_get_array (member),
12453 else if (json_object_has_member (object, "y-axis"))
12455 member = json_object_get_member (object, "y-axis");
12457 info->axis = CLUTTER_Y_AXIS;
12459 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12461 info->angle = json_node_get_double (member);
12464 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12465 retval = parse_rotation_array (actor,
12466 json_node_get_array (member),
12471 else if (json_object_has_member (object, "z-axis"))
12473 member = json_object_get_member (object, "z-axis");
12475 info->axis = CLUTTER_Z_AXIS;
12477 if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12479 info->angle = json_node_get_double (member);
12482 else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12483 retval = parse_rotation_array (actor,
12484 json_node_get_array (member),
12495 parse_actor_metas (ClutterScript *script,
12496 ClutterActor *actor,
12499 GList *elements, *l;
12500 GSList *retval = NULL;
12502 if (!JSON_NODE_HOLDS_ARRAY (node))
12505 elements = json_array_get_elements (json_node_get_array (node));
12507 for (l = elements; l != NULL; l = l->next)
12509 JsonNode *element = l->data;
12510 const gchar *id_ = _clutter_script_get_id_from_node (element);
12513 if (id_ == NULL || *id_ == '\0')
12516 meta = clutter_script_get_object (script, id_);
12520 retval = g_slist_prepend (retval, meta);
12523 g_list_free (elements);
12525 return g_slist_reverse (retval);
12529 parse_behaviours (ClutterScript *script,
12530 ClutterActor *actor,
12533 GList *elements, *l;
12534 GSList *retval = NULL;
12536 if (!JSON_NODE_HOLDS_ARRAY (node))
12539 elements = json_array_get_elements (json_node_get_array (node));
12541 for (l = elements; l != NULL; l = l->next)
12543 JsonNode *element = l->data;
12544 const gchar *id_ = _clutter_script_get_id_from_node (element);
12545 GObject *behaviour;
12547 if (id_ == NULL || *id_ == '\0')
12550 behaviour = clutter_script_get_object (script, id_);
12551 if (behaviour == NULL)
12554 retval = g_slist_prepend (retval, behaviour);
12557 g_list_free (elements);
12559 return g_slist_reverse (retval);
12563 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12564 ClutterScript *script,
12569 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12570 gboolean retval = FALSE;
12572 if ((name[0] == 'x' && name[1] == '\0') ||
12573 (name[0] == 'y' && name[1] == '\0') ||
12574 (strcmp (name, "width") == 0) ||
12575 (strcmp (name, "height") == 0) ||
12576 (strcmp (name, "anchor_x") == 0) ||
12577 (strcmp (name, "anchor_y") == 0))
12579 ParseDimension dimension;
12582 if (name[0] == 'x')
12583 dimension = PARSE_X;
12584 else if (name[0] == 'y')
12585 dimension = PARSE_Y;
12586 else if (name[0] == 'w')
12587 dimension = PARSE_WIDTH;
12588 else if (name[0] == 'h')
12589 dimension = PARSE_HEIGHT;
12590 else if (name[0] == 'a' && name[7] == 'x')
12591 dimension = PARSE_ANCHOR_X;
12592 else if (name[0] == 'a' && name[7] == 'y')
12593 dimension = PARSE_ANCHOR_Y;
12597 units = parse_units (actor, dimension, node);
12599 /* convert back to pixels: all properties are pixel-based */
12600 g_value_init (value, G_TYPE_FLOAT);
12601 g_value_set_float (value, units);
12605 else if (strcmp (name, "rotation") == 0)
12607 RotationInfo *info;
12609 info = g_slice_new0 (RotationInfo);
12610 retval = parse_rotation (actor, node, info);
12614 g_value_init (value, G_TYPE_POINTER);
12615 g_value_set_pointer (value, info);
12618 g_slice_free (RotationInfo, info);
12620 else if (strcmp (name, "behaviours") == 0)
12624 #ifdef CLUTTER_ENABLE_DEBUG
12625 if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12626 _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12627 "and it should not be used in newly "
12628 "written ClutterScript definitions.");
12631 l = parse_behaviours (script, actor, node);
12633 g_value_init (value, G_TYPE_POINTER);
12634 g_value_set_pointer (value, l);
12638 else if (strcmp (name, "actions") == 0 ||
12639 strcmp (name, "constraints") == 0 ||
12640 strcmp (name, "effects") == 0)
12644 l = parse_actor_metas (script, actor, node);
12646 g_value_init (value, G_TYPE_POINTER);
12647 g_value_set_pointer (value, l);
12656 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12657 ClutterScript *script,
12659 const GValue *value)
12661 ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12663 #ifdef CLUTTER_ENABLE_DEBUG
12664 if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12666 gchar *tmp = g_strdup_value_contents (value);
12668 CLUTTER_NOTE (SCRIPT,
12669 "in ClutterActor::set_custom_property('%s') = %s",
12675 #endif /* CLUTTER_ENABLE_DEBUG */
12677 if (strcmp (name, "rotation") == 0)
12679 RotationInfo *info;
12681 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12684 info = g_value_get_pointer (value);
12686 clutter_actor_set_rotation (actor,
12687 info->axis, info->angle,
12692 g_slice_free (RotationInfo, info);
12697 if (strcmp (name, "behaviours") == 0)
12699 GSList *behaviours, *l;
12701 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12704 behaviours = g_value_get_pointer (value);
12705 for (l = behaviours; l != NULL; l = l->next)
12707 ClutterBehaviour *behaviour = l->data;
12709 clutter_behaviour_apply (behaviour, actor);
12712 g_slist_free (behaviours);
12717 if (strcmp (name, "actions") == 0 ||
12718 strcmp (name, "constraints") == 0 ||
12719 strcmp (name, "effects") == 0)
12723 if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12726 metas = g_value_get_pointer (value);
12727 for (l = metas; l != NULL; l = l->next)
12729 if (name[0] == 'a')
12730 clutter_actor_add_action (actor, l->data);
12732 if (name[0] == 'c')
12733 clutter_actor_add_constraint (actor, l->data);
12735 if (name[0] == 'e')
12736 clutter_actor_add_effect (actor, l->data);
12739 g_slist_free (metas);
12744 g_object_set_property (G_OBJECT (scriptable), name, value);
12748 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12750 iface->parse_custom_node = clutter_actor_parse_custom_node;
12751 iface->set_custom_property = clutter_actor_set_custom_property;
12754 static ClutterActorMeta *
12755 get_meta_from_animation_property (ClutterActor *actor,
12759 ClutterActorPrivate *priv = actor->priv;
12760 ClutterActorMeta *meta = NULL;
12763 /* if this is not a special property, fall through */
12764 if (name[0] != '@')
12767 /* detect the properties named using the following spec:
12769 * @<section>.<meta-name>.<property-name>
12771 * where <section> can be one of the following:
12777 * and <meta-name> is the name set on a specific ActorMeta
12780 tokens = g_strsplit (name + 1, ".", -1);
12781 if (tokens == NULL || g_strv_length (tokens) != 3)
12783 CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12785 g_strfreev (tokens);
12789 if (strcmp (tokens[0], "actions") == 0)
12790 meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12792 if (strcmp (tokens[0], "constraints") == 0)
12793 meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12795 if (strcmp (tokens[0], "effects") == 0)
12796 meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12798 if (name_p != NULL)
12799 *name_p = g_strdup (tokens[2]);
12801 CLUTTER_NOTE (ANIMATION,
12802 "Looking for property '%s' of object '%s' in section '%s'",
12807 g_strfreev (tokens);
12812 static GParamSpec *
12813 clutter_actor_find_property (ClutterAnimatable *animatable,
12814 const gchar *property_name)
12816 ClutterActorMeta *meta = NULL;
12817 GObjectClass *klass = NULL;
12818 GParamSpec *pspec = NULL;
12819 gchar *p_name = NULL;
12821 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12827 klass = G_OBJECT_GET_CLASS (meta);
12829 pspec = g_object_class_find_property (klass, p_name);
12833 klass = G_OBJECT_GET_CLASS (animatable);
12835 pspec = g_object_class_find_property (klass, property_name);
12844 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12845 const gchar *property_name,
12848 ClutterActorMeta *meta = NULL;
12849 gchar *p_name = NULL;
12851 meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12856 g_object_get_property (G_OBJECT (meta), p_name, initial);
12858 g_object_get_property (G_OBJECT (animatable), property_name, initial);
12864 * clutter_actor_set_animatable_property:
12865 * @actor: a #ClutterActor
12866 * @prop_id: the paramspec id
12867 * @value: the value to set
12868 * @pspec: the paramspec
12870 * Sets values of animatable properties.
12872 * This is a variant of clutter_actor_set_property() that gets called
12873 * by the #ClutterAnimatable implementation of #ClutterActor for the
12874 * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12877 * Unlike the implementation of #GObjectClass.set_property(), this
12878 * function will not update the interval if a transition involving an
12879 * animatable property is in progress - this avoids cycles with the
12880 * transition API calling the public API.
12883 clutter_actor_set_animatable_property (ClutterActor *actor,
12885 const GValue *value,
12891 clutter_actor_set_x_internal (actor, g_value_get_float (value));
12895 clutter_actor_set_y_internal (actor, g_value_get_float (value));
12899 clutter_actor_set_width_internal (actor, g_value_get_float (value));
12903 clutter_actor_set_height_internal (actor, g_value_get_float (value));
12907 clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12911 clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12914 case PROP_BACKGROUND_COLOR:
12915 clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12919 clutter_actor_set_scale_factor_internal (actor,
12920 g_value_get_double (value),
12925 clutter_actor_set_scale_factor_internal (actor,
12926 g_value_get_double (value),
12930 case PROP_ROTATION_ANGLE_X:
12931 clutter_actor_set_rotation_angle_internal (actor,
12933 g_value_get_double (value));
12936 case PROP_ROTATION_ANGLE_Y:
12937 clutter_actor_set_rotation_angle_internal (actor,
12939 g_value_get_double (value));
12942 case PROP_ROTATION_ANGLE_Z:
12943 clutter_actor_set_rotation_angle_internal (actor,
12945 g_value_get_double (value));
12949 g_object_set_property (G_OBJECT (actor), pspec->name, value);
12955 clutter_actor_set_final_state (ClutterAnimatable *animatable,
12956 const gchar *property_name,
12957 const GValue *final)
12959 ClutterActor *actor = CLUTTER_ACTOR (animatable);
12960 ClutterActorMeta *meta = NULL;
12961 gchar *p_name = NULL;
12963 meta = get_meta_from_animation_property (actor,
12967 g_object_set_property (G_OBJECT (meta), p_name, final);
12970 GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
12973 pspec = g_object_class_find_property (obj_class, property_name);
12975 if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
12977 /* XXX - I'm going to the special hell for this */
12978 clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
12981 g_object_set_property (G_OBJECT (animatable), pspec->name, final);
12988 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
12990 iface->find_property = clutter_actor_find_property;
12991 iface->get_initial_state = clutter_actor_get_initial_state;
12992 iface->set_final_state = clutter_actor_set_final_state;
12996 * clutter_actor_transform_stage_point:
12997 * @self: A #ClutterActor
12998 * @x: (in): x screen coordinate of the point to unproject
12999 * @y: (in): y screen coordinate of the point to unproject
13000 * @x_out: (out): return location for the unprojected x coordinance
13001 * @y_out: (out): return location for the unprojected y coordinance
13003 * This function translates screen coordinates (@x, @y) to
13004 * coordinates relative to the actor. For example, it can be used to translate
13005 * screen events from global screen coordinates into actor-local coordinates.
13007 * The conversion can fail, notably if the transform stack results in the
13008 * actor being projected on the screen as a mere line.
13010 * The conversion should not be expected to be pixel-perfect due to the
13011 * nature of the operation. In general the error grows when the skewing
13012 * of the actor rectangle on screen increases.
13014 * <note><para>This function can be computationally intensive.</para></note>
13016 * <note><para>This function only works when the allocation is up-to-date,
13017 * i.e. inside of paint().</para></note>
13019 * Return value: %TRUE if conversion was successful.
13024 clutter_actor_transform_stage_point (ClutterActor *self,
13030 ClutterVertex v[4];
13033 int du, dv, xi, yi;
13035 float xf, yf, wf, det;
13036 ClutterActorPrivate *priv;
13038 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13042 /* This implementation is based on the quad -> quad projection algorithm
13043 * described by Paul Heckbert in:
13045 * http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13047 * and the sample implementation at:
13049 * http://www.cs.cmu.edu/~ph/src/texfund/
13051 * Our texture is a rectangle with origin [0, 0], so we are mapping from
13052 * quad to rectangle only, which significantly simplifies things; the
13053 * function calls have been unrolled, and most of the math is done in fixed
13057 clutter_actor_get_abs_allocation_vertices (self, v);
13059 /* Keeping these as ints simplifies the multiplication (no significant
13060 * loss of precision here).
13062 du = (int) (priv->allocation.x2 - priv->allocation.x1);
13063 dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13068 #define UX2FP(x) (x)
13069 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13071 /* First, find mapping from unit uv square to xy quadrilateral; this
13072 * equivalent to the pmap_square_quad() functions in the sample
13073 * implementation, which we can simplify, since our target is always
13076 px = v[0].x - v[1].x + v[3].x - v[2].x;
13077 py = v[0].y - v[1].y + v[3].y - v[2].y;
13081 /* affine transform */
13082 RQ[0][0] = UX2FP (v[1].x - v[0].x);
13083 RQ[1][0] = UX2FP (v[3].x - v[1].x);
13084 RQ[2][0] = UX2FP (v[0].x);
13085 RQ[0][1] = UX2FP (v[1].y - v[0].y);
13086 RQ[1][1] = UX2FP (v[3].y - v[1].y);
13087 RQ[2][1] = UX2FP (v[0].y);
13094 /* projective transform */
13095 double dx1, dx2, dy1, dy2, del;
13097 dx1 = UX2FP (v[1].x - v[3].x);
13098 dx2 = UX2FP (v[2].x - v[3].x);
13099 dy1 = UX2FP (v[1].y - v[3].y);
13100 dy2 = UX2FP (v[2].y - v[3].y);
13102 del = DET2FP (dx1, dx2, dy1, dy2);
13107 * The division here needs to be done in floating point for
13108 * precisions reasons.
13110 RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13111 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13112 RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13114 RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13115 RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13116 RQ[2][0] = UX2FP (v[0].x);
13117 RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13118 RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13119 RQ[2][1] = UX2FP (v[0].y);
13123 * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13124 * square. Since our rectangle is based at 0,0 we only need to scale.
13134 * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13137 ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13138 ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13139 ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13140 ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13141 ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13142 ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13143 ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13144 ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13145 ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13148 * Check the resulting matrix is OK.
13150 det = (RQ[0][0] * ST[0][0])
13151 + (RQ[0][1] * ST[0][1])
13152 + (RQ[0][2] * ST[0][2]);
13157 * Now transform our point with the ST matrix; the notional w
13158 * coordinate is 1, hence the last part is simply added.
13163 xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13164 yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13165 wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13183 static ClutterGeometry*
13184 clutter_geometry_copy (const ClutterGeometry *geometry)
13186 return g_slice_dup (ClutterGeometry, geometry);
13190 clutter_geometry_free (ClutterGeometry *geometry)
13192 if (G_LIKELY (geometry != NULL))
13193 g_slice_free (ClutterGeometry, geometry);
13197 * clutter_geometry_union:
13198 * @geometry_a: a #ClutterGeometry
13199 * @geometry_b: another #ClutterGeometry
13200 * @result: (out): location to store the result
13202 * Find the union of two rectangles represented as #ClutterGeometry.
13207 clutter_geometry_union (const ClutterGeometry *geometry_a,
13208 const ClutterGeometry *geometry_b,
13209 ClutterGeometry *result)
13211 /* We don't try to handle rectangles that can't be represented
13212 * as a signed integer box */
13213 gint x_1 = MIN (geometry_a->x, geometry_b->x);
13214 gint y_1 = MIN (geometry_a->y, geometry_b->y);
13215 gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13216 geometry_b->x + (gint)geometry_b->width);
13217 gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13218 geometry_b->y + (gint)geometry_b->height);
13221 result->width = x_2 - x_1;
13222 result->height = y_2 - y_1;
13226 * clutter_geometry_intersects:
13227 * @geometry0: The first geometry to test
13228 * @geometry1: The second geometry to test
13230 * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13231 * they do else %FALSE.
13233 * Return value: %TRUE of @geometry0 and geometry1 intersect else
13239 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13240 const ClutterGeometry *geometry1)
13242 if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13243 geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13244 (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13245 (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13252 clutter_geometry_progress (const GValue *a,
13257 const ClutterGeometry *a_geom = g_value_get_boxed (a);
13258 const ClutterGeometry *b_geom = g_value_get_boxed (b);
13259 ClutterGeometry res = { 0, };
13260 gint a_width = a_geom->width;
13261 gint b_width = b_geom->width;
13262 gint a_height = a_geom->height;
13263 gint b_height = b_geom->height;
13265 res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13266 res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13268 res.width = a_width + (b_width - a_width) * progress;
13269 res.height = a_height + (b_height - a_height) * progress;
13271 g_value_set_boxed (retval, &res);
13276 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13277 clutter_geometry_copy,
13278 clutter_geometry_free,
13279 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13286 * clutter_vertex_new:
13291 * Creates a new #ClutterVertex for the point in 3D space
13292 * identified by the 3 coordinates @x, @y, @z
13294 * Return value: the newly allocate #ClutterVertex. Use
13295 * clutter_vertex_free() to free the resources
13300 clutter_vertex_new (gfloat x,
13304 ClutterVertex *vertex;
13306 vertex = g_slice_new (ClutterVertex);
13315 * clutter_vertex_copy:
13316 * @vertex: a #ClutterVertex
13320 * Return value: a newly allocated copy of #ClutterVertex. Use
13321 * clutter_vertex_free() to free the allocated resources
13326 clutter_vertex_copy (const ClutterVertex *vertex)
13328 if (G_LIKELY (vertex != NULL))
13329 return g_slice_dup (ClutterVertex, vertex);
13335 * clutter_vertex_free:
13336 * @vertex: a #ClutterVertex
13338 * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13343 clutter_vertex_free (ClutterVertex *vertex)
13345 if (G_UNLIKELY (vertex != NULL))
13346 g_slice_free (ClutterVertex, vertex);
13350 * clutter_vertex_equal:
13351 * @vertex_a: a #ClutterVertex
13352 * @vertex_b: a #ClutterVertex
13354 * Compares @vertex_a and @vertex_b for equality
13356 * Return value: %TRUE if the passed #ClutterVertex are equal
13361 clutter_vertex_equal (const ClutterVertex *vertex_a,
13362 const ClutterVertex *vertex_b)
13364 g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13366 if (vertex_a == vertex_b)
13369 return vertex_a->x == vertex_b->x &&
13370 vertex_a->y == vertex_b->y &&
13371 vertex_a->z == vertex_b->z;
13375 clutter_vertex_progress (const GValue *a,
13380 const ClutterVertex *av = g_value_get_boxed (a);
13381 const ClutterVertex *bv = g_value_get_boxed (b);
13382 ClutterVertex res = { 0, };
13384 res.x = av->x + (bv->x - av->x) * progress;
13385 res.y = av->y + (bv->y - av->y) * progress;
13386 res.z = av->z + (bv->z - av->z) * progress;
13388 g_value_set_boxed (retval, &res);
13393 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13394 clutter_vertex_copy,
13395 clutter_vertex_free,
13396 CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13399 * clutter_actor_is_rotated:
13400 * @self: a #ClutterActor
13402 * Checks whether any rotation is applied to the actor.
13404 * Return value: %TRUE if the actor is rotated.
13409 clutter_actor_is_rotated (ClutterActor *self)
13411 const ClutterTransformInfo *info;
13413 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13415 info = _clutter_actor_get_transform_info_or_defaults (self);
13417 if (info->rx_angle || info->ry_angle || info->rz_angle)
13424 * clutter_actor_is_scaled:
13425 * @self: a #ClutterActor
13427 * Checks whether the actor is scaled in either dimension.
13429 * Return value: %TRUE if the actor is scaled.
13434 clutter_actor_is_scaled (ClutterActor *self)
13436 const ClutterTransformInfo *info;
13438 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13440 info = _clutter_actor_get_transform_info_or_defaults (self);
13442 if (info->scale_x != 1.0 || info->scale_y != 1.0)
13449 _clutter_actor_get_stage_internal (ClutterActor *actor)
13451 while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13452 actor = actor->priv->parent;
13458 * clutter_actor_get_stage:
13459 * @actor: a #ClutterActor
13461 * Retrieves the #ClutterStage where @actor is contained.
13463 * Return value: (transfer none) (type Clutter.Stage): the stage
13464 * containing the actor, or %NULL
13469 clutter_actor_get_stage (ClutterActor *actor)
13471 g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13473 return _clutter_actor_get_stage_internal (actor);
13477 * clutter_actor_allocate_available_size:
13478 * @self: a #ClutterActor
13479 * @x: the actor's X coordinate
13480 * @y: the actor's Y coordinate
13481 * @available_width: the maximum available width, or -1 to use the
13482 * actor's natural width
13483 * @available_height: the maximum available height, or -1 to use the
13484 * actor's natural height
13485 * @flags: flags controlling the allocation
13487 * Allocates @self taking into account the #ClutterActor<!-- -->'s
13488 * preferred size, but limiting it to the maximum available width
13489 * and height provided.
13491 * This function will do the right thing when dealing with the
13492 * actor's request mode.
13494 * The implementation of this function is equivalent to:
13497 * if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13499 * clutter_actor_get_preferred_width (self, available_height,
13501 * &natural_width);
13502 * width = CLAMP (natural_width, min_width, available_width);
13504 * clutter_actor_get_preferred_height (self, width,
13506 * &natural_height);
13507 * height = CLAMP (natural_height, min_height, available_height);
13511 * clutter_actor_get_preferred_height (self, available_width,
13513 * &natural_height);
13514 * height = CLAMP (natural_height, min_height, available_height);
13516 * clutter_actor_get_preferred_width (self, height,
13518 * &natural_width);
13519 * width = CLAMP (natural_width, min_width, available_width);
13522 * box.x1 = x; box.y1 = y;
13523 * box.x2 = box.x1 + available_width;
13524 * box.y2 = box.y1 + available_height;
13525 * clutter_actor_allocate (self, &box, flags);
13528 * This function can be used by fluid layout managers to allocate
13529 * an actor's preferred size without making it bigger than the area
13530 * available for the container.
13535 clutter_actor_allocate_available_size (ClutterActor *self,
13538 gfloat available_width,
13539 gfloat available_height,
13540 ClutterAllocationFlags flags)
13542 ClutterActorPrivate *priv;
13543 gfloat width, height;
13544 gfloat min_width, min_height;
13545 gfloat natural_width, natural_height;
13546 ClutterActorBox box;
13548 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13552 width = height = 0.0;
13554 switch (priv->request_mode)
13556 case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13557 clutter_actor_get_preferred_width (self, available_height,
13560 width = CLAMP (natural_width, min_width, available_width);
13562 clutter_actor_get_preferred_height (self, width,
13565 height = CLAMP (natural_height, min_height, available_height);
13568 case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13569 clutter_actor_get_preferred_height (self, available_width,
13572 height = CLAMP (natural_height, min_height, available_height);
13574 clutter_actor_get_preferred_width (self, height,
13577 width = CLAMP (natural_width, min_width, available_width);
13584 box.x2 = box.x1 + width;
13585 box.y2 = box.y1 + height;
13586 clutter_actor_allocate (self, &box, flags);
13590 * clutter_actor_allocate_preferred_size:
13591 * @self: a #ClutterActor
13592 * @flags: flags controlling the allocation
13594 * Allocates the natural size of @self.
13596 * This function is a utility call for #ClutterActor implementations
13597 * that allocates the actor's preferred natural size. It can be used
13598 * by fixed layout managers (like #ClutterGroup or so called
13599 * 'composite actors') inside the ClutterActor::allocate
13600 * implementation to give each child exactly how much space it
13603 * This function is not meant to be used by applications. It is also
13604 * not meant to be used outside the implementation of the
13605 * ClutterActor::allocate virtual function.
13610 clutter_actor_allocate_preferred_size (ClutterActor *self,
13611 ClutterAllocationFlags flags)
13613 gfloat actor_x, actor_y;
13614 gfloat natural_width, natural_height;
13615 ClutterActorBox actor_box;
13617 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13619 actor_x = clutter_actor_get_x (self);
13620 actor_y = clutter_actor_get_y (self);
13622 clutter_actor_get_preferred_size (self,
13627 actor_box.x1 = actor_x;
13628 actor_box.y1 = actor_y;
13629 actor_box.x2 = actor_box.x1 + natural_width;
13630 actor_box.y2 = actor_box.y1 + natural_height;
13632 clutter_actor_allocate (self, &actor_box, flags);
13636 * clutter_actor_allocate_align_fill:
13637 * @self: a #ClutterActor
13638 * @box: a #ClutterActorBox, containing the available width and height
13639 * @x_align: the horizontal alignment, between 0 and 1
13640 * @y_align: the vertical alignment, between 0 and 1
13641 * @x_fill: whether the actor should fill horizontally
13642 * @y_fill: whether the actor should fill vertically
13643 * @flags: allocation flags to be passed to clutter_actor_allocate()
13645 * Allocates @self by taking into consideration the available allocation
13646 * area; an alignment factor on either axis; and whether the actor should
13647 * fill the allocation on either axis.
13649 * The @box should contain the available allocation width and height;
13650 * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13651 * allocation will be offset by their value.
13653 * This function takes into consideration the geometry request specified by
13654 * the #ClutterActor:request-mode property, and the text direction.
13656 * This function is useful for fluid layout managers, like #ClutterBinLayout
13657 * or #ClutterTableLayout
13662 clutter_actor_allocate_align_fill (ClutterActor *self,
13663 const ClutterActorBox *box,
13668 ClutterAllocationFlags flags)
13670 ClutterActorPrivate *priv;
13671 ClutterActorBox allocation = { 0, };
13672 gfloat x_offset, y_offset;
13673 gfloat available_width, available_height;
13674 gfloat child_width, child_height;
13676 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13677 g_return_if_fail (box != NULL);
13678 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13679 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13683 clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13684 clutter_actor_box_get_size (box, &available_width, &available_height);
13686 if (available_width < 0)
13687 available_width = 0;
13689 if (available_height < 0)
13690 available_height = 0;
13694 allocation.x1 = x_offset;
13695 allocation.x2 = allocation.x1 + available_width;
13700 allocation.y1 = y_offset;
13701 allocation.y2 = allocation.y1 + available_height;
13704 /* if we are filling horizontally and vertically then we're done */
13705 if (x_fill && y_fill)
13708 child_width = child_height = 0.0f;
13710 if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13712 gfloat min_width, natural_width;
13713 gfloat min_height, natural_height;
13715 clutter_actor_get_preferred_width (self, available_height,
13719 child_width = CLAMP (natural_width, min_width, available_width);
13723 clutter_actor_get_preferred_height (self, child_width,
13727 child_height = CLAMP (natural_height, min_height, available_height);
13732 gfloat min_width, natural_width;
13733 gfloat min_height, natural_height;
13735 clutter_actor_get_preferred_height (self, available_width,
13739 child_height = CLAMP (natural_height, min_height, available_height);
13743 clutter_actor_get_preferred_width (self, child_height,
13747 child_width = CLAMP (natural_width, min_width, available_width);
13751 /* invert the horizontal alignment for RTL languages */
13752 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13753 x_align = 1.0 - x_align;
13757 allocation.x1 = x_offset
13758 + ((available_width - child_width) * x_align);
13759 allocation.x2 = allocation.x1 + child_width;
13764 allocation.y1 = y_offset
13765 + ((available_height - child_height) * y_align);
13766 allocation.y2 = allocation.y1 + child_height;
13770 clutter_actor_box_clamp_to_pixel (&allocation);
13771 clutter_actor_allocate (self, &allocation, flags);
13775 * clutter_actor_grab_key_focus:
13776 * @self: a #ClutterActor
13778 * Sets the key focus of the #ClutterStage including @self
13779 * to this #ClutterActor.
13784 clutter_actor_grab_key_focus (ClutterActor *self)
13786 ClutterActor *stage;
13788 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13790 stage = _clutter_actor_get_stage_internal (self);
13792 clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13796 * clutter_actor_get_pango_context:
13797 * @self: a #ClutterActor
13799 * Retrieves the #PangoContext for @self. The actor's #PangoContext
13800 * is already configured using the appropriate font map, resolution
13801 * and font options.
13803 * Unlike clutter_actor_create_pango_context(), this context is owend
13804 * by the #ClutterActor and it will be updated each time the options
13805 * stored by the #ClutterBackend change.
13807 * You can use the returned #PangoContext to create a #PangoLayout
13808 * and render text using cogl_pango_render_layout() to reuse the
13809 * glyphs cache also used by Clutter.
13811 * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13812 * The returned #PangoContext is owned by the actor and should not be
13813 * unreferenced by the application code
13818 clutter_actor_get_pango_context (ClutterActor *self)
13820 ClutterActorPrivate *priv;
13822 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13826 if (priv->pango_context != NULL)
13827 return priv->pango_context;
13829 priv->pango_context = _clutter_context_get_pango_context ();
13830 g_object_ref (priv->pango_context);
13832 return priv->pango_context;
13836 * clutter_actor_create_pango_context:
13837 * @self: a #ClutterActor
13839 * Creates a #PangoContext for the given actor. The #PangoContext
13840 * is already configured using the appropriate font map, resolution
13841 * and font options.
13843 * See also clutter_actor_get_pango_context().
13845 * Return value: (transfer full): the newly created #PangoContext.
13846 * Use g_object_unref() on the returned value to deallocate its
13852 clutter_actor_create_pango_context (ClutterActor *self)
13854 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13856 return _clutter_context_create_pango_context ();
13860 * clutter_actor_create_pango_layout:
13861 * @self: a #ClutterActor
13862 * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13864 * Creates a new #PangoLayout from the same #PangoContext used
13865 * by the #ClutterActor. The #PangoLayout is already configured
13866 * with the font map, resolution and font options, and the
13869 * If you want to keep around a #PangoLayout created by this
13870 * function you will have to connect to the #ClutterBackend::font-changed
13871 * and #ClutterBackend::resolution-changed signals, and call
13872 * pango_layout_context_changed() in response to them.
13874 * Return value: (transfer full): the newly created #PangoLayout.
13875 * Use g_object_unref() when done
13880 clutter_actor_create_pango_layout (ClutterActor *self,
13883 PangoContext *context;
13884 PangoLayout *layout;
13886 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13888 context = clutter_actor_get_pango_context (self);
13889 layout = pango_layout_new (context);
13892 pango_layout_set_text (layout, text, -1);
13897 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13898 * ClutterOffscreenEffect.
13901 _clutter_actor_set_opacity_override (ClutterActor *self,
13904 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13906 self->priv->opacity_override = opacity;
13910 _clutter_actor_get_opacity_override (ClutterActor *self)
13912 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13914 return self->priv->opacity_override;
13917 /* Allows you to disable applying the actors model view transform during
13918 * a paint. Used by ClutterClone. */
13920 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
13923 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13925 self->priv->enable_model_view_transform = enable;
13929 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
13932 ClutterActorPrivate *priv;
13934 g_return_if_fail (CLUTTER_IS_ACTOR (self));
13938 priv->enable_paint_unmapped = enable;
13940 if (priv->enable_paint_unmapped)
13942 /* Make sure that the parents of the widget are realized first;
13943 * otherwise checks in clutter_actor_update_map_state() will
13946 clutter_actor_realize (self);
13948 clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
13952 clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
13957 clutter_anchor_coord_get_units (ClutterActor *self,
13958 const AnchorCoord *coord,
13963 if (coord->is_fractional)
13965 gfloat actor_width, actor_height;
13967 clutter_actor_get_size (self, &actor_width, &actor_height);
13970 *x = actor_width * coord->v.fraction.x;
13973 *y = actor_height * coord->v.fraction.y;
13981 *x = coord->v.units.x;
13984 *y = coord->v.units.y;
13987 *z = coord->v.units.z;
13992 clutter_anchor_coord_set_units (AnchorCoord *coord,
13997 coord->is_fractional = FALSE;
13998 coord->v.units.x = x;
13999 coord->v.units.y = y;
14000 coord->v.units.z = z;
14003 static ClutterGravity
14004 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14006 if (coord->is_fractional)
14008 if (coord->v.fraction.x == 0.0)
14010 if (coord->v.fraction.y == 0.0)
14011 return CLUTTER_GRAVITY_NORTH_WEST;
14012 else if (coord->v.fraction.y == 0.5)
14013 return CLUTTER_GRAVITY_WEST;
14014 else if (coord->v.fraction.y == 1.0)
14015 return CLUTTER_GRAVITY_SOUTH_WEST;
14017 return CLUTTER_GRAVITY_NONE;
14019 else if (coord->v.fraction.x == 0.5)
14021 if (coord->v.fraction.y == 0.0)
14022 return CLUTTER_GRAVITY_NORTH;
14023 else if (coord->v.fraction.y == 0.5)
14024 return CLUTTER_GRAVITY_CENTER;
14025 else if (coord->v.fraction.y == 1.0)
14026 return CLUTTER_GRAVITY_SOUTH;
14028 return CLUTTER_GRAVITY_NONE;
14030 else if (coord->v.fraction.x == 1.0)
14032 if (coord->v.fraction.y == 0.0)
14033 return CLUTTER_GRAVITY_NORTH_EAST;
14034 else if (coord->v.fraction.y == 0.5)
14035 return CLUTTER_GRAVITY_EAST;
14036 else if (coord->v.fraction.y == 1.0)
14037 return CLUTTER_GRAVITY_SOUTH_EAST;
14039 return CLUTTER_GRAVITY_NONE;
14042 return CLUTTER_GRAVITY_NONE;
14045 return CLUTTER_GRAVITY_NONE;
14049 clutter_anchor_coord_set_gravity (AnchorCoord *coord,
14050 ClutterGravity gravity)
14054 case CLUTTER_GRAVITY_NORTH:
14055 coord->v.fraction.x = 0.5;
14056 coord->v.fraction.y = 0.0;
14059 case CLUTTER_GRAVITY_NORTH_EAST:
14060 coord->v.fraction.x = 1.0;
14061 coord->v.fraction.y = 0.0;
14064 case CLUTTER_GRAVITY_EAST:
14065 coord->v.fraction.x = 1.0;
14066 coord->v.fraction.y = 0.5;
14069 case CLUTTER_GRAVITY_SOUTH_EAST:
14070 coord->v.fraction.x = 1.0;
14071 coord->v.fraction.y = 1.0;
14074 case CLUTTER_GRAVITY_SOUTH:
14075 coord->v.fraction.x = 0.5;
14076 coord->v.fraction.y = 1.0;
14079 case CLUTTER_GRAVITY_SOUTH_WEST:
14080 coord->v.fraction.x = 0.0;
14081 coord->v.fraction.y = 1.0;
14084 case CLUTTER_GRAVITY_WEST:
14085 coord->v.fraction.x = 0.0;
14086 coord->v.fraction.y = 0.5;
14089 case CLUTTER_GRAVITY_NORTH_WEST:
14090 coord->v.fraction.x = 0.0;
14091 coord->v.fraction.y = 0.0;
14094 case CLUTTER_GRAVITY_CENTER:
14095 coord->v.fraction.x = 0.5;
14096 coord->v.fraction.y = 0.5;
14100 coord->v.fraction.x = 0.0;
14101 coord->v.fraction.y = 0.0;
14105 coord->is_fractional = TRUE;
14109 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14111 if (coord->is_fractional)
14112 return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14114 return (coord->v.units.x == 0.0
14115 && coord->v.units.y == 0.0
14116 && coord->v.units.z == 0.0);
14120 * clutter_actor_get_flags:
14121 * @self: a #ClutterActor
14123 * Retrieves the flags set on @self
14125 * Return value: a bitwise or of #ClutterActorFlags or 0
14130 clutter_actor_get_flags (ClutterActor *self)
14132 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14134 return self->flags;
14138 * clutter_actor_set_flags:
14139 * @self: a #ClutterActor
14140 * @flags: the flags to set
14142 * Sets @flags on @self
14144 * This function will emit notifications for the changed properties
14149 clutter_actor_set_flags (ClutterActor *self,
14150 ClutterActorFlags flags)
14152 ClutterActorFlags old_flags;
14154 gboolean was_reactive_set, reactive_set;
14155 gboolean was_realized_set, realized_set;
14156 gboolean was_mapped_set, mapped_set;
14157 gboolean was_visible_set, visible_set;
14159 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14161 if (self->flags == flags)
14164 obj = G_OBJECT (self);
14165 g_object_ref (obj);
14166 g_object_freeze_notify (obj);
14168 old_flags = self->flags;
14170 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14171 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14172 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14173 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14175 self->flags |= flags;
14177 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14178 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14179 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14180 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14182 if (reactive_set != was_reactive_set)
14183 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14185 if (realized_set != was_realized_set)
14186 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14188 if (mapped_set != was_mapped_set)
14189 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14191 if (visible_set != was_visible_set)
14192 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14194 g_object_thaw_notify (obj);
14195 g_object_unref (obj);
14199 * clutter_actor_unset_flags:
14200 * @self: a #ClutterActor
14201 * @flags: the flags to unset
14203 * Unsets @flags on @self
14205 * This function will emit notifications for the changed properties
14210 clutter_actor_unset_flags (ClutterActor *self,
14211 ClutterActorFlags flags)
14213 ClutterActorFlags old_flags;
14215 gboolean was_reactive_set, reactive_set;
14216 gboolean was_realized_set, realized_set;
14217 gboolean was_mapped_set, mapped_set;
14218 gboolean was_visible_set, visible_set;
14220 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14222 obj = G_OBJECT (self);
14223 g_object_freeze_notify (obj);
14225 old_flags = self->flags;
14227 was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14228 was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14229 was_mapped_set = ((old_flags & CLUTTER_ACTOR_MAPPED) != 0);
14230 was_visible_set = ((old_flags & CLUTTER_ACTOR_VISIBLE) != 0);
14232 self->flags &= ~flags;
14234 if (self->flags == old_flags)
14237 reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14238 realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14239 mapped_set = ((self->flags & CLUTTER_ACTOR_MAPPED) != 0);
14240 visible_set = ((self->flags & CLUTTER_ACTOR_VISIBLE) != 0);
14242 if (reactive_set != was_reactive_set)
14243 g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14245 if (realized_set != was_realized_set)
14246 g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14248 if (mapped_set != was_mapped_set)
14249 g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14251 if (visible_set != was_visible_set)
14252 g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14254 g_object_thaw_notify (obj);
14258 * clutter_actor_get_transformation_matrix:
14259 * @self: a #ClutterActor
14260 * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14262 * Retrieves the transformations applied to @self relative to its
14268 clutter_actor_get_transformation_matrix (ClutterActor *self,
14269 CoglMatrix *matrix)
14271 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14273 cogl_matrix_init_identity (matrix);
14275 _clutter_actor_apply_modelview_transform (self, matrix);
14279 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14280 gboolean is_in_clone_paint)
14282 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14283 self->priv->in_clone_paint = is_in_clone_paint;
14287 * clutter_actor_is_in_clone_paint:
14288 * @self: a #ClutterActor
14290 * Checks whether @self is being currently painted by a #ClutterClone
14292 * This function is useful only inside the ::paint virtual function
14293 * implementations or within handlers for the #ClutterActor::paint
14296 * This function should not be used by applications
14298 * Return value: %TRUE if the #ClutterActor is currently being painted
14299 * by a #ClutterClone, and %FALSE otherwise
14304 clutter_actor_is_in_clone_paint (ClutterActor *self)
14306 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14308 return self->priv->in_clone_paint;
14312 set_direction_recursive (ClutterActor *actor,
14313 gpointer user_data)
14315 ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14317 clutter_actor_set_text_direction (actor, text_dir);
14323 * clutter_actor_set_text_direction:
14324 * @self: a #ClutterActor
14325 * @text_dir: the text direction for @self
14327 * Sets the #ClutterTextDirection for an actor
14329 * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14331 * If @self implements #ClutterContainer then this function will recurse
14332 * inside all the children of @self (including the internal ones).
14334 * Composite actors not implementing #ClutterContainer, or actors requiring
14335 * special handling when the text direction changes, should connect to
14336 * the #GObject::notify signal for the #ClutterActor:text-direction property
14341 clutter_actor_set_text_direction (ClutterActor *self,
14342 ClutterTextDirection text_dir)
14344 ClutterActorPrivate *priv;
14346 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14347 g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14351 if (priv->text_direction != text_dir)
14353 priv->text_direction = text_dir;
14355 /* we need to emit the notify::text-direction first, so that
14356 * the sub-classes can catch that and do specific handling of
14357 * the text direction; see clutter_text_direction_changed_cb()
14358 * inside clutter-text.c
14360 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14362 _clutter_actor_foreach_child (self, set_direction_recursive,
14363 GINT_TO_POINTER (text_dir));
14365 clutter_actor_queue_relayout (self);
14370 _clutter_actor_set_has_pointer (ClutterActor *self,
14371 gboolean has_pointer)
14373 ClutterActorPrivate *priv = self->priv;
14375 if (priv->has_pointer != has_pointer)
14377 priv->has_pointer = has_pointer;
14379 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14384 * clutter_actor_get_text_direction:
14385 * @self: a #ClutterActor
14387 * Retrieves the value set using clutter_actor_set_text_direction()
14389 * If no text direction has been previously set, the default text
14390 * direction, as returned by clutter_get_default_text_direction(), will
14391 * be returned instead
14393 * Return value: the #ClutterTextDirection for the actor
14397 ClutterTextDirection
14398 clutter_actor_get_text_direction (ClutterActor *self)
14400 ClutterActorPrivate *priv;
14402 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14403 CLUTTER_TEXT_DIRECTION_LTR);
14407 /* if no direction has been set yet use the default */
14408 if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14409 priv->text_direction = clutter_get_default_text_direction ();
14411 return priv->text_direction;
14415 * clutter_actor_push_internal:
14416 * @self: a #ClutterActor
14418 * Should be used by actors implementing the #ClutterContainer and with
14419 * internal children added through clutter_actor_set_parent(), for instance:
14423 * my_actor_init (MyActor *self)
14425 * self->priv = SELF_ACTOR_GET_PRIVATE (self);
14427 * clutter_actor_push_internal (CLUTTER_ACTOR (self));
14429 * /* calling clutter_actor_set_parent() now will result in
14430 * * the internal flag being set on a child of MyActor
14433 * /* internal child - a background texture */
14434 * self->priv->background_tex = clutter_texture_new ();
14435 * clutter_actor_set_parent (self->priv->background_tex,
14436 * CLUTTER_ACTOR (self));
14438 * /* internal child - a label */
14439 * self->priv->label = clutter_text_new ();
14440 * clutter_actor_set_parent (self->priv->label,
14441 * CLUTTER_ACTOR (self));
14443 * clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14445 * /* calling clutter_actor_set_parent() now will not result in
14446 * * the internal flag being set on a child of MyActor
14451 * This function will be used by Clutter to toggle an "internal child"
14452 * flag whenever clutter_actor_set_parent() is called; internal children
14453 * are handled differently by Clutter, specifically when destroying their
14456 * Call clutter_actor_pop_internal() when you finished adding internal
14459 * Nested calls to clutter_actor_push_internal() are allowed, but each
14460 * one must by followed by a clutter_actor_pop_internal() call.
14464 * Deprecated: 1.10: All children of an actor are accessible through
14465 * the #ClutterActor API, and #ClutterActor implements the
14466 * #ClutterContainer interface, so this function is only useful
14467 * for legacy containers overriding the default implementation.
14470 clutter_actor_push_internal (ClutterActor *self)
14472 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14474 self->priv->internal_child += 1;
14478 * clutter_actor_pop_internal:
14479 * @self: a #ClutterActor
14481 * Disables the effects of clutter_actor_push_internal().
14485 * Deprecated: 1.10: All children of an actor are accessible through
14486 * the #ClutterActor API. This function is only useful for legacy
14487 * containers overriding the default implementation of the
14488 * #ClutterContainer interface.
14491 clutter_actor_pop_internal (ClutterActor *self)
14493 ClutterActorPrivate *priv;
14495 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14499 if (priv->internal_child == 0)
14501 g_warning ("Mismatched %s: you need to call "
14502 "clutter_actor_push_composite() at least once before "
14503 "calling this function", G_STRFUNC);
14507 priv->internal_child -= 1;
14511 * clutter_actor_has_pointer:
14512 * @self: a #ClutterActor
14514 * Checks whether an actor contains the pointer of a
14515 * #ClutterInputDevice
14517 * Return value: %TRUE if the actor contains the pointer, and
14523 clutter_actor_has_pointer (ClutterActor *self)
14525 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14527 return self->priv->has_pointer;
14530 /* XXX: This is a workaround for not being able to break the ABI of
14531 * the QUEUE_REDRAW signal. It is an out-of-band argument. See
14532 * clutter_actor_queue_clipped_redraw() for details.
14534 ClutterPaintVolume *
14535 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14537 return g_object_get_data (G_OBJECT (self),
14538 "-clutter-actor-queue-redraw-clip");
14542 _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
14543 ClutterPaintVolume *clip)
14545 g_object_set_data (G_OBJECT (self),
14546 "-clutter-actor-queue-redraw-clip",
14551 * clutter_actor_has_allocation:
14552 * @self: a #ClutterActor
14554 * Checks if the actor has an up-to-date allocation assigned to
14555 * it. This means that the actor should have an allocation: it's
14556 * visible and has a parent. It also means that there is no
14557 * outstanding relayout request in progress for the actor or its
14558 * children (There might be other outstanding layout requests in
14559 * progress that will cause the actor to get a new allocation
14560 * when the stage is laid out, however).
14562 * If this function returns %FALSE, then the actor will normally
14563 * be allocated before it is next drawn on the screen.
14565 * Return value: %TRUE if the actor has an up-to-date allocation
14570 clutter_actor_has_allocation (ClutterActor *self)
14572 ClutterActorPrivate *priv;
14574 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14578 return priv->parent != NULL &&
14579 CLUTTER_ACTOR_IS_VISIBLE (self) &&
14580 !priv->needs_allocation;
14584 * clutter_actor_add_action:
14585 * @self: a #ClutterActor
14586 * @action: a #ClutterAction
14588 * Adds @action to the list of actions applied to @self
14590 * A #ClutterAction can only belong to one actor at a time
14592 * The #ClutterActor will hold a reference on @action until either
14593 * clutter_actor_remove_action() or clutter_actor_clear_actions()
14599 clutter_actor_add_action (ClutterActor *self,
14600 ClutterAction *action)
14602 ClutterActorPrivate *priv;
14604 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14605 g_return_if_fail (CLUTTER_IS_ACTION (action));
14609 if (priv->actions == NULL)
14611 priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14612 priv->actions->actor = self;
14615 _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14617 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14621 * clutter_actor_add_action_with_name:
14622 * @self: a #ClutterActor
14623 * @name: the name to set on the action
14624 * @action: a #ClutterAction
14626 * A convenience function for setting the name of a #ClutterAction
14627 * while adding it to the list of actions applied to @self
14629 * This function is the logical equivalent of:
14632 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14633 * clutter_actor_add_action (self, action);
14639 clutter_actor_add_action_with_name (ClutterActor *self,
14641 ClutterAction *action)
14643 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14644 g_return_if_fail (name != NULL);
14645 g_return_if_fail (CLUTTER_IS_ACTION (action));
14647 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14648 clutter_actor_add_action (self, action);
14652 * clutter_actor_remove_action:
14653 * @self: a #ClutterActor
14654 * @action: a #ClutterAction
14656 * Removes @action from the list of actions applied to @self
14658 * The reference held by @self on the #ClutterAction will be released
14663 clutter_actor_remove_action (ClutterActor *self,
14664 ClutterAction *action)
14666 ClutterActorPrivate *priv;
14668 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14669 g_return_if_fail (CLUTTER_IS_ACTION (action));
14673 if (priv->actions == NULL)
14676 _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14678 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14682 * clutter_actor_remove_action_by_name:
14683 * @self: a #ClutterActor
14684 * @name: the name of the action to remove
14686 * Removes the #ClutterAction with the given name from the list
14687 * of actions applied to @self
14692 clutter_actor_remove_action_by_name (ClutterActor *self,
14695 ClutterActorPrivate *priv;
14696 ClutterActorMeta *meta;
14698 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14699 g_return_if_fail (name != NULL);
14703 if (priv->actions == NULL)
14706 meta = _clutter_meta_group_get_meta (priv->actions, name);
14710 _clutter_meta_group_remove_meta (priv->actions, meta);
14712 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14716 * clutter_actor_get_actions:
14717 * @self: a #ClutterActor
14719 * Retrieves the list of actions applied to @self
14721 * Return value: (transfer container) (element-type Clutter.Action): a copy
14722 * of the list of #ClutterAction<!-- -->s. The contents of the list are
14723 * owned by the #ClutterActor. Use g_list_free() to free the resources
14724 * allocated by the returned #GList
14729 clutter_actor_get_actions (ClutterActor *self)
14731 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14733 if (self->priv->actions == NULL)
14736 return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14740 * clutter_actor_get_action:
14741 * @self: a #ClutterActor
14742 * @name: the name of the action to retrieve
14744 * Retrieves the #ClutterAction with the given name in the list
14745 * of actions applied to @self
14747 * Return value: (transfer none): a #ClutterAction for the given
14748 * name, or %NULL. The returned #ClutterAction is owned by the
14749 * actor and it should not be unreferenced directly
14754 clutter_actor_get_action (ClutterActor *self,
14757 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14758 g_return_val_if_fail (name != NULL, NULL);
14760 if (self->priv->actions == NULL)
14763 return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14767 * clutter_actor_clear_actions:
14768 * @self: a #ClutterActor
14770 * Clears the list of actions applied to @self
14775 clutter_actor_clear_actions (ClutterActor *self)
14777 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14779 if (self->priv->actions == NULL)
14782 _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14786 * clutter_actor_add_constraint:
14787 * @self: a #ClutterActor
14788 * @constraint: a #ClutterConstraint
14790 * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14793 * The #ClutterActor will hold a reference on the @constraint until
14794 * either clutter_actor_remove_constraint() or
14795 * clutter_actor_clear_constraints() is called.
14800 clutter_actor_add_constraint (ClutterActor *self,
14801 ClutterConstraint *constraint)
14803 ClutterActorPrivate *priv;
14805 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14806 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14810 if (priv->constraints == NULL)
14812 priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14813 priv->constraints->actor = self;
14816 _clutter_meta_group_add_meta (priv->constraints,
14817 CLUTTER_ACTOR_META (constraint));
14818 clutter_actor_queue_relayout (self);
14820 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14824 * clutter_actor_add_constraint_with_name:
14825 * @self: a #ClutterActor
14826 * @name: the name to set on the constraint
14827 * @constraint: a #ClutterConstraint
14829 * A convenience function for setting the name of a #ClutterConstraint
14830 * while adding it to the list of constraints applied to @self
14832 * This function is the logical equivalent of:
14835 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14836 * clutter_actor_add_constraint (self, constraint);
14842 clutter_actor_add_constraint_with_name (ClutterActor *self,
14844 ClutterConstraint *constraint)
14846 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14847 g_return_if_fail (name != NULL);
14848 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14850 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14851 clutter_actor_add_constraint (self, constraint);
14855 * clutter_actor_remove_constraint:
14856 * @self: a #ClutterActor
14857 * @constraint: a #ClutterConstraint
14859 * Removes @constraint from the list of constraints applied to @self
14861 * The reference held by @self on the #ClutterConstraint will be released
14866 clutter_actor_remove_constraint (ClutterActor *self,
14867 ClutterConstraint *constraint)
14869 ClutterActorPrivate *priv;
14871 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14872 g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14876 if (priv->constraints == NULL)
14879 _clutter_meta_group_remove_meta (priv->constraints,
14880 CLUTTER_ACTOR_META (constraint));
14881 clutter_actor_queue_relayout (self);
14883 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14887 * clutter_actor_remove_constraint_by_name:
14888 * @self: a #ClutterActor
14889 * @name: the name of the constraint to remove
14891 * Removes the #ClutterConstraint with the given name from the list
14892 * of constraints applied to @self
14897 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14900 ClutterActorPrivate *priv;
14901 ClutterActorMeta *meta;
14903 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14904 g_return_if_fail (name != NULL);
14908 if (priv->constraints == NULL)
14911 meta = _clutter_meta_group_get_meta (priv->constraints, name);
14915 _clutter_meta_group_remove_meta (priv->constraints, meta);
14916 clutter_actor_queue_relayout (self);
14920 * clutter_actor_get_constraints:
14921 * @self: a #ClutterActor
14923 * Retrieves the list of constraints applied to @self
14925 * Return value: (transfer container) (element-type Clutter.Constraint): a copy
14926 * of the list of #ClutterConstraint<!-- -->s. The contents of the list are
14927 * owned by the #ClutterActor. Use g_list_free() to free the resources
14928 * allocated by the returned #GList
14933 clutter_actor_get_constraints (ClutterActor *self)
14935 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14937 if (self->priv->constraints == NULL)
14940 return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
14944 * clutter_actor_get_constraint:
14945 * @self: a #ClutterActor
14946 * @name: the name of the constraint to retrieve
14948 * Retrieves the #ClutterConstraint with the given name in the list
14949 * of constraints applied to @self
14951 * Return value: (transfer none): a #ClutterConstraint for the given
14952 * name, or %NULL. The returned #ClutterConstraint is owned by the
14953 * actor and it should not be unreferenced directly
14957 ClutterConstraint *
14958 clutter_actor_get_constraint (ClutterActor *self,
14961 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14962 g_return_val_if_fail (name != NULL, NULL);
14964 if (self->priv->constraints == NULL)
14967 return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
14971 * clutter_actor_clear_constraints:
14972 * @self: a #ClutterActor
14974 * Clears the list of constraints applied to @self
14979 clutter_actor_clear_constraints (ClutterActor *self)
14981 g_return_if_fail (CLUTTER_IS_ACTOR (self));
14983 if (self->priv->constraints == NULL)
14986 _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
14988 clutter_actor_queue_relayout (self);
14992 * clutter_actor_set_clip_to_allocation:
14993 * @self: a #ClutterActor
14994 * @clip_set: %TRUE to apply a clip tracking the allocation
14996 * Sets whether @self should be clipped to the same size as its
15002 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15005 ClutterActorPrivate *priv;
15007 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15009 clip_set = !!clip_set;
15013 if (priv->clip_to_allocation != clip_set)
15015 priv->clip_to_allocation = clip_set;
15017 clutter_actor_queue_redraw (self);
15019 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15024 * clutter_actor_get_clip_to_allocation:
15025 * @self: a #ClutterActor
15027 * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15029 * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15034 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15036 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15038 return self->priv->clip_to_allocation;
15042 * clutter_actor_add_effect:
15043 * @self: a #ClutterActor
15044 * @effect: a #ClutterEffect
15046 * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15048 * The #ClutterActor will hold a reference on the @effect until either
15049 * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15055 clutter_actor_add_effect (ClutterActor *self,
15056 ClutterEffect *effect)
15058 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15059 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15061 _clutter_actor_add_effect_internal (self, effect);
15063 clutter_actor_queue_redraw (self);
15065 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15069 * clutter_actor_add_effect_with_name:
15070 * @self: a #ClutterActor
15071 * @name: the name to set on the effect
15072 * @effect: a #ClutterEffect
15074 * A convenience function for setting the name of a #ClutterEffect
15075 * while adding it to the list of effectss applied to @self
15077 * This function is the logical equivalent of:
15080 * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15081 * clutter_actor_add_effect (self, effect);
15087 clutter_actor_add_effect_with_name (ClutterActor *self,
15089 ClutterEffect *effect)
15091 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15092 g_return_if_fail (name != NULL);
15093 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15095 clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15096 clutter_actor_add_effect (self, effect);
15100 * clutter_actor_remove_effect:
15101 * @self: a #ClutterActor
15102 * @effect: a #ClutterEffect
15104 * Removes @effect from the list of effects applied to @self
15106 * The reference held by @self on the #ClutterEffect will be released
15111 clutter_actor_remove_effect (ClutterActor *self,
15112 ClutterEffect *effect)
15114 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15115 g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15117 _clutter_actor_remove_effect_internal (self, effect);
15119 clutter_actor_queue_redraw (self);
15121 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15125 * clutter_actor_remove_effect_by_name:
15126 * @self: a #ClutterActor
15127 * @name: the name of the effect to remove
15129 * Removes the #ClutterEffect with the given name from the list
15130 * of effects applied to @self
15135 clutter_actor_remove_effect_by_name (ClutterActor *self,
15138 ClutterActorPrivate *priv;
15139 ClutterActorMeta *meta;
15141 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15142 g_return_if_fail (name != NULL);
15146 if (priv->effects == NULL)
15149 meta = _clutter_meta_group_get_meta (priv->effects, name);
15153 clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15157 * clutter_actor_get_effects:
15158 * @self: a #ClutterActor
15160 * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15162 * Return value: (transfer container) (element-type Clutter.Effect): a list
15163 * of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15164 * list are owned by Clutter and they should not be freed. You should
15165 * free the returned list using g_list_free() when done
15170 clutter_actor_get_effects (ClutterActor *self)
15172 ClutterActorPrivate *priv;
15174 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15178 if (priv->effects == NULL)
15181 return _clutter_meta_group_get_metas_no_internal (priv->effects);
15185 * clutter_actor_get_effect:
15186 * @self: a #ClutterActor
15187 * @name: the name of the effect to retrieve
15189 * Retrieves the #ClutterEffect with the given name in the list
15190 * of effects applied to @self
15192 * Return value: (transfer none): a #ClutterEffect for the given
15193 * name, or %NULL. The returned #ClutterEffect is owned by the
15194 * actor and it should not be unreferenced directly
15199 clutter_actor_get_effect (ClutterActor *self,
15202 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15203 g_return_val_if_fail (name != NULL, NULL);
15205 if (self->priv->effects == NULL)
15208 return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15212 * clutter_actor_clear_effects:
15213 * @self: a #ClutterActor
15215 * Clears the list of effects applied to @self
15220 clutter_actor_clear_effects (ClutterActor *self)
15222 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15224 if (self->priv->effects == NULL)
15227 _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15229 clutter_actor_queue_redraw (self);
15233 * clutter_actor_has_key_focus:
15234 * @self: a #ClutterActor
15236 * Checks whether @self is the #ClutterActor that has key focus
15238 * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15243 clutter_actor_has_key_focus (ClutterActor *self)
15245 ClutterActor *stage;
15247 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15249 stage = _clutter_actor_get_stage_internal (self);
15253 return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15257 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15258 ClutterPaintVolume *pv)
15260 ClutterActorPrivate *priv = self->priv;
15262 /* Actors are only expected to report a valid paint volume
15263 * while they have a valid allocation. */
15264 if (G_UNLIKELY (priv->needs_allocation))
15266 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15267 "Actor needs allocation",
15268 _clutter_actor_get_debug_name (self));
15272 /* Check if there are any handlers connected to the paint
15273 * signal. If there are then all bets are off for what the paint
15274 * volume for this actor might possibly be!
15276 * XXX: It's expected that this is going to end up being quite a
15277 * costly check to have to do here, but we haven't come up with
15278 * another solution that can reliably catch paint signal handlers at
15279 * the right time to either avoid artefacts due to invalid stage
15280 * clipping or due to incorrect culling.
15282 * Previously we checked in clutter_actor_paint(), but at that time
15283 * we may already be using a stage clip that could be derived from
15284 * an invalid paint-volume. We used to try and handle that by
15285 * queuing a follow up, unclipped, redraw but still the previous
15286 * checking wasn't enough to catch invalid volumes involved in
15287 * culling (considering that containers may derive their volume from
15288 * children that haven't yet been painted)
15290 * Longer term, improved solutions could be:
15291 * - Disallow painting in the paint signal, only allow using it
15292 * for tracking when paints happen. We can add another API that
15293 * allows monkey patching the paint of arbitrary actors but in a
15294 * more controlled way and that also supports modifying the
15296 * - If we could be notified somehow when signal handlers are
15297 * connected we wouldn't have to poll for handlers like this.
15299 if (g_signal_has_handler_pending (self,
15300 actor_signals[PAINT],
15304 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15305 "Actor has \"paint\" signal handlers",
15306 _clutter_actor_get_debug_name (self));
15310 _clutter_paint_volume_init_static (pv, self);
15312 if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15314 clutter_paint_volume_free (pv);
15315 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15316 "Actor failed to report a volume",
15317 _clutter_actor_get_debug_name (self));
15321 /* since effects can modify the paint volume, we allow them to actually
15322 * do this by making get_paint_volume() "context sensitive"
15324 if (priv->effects != NULL)
15326 if (priv->current_effect != NULL)
15328 const GList *effects, *l;
15330 /* if we are being called from within the paint sequence of
15331 * an actor, get the paint volume up to the current effect
15333 effects = _clutter_meta_group_peek_metas (priv->effects);
15335 l != NULL || (l != NULL && l->data != priv->current_effect);
15338 if (!_clutter_effect_get_paint_volume (l->data, pv))
15340 clutter_paint_volume_free (pv);
15341 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15342 "Effect (%s) failed to report a volume",
15343 _clutter_actor_get_debug_name (self),
15344 _clutter_actor_meta_get_debug_name (l->data));
15351 const GList *effects, *l;
15353 /* otherwise, get the cumulative volume */
15354 effects = _clutter_meta_group_peek_metas (priv->effects);
15355 for (l = effects; l != NULL; l = l->next)
15356 if (!_clutter_effect_get_paint_volume (l->data, pv))
15358 clutter_paint_volume_free (pv);
15359 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15360 "Effect (%s) failed to report a volume",
15361 _clutter_actor_get_debug_name (self),
15362 _clutter_actor_meta_get_debug_name (l->data));
15371 /* The public clutter_actor_get_paint_volume API returns a const
15372 * pointer since we return a pointer directly to the cached
15373 * PaintVolume associated with the actor and don't want the user to
15374 * inadvertently modify it, but for internal uses we sometimes need
15375 * access to the same PaintVolume but need to apply some book-keeping
15376 * modifications to it so we don't want a const pointer.
15378 static ClutterPaintVolume *
15379 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15381 ClutterActorPrivate *priv;
15385 if (priv->paint_volume_valid)
15386 clutter_paint_volume_free (&priv->paint_volume);
15388 if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15390 priv->paint_volume_valid = TRUE;
15391 return &priv->paint_volume;
15395 priv->paint_volume_valid = FALSE;
15401 * clutter_actor_get_paint_volume:
15402 * @self: a #ClutterActor
15404 * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15405 * when a paint volume can't be determined.
15407 * The paint volume is defined as the 3D space occupied by an actor
15408 * when being painted.
15410 * This function will call the <function>get_paint_volume()</function>
15411 * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15412 * should not usually care about overriding the default implementation,
15413 * unless they are, for instance: painting outside their allocation, or
15414 * actors with a depth factor (not in terms of #ClutterActor:depth but real
15417 * <note>2D actors overriding <function>get_paint_volume()</function>
15418 * ensure their volume has a depth of 0. (This will be true so long as
15419 * you don't call clutter_paint_volume_set_depth().)</note>
15421 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15422 * or %NULL if no volume could be determined. The returned pointer
15423 * is not guaranteed to be valid across multiple frames; if you want
15424 * to keep it, you will need to copy it using clutter_paint_volume_copy().
15428 const ClutterPaintVolume *
15429 clutter_actor_get_paint_volume (ClutterActor *self)
15431 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15433 return _clutter_actor_get_paint_volume_mutable (self);
15437 * clutter_actor_get_transformed_paint_volume:
15438 * @self: a #ClutterActor
15439 * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15440 * (or %NULL for the stage)
15442 * Retrieves the 3D paint volume of an actor like
15443 * clutter_actor_get_paint_volume() does (Please refer to the
15444 * documentation of clutter_actor_get_paint_volume() for more
15445 * details.) and it additionally transforms the paint volume into the
15446 * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15447 * is passed for @relative_to_ancestor)
15449 * This can be used by containers that base their paint volume on
15450 * the volume of their children. Such containers can query the
15451 * transformed paint volume of all of its children and union them
15452 * together using clutter_paint_volume_union().
15454 * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15455 * or %NULL if no volume could be determined. The returned pointer is
15456 * not guaranteed to be valid across multiple frames; if you wish to
15457 * keep it, you will have to copy it using clutter_paint_volume_copy().
15461 const ClutterPaintVolume *
15462 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15463 ClutterActor *relative_to_ancestor)
15465 const ClutterPaintVolume *volume;
15466 ClutterActor *stage;
15467 ClutterPaintVolume *transformed_volume;
15469 stage = _clutter_actor_get_stage_internal (self);
15470 if (G_UNLIKELY (stage == NULL))
15473 if (relative_to_ancestor == NULL)
15474 relative_to_ancestor = stage;
15476 volume = clutter_actor_get_paint_volume (self);
15477 if (volume == NULL)
15480 transformed_volume =
15481 _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15483 _clutter_paint_volume_copy_static (volume, transformed_volume);
15485 _clutter_paint_volume_transform_relative (transformed_volume,
15486 relative_to_ancestor);
15488 return transformed_volume;
15492 * clutter_actor_get_paint_box:
15493 * @self: a #ClutterActor
15494 * @box: (out): return location for a #ClutterActorBox
15496 * Retrieves the paint volume of the passed #ClutterActor, and
15497 * transforms it into a 2D bounding box in stage coordinates.
15499 * This function is useful to determine the on screen area occupied by
15500 * the actor. The box is only an approximation and may often be
15501 * considerably larger due to the optimizations used to calculate the
15502 * box. The box is never smaller though, so it can reliably be used
15505 * There are times when a 2D paint box can't be determined, e.g.
15506 * because the actor isn't yet parented under a stage or because
15507 * the actor is unable to determine a paint volume.
15509 * Return value: %TRUE if a 2D paint box could be determined, else
15515 clutter_actor_get_paint_box (ClutterActor *self,
15516 ClutterActorBox *box)
15518 ClutterActor *stage;
15519 ClutterPaintVolume *pv;
15521 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15522 g_return_val_if_fail (box != NULL, FALSE);
15524 stage = _clutter_actor_get_stage_internal (self);
15525 if (G_UNLIKELY (!stage))
15528 pv = _clutter_actor_get_paint_volume_mutable (self);
15529 if (G_UNLIKELY (!pv))
15532 _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15538 * clutter_actor_has_overlaps:
15539 * @self: A #ClutterActor
15541 * Asks the actor's implementation whether it may contain overlapping
15544 * For example; Clutter may use this to determine whether the painting
15545 * should be redirected to an offscreen buffer to correctly implement
15546 * the opacity property.
15548 * Custom actors can override the default response by implementing the
15549 * #ClutterActor <function>has_overlaps</function> virtual function. See
15550 * clutter_actor_set_offscreen_redirect() for more information.
15552 * Return value: %TRUE if the actor may have overlapping primitives, and
15558 clutter_actor_has_overlaps (ClutterActor *self)
15560 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15562 return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15566 * clutter_actor_has_effects:
15567 * @self: A #ClutterActor
15569 * Returns whether the actor has any effects applied.
15571 * Return value: %TRUE if the actor has any effects,
15577 clutter_actor_has_effects (ClutterActor *self)
15579 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15581 if (self->priv->effects == NULL)
15584 return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15588 * clutter_actor_has_constraints:
15589 * @self: A #ClutterActor
15591 * Returns whether the actor has any constraints applied.
15593 * Return value: %TRUE if the actor has any constraints,
15599 clutter_actor_has_constraints (ClutterActor *self)
15601 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15603 return self->priv->constraints != NULL;
15607 * clutter_actor_has_actions:
15608 * @self: A #ClutterActor
15610 * Returns whether the actor has any actions applied.
15612 * Return value: %TRUE if the actor has any actions,
15618 clutter_actor_has_actions (ClutterActor *self)
15620 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15622 return self->priv->actions != NULL;
15626 * clutter_actor_get_n_children:
15627 * @self: a #ClutterActor
15629 * Retrieves the number of children of @self.
15631 * Return value: the number of children of an actor
15636 clutter_actor_get_n_children (ClutterActor *self)
15638 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15640 return self->priv->n_children;
15644 * clutter_actor_get_child_at_index:
15645 * @self: a #ClutterActor
15646 * @index_: the position in the list of children
15648 * Retrieves the actor at the given @index_ inside the list of
15649 * children of @self.
15651 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15656 clutter_actor_get_child_at_index (ClutterActor *self,
15659 ClutterActor *iter;
15662 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15663 g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15665 for (iter = self->priv->first_child, i = 0;
15666 iter != NULL && i < index_;
15667 iter = iter->priv->next_sibling, i += 1)
15674 * _clutter_actor_foreach_child:
15675 * @actor: The actor whos children you want to iterate
15676 * @callback: The function to call for each child
15677 * @user_data: Private data to pass to @callback
15679 * Calls a given @callback once for each child of the specified @actor and
15680 * passing the @user_data pointer each time.
15682 * Return value: returns %TRUE if all children were iterated, else
15683 * %FALSE if a callback broke out of iteration early.
15686 _clutter_actor_foreach_child (ClutterActor *self,
15687 ClutterForeachCallback callback,
15688 gpointer user_data)
15690 ClutterActorPrivate *priv = self->priv;
15691 ClutterActor *iter;
15694 for (cont = TRUE, iter = priv->first_child;
15695 cont && iter != NULL;
15696 iter = iter->priv->next_sibling)
15698 cont = callback (iter, user_data);
15705 /* For debugging purposes this gives us a simple way to print out
15706 * the scenegraph e.g in gdb using:
15708 * _clutter_actor_traverse (stage,
15710 * clutter_debug_print_actor_cb,
15715 static ClutterActorTraverseVisitFlags
15716 clutter_debug_print_actor_cb (ClutterActor *actor,
15720 g_print ("%*s%s:%p\n",
15722 _clutter_actor_get_debug_name (actor),
15725 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15730 _clutter_actor_traverse_breadth (ClutterActor *actor,
15731 ClutterTraverseCallback callback,
15732 gpointer user_data)
15734 GQueue *queue = g_queue_new ();
15735 ClutterActor dummy;
15736 int current_depth = 0;
15738 g_queue_push_tail (queue, actor);
15739 g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15741 while ((actor = g_queue_pop_head (queue)))
15743 ClutterActorTraverseVisitFlags flags;
15745 if (actor == &dummy)
15748 g_queue_push_tail (queue, &dummy);
15752 flags = callback (actor, current_depth, user_data);
15753 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15755 else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15757 ClutterActor *iter;
15759 for (iter = actor->priv->first_child;
15761 iter = iter->priv->next_sibling)
15763 g_queue_push_tail (queue, iter);
15768 g_queue_free (queue);
15771 static ClutterActorTraverseVisitFlags
15772 _clutter_actor_traverse_depth (ClutterActor *actor,
15773 ClutterTraverseCallback before_children_callback,
15774 ClutterTraverseCallback after_children_callback,
15776 gpointer user_data)
15778 ClutterActorTraverseVisitFlags flags;
15780 flags = before_children_callback (actor, current_depth, user_data);
15781 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15782 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15784 if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15786 ClutterActor *iter;
15788 for (iter = actor->priv->first_child;
15790 iter = iter->priv->next_sibling)
15792 flags = _clutter_actor_traverse_depth (iter,
15793 before_children_callback,
15794 after_children_callback,
15798 if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15799 return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15803 if (after_children_callback)
15804 return after_children_callback (actor, current_depth, user_data);
15806 return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15809 /* _clutter_actor_traverse:
15810 * @actor: The actor to start traversing the graph from
15811 * @flags: These flags may affect how the traversal is done
15812 * @before_children_callback: A function to call before visiting the
15813 * children of the current actor.
15814 * @after_children_callback: A function to call after visiting the
15815 * children of the current actor. (Ignored if
15816 * %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15817 * @user_data: The private data to pass to the callbacks
15819 * Traverses the scenegraph starting at the specified @actor and
15820 * descending through all its children and its children's children.
15821 * For each actor traversed @before_children_callback and
15822 * @after_children_callback are called with the specified
15823 * @user_data, before and after visiting that actor's children.
15825 * The callbacks can return flags that affect the ongoing traversal
15826 * such as by skipping over an actors children or bailing out of
15827 * any further traversing.
15830 _clutter_actor_traverse (ClutterActor *actor,
15831 ClutterActorTraverseFlags flags,
15832 ClutterTraverseCallback before_children_callback,
15833 ClutterTraverseCallback after_children_callback,
15834 gpointer user_data)
15836 if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15837 _clutter_actor_traverse_breadth (actor,
15838 before_children_callback,
15840 else /* DEPTH_FIRST */
15841 _clutter_actor_traverse_depth (actor,
15842 before_children_callback,
15843 after_children_callback,
15844 0, /* start depth */
15849 on_layout_manager_changed (ClutterLayoutManager *manager,
15850 ClutterActor *self)
15852 clutter_actor_queue_relayout (self);
15856 * clutter_actor_set_layout_manager:
15857 * @self: a #ClutterActor
15858 * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15860 * Sets the #ClutterLayoutManager delegate object that will be used to
15861 * lay out the children of @self.
15863 * The #ClutterActor will take a reference on the passed @manager which
15864 * will be released either when the layout manager is removed, or when
15865 * the actor is destroyed.
15870 clutter_actor_set_layout_manager (ClutterActor *self,
15871 ClutterLayoutManager *manager)
15873 ClutterActorPrivate *priv;
15875 g_return_if_fail (CLUTTER_IS_ACTOR (self));
15876 g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15880 if (priv->layout_manager != NULL)
15882 g_signal_handlers_disconnect_by_func (priv->layout_manager,
15883 G_CALLBACK (on_layout_manager_changed),
15885 clutter_layout_manager_set_container (priv->layout_manager, NULL);
15886 g_object_unref (priv->layout_manager);
15889 priv->layout_manager = manager;
15891 if (priv->layout_manager != NULL)
15893 g_object_ref_sink (priv->layout_manager);
15894 clutter_layout_manager_set_container (priv->layout_manager,
15895 CLUTTER_CONTAINER (self));
15896 g_signal_connect (priv->layout_manager, "layout-changed",
15897 G_CALLBACK (on_layout_manager_changed),
15901 clutter_actor_queue_relayout (self);
15903 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
15907 * clutter_actor_get_layout_manager:
15908 * @self: a #ClutterActor
15910 * Retrieves the #ClutterLayoutManager used by @self.
15912 * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
15917 ClutterLayoutManager *
15918 clutter_actor_get_layout_manager (ClutterActor *self)
15920 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15922 return self->priv->layout_manager;
15925 static const ClutterLayoutInfo default_layout_info = {
15928 { 0, 0, 0, 0 }, /* margin */
15929 CLUTTER_ACTOR_ALIGN_FILL, /* x-align */
15930 CLUTTER_ACTOR_ALIGN_FILL, /* y-align */
15931 0.f, 0.f, /* min_width, natural_width */
15932 0.f, 0.f, /* natual_width, natural_height */
15936 layout_info_free (gpointer data)
15938 if (G_LIKELY (data != NULL))
15939 g_slice_free (ClutterLayoutInfo, data);
15943 * _clutter_actor_get_layout_info:
15944 * @self: a #ClutterActor
15946 * Retrieves a pointer to the ClutterLayoutInfo structure.
15948 * If the actor does not have a ClutterLayoutInfo associated to it, one
15949 * will be created and initialized to the default values.
15951 * This function should be used for setters.
15953 * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
15956 * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
15958 ClutterLayoutInfo *
15959 _clutter_actor_get_layout_info (ClutterActor *self)
15961 ClutterLayoutInfo *retval;
15963 retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15964 if (retval == NULL)
15966 retval = g_slice_new (ClutterLayoutInfo);
15968 *retval = default_layout_info;
15970 g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
15979 * _clutter_actor_get_layout_info_or_defaults:
15980 * @self: a #ClutterActor
15982 * Retrieves the ClutterLayoutInfo structure associated to an actor.
15984 * If the actor does not have a ClutterLayoutInfo structure associated to it,
15985 * then the default structure will be returned.
15987 * This function should only be used for getters.
15989 * Return value: a const pointer to the ClutterLayoutInfo structure
15991 const ClutterLayoutInfo *
15992 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
15994 const ClutterLayoutInfo *info;
15996 info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
15998 return &default_layout_info;
16004 * clutter_actor_set_x_align:
16005 * @self: a #ClutterActor
16006 * @x_align: the horizontal alignment policy
16008 * Sets the horizontal alignment policy of a #ClutterActor, in case the
16009 * actor received extra horizontal space.
16011 * See also the #ClutterActor:x-align property.
16016 clutter_actor_set_x_align (ClutterActor *self,
16017 ClutterActorAlign x_align)
16019 ClutterLayoutInfo *info;
16021 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16023 info = _clutter_actor_get_layout_info (self);
16025 if (info->x_align != x_align)
16027 info->x_align = x_align;
16029 clutter_actor_queue_relayout (self);
16031 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16036 * clutter_actor_get_x_align:
16037 * @self: a #ClutterActor
16039 * Retrieves the horizontal alignment policy set using
16040 * clutter_actor_set_x_align().
16042 * Return value: the horizontal alignment policy.
16047 clutter_actor_get_x_align (ClutterActor *self)
16049 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16051 return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16055 * clutter_actor_set_y_align:
16056 * @self: a #ClutterActor
16057 * @y_align: the vertical alignment policy
16059 * Sets the vertical alignment policy of a #ClutterActor, in case the
16060 * actor received extra vertical space.
16062 * See also the #ClutterActor:y-align property.
16067 clutter_actor_set_y_align (ClutterActor *self,
16068 ClutterActorAlign y_align)
16070 ClutterLayoutInfo *info;
16072 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16074 info = _clutter_actor_get_layout_info (self);
16076 if (info->y_align != y_align)
16078 info->y_align = y_align;
16080 clutter_actor_queue_relayout (self);
16082 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16087 * clutter_actor_get_y_align:
16088 * @self: a #ClutterActor
16090 * Retrieves the vertical alignment policy set using
16091 * clutter_actor_set_y_align().
16093 * Return value: the vertical alignment policy.
16098 clutter_actor_get_y_align (ClutterActor *self)
16100 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16102 return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16107 * clutter_margin_new:
16109 * Creates a new #ClutterMargin.
16111 * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16112 * clutter_margin_free() to free the resources associated with it when
16118 clutter_margin_new (void)
16120 return g_slice_new0 (ClutterMargin);
16124 * clutter_margin_copy:
16125 * @margin_: a #ClutterMargin
16127 * Creates a new #ClutterMargin and copies the contents of @margin_ into
16128 * the newly created structure.
16130 * Return value: (transfer full): a copy of the #ClutterMargin.
16135 clutter_margin_copy (const ClutterMargin *margin_)
16137 if (G_LIKELY (margin_ != NULL))
16138 return g_slice_dup (ClutterMargin, margin_);
16144 * clutter_margin_free:
16145 * @margin_: a #ClutterMargin
16147 * Frees the resources allocated by clutter_margin_new() and
16148 * clutter_margin_copy().
16153 clutter_margin_free (ClutterMargin *margin_)
16155 if (G_LIKELY (margin_ != NULL))
16156 g_slice_free (ClutterMargin, margin_);
16159 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16160 clutter_margin_copy,
16161 clutter_margin_free)
16164 * clutter_actor_set_margin:
16165 * @self: a #ClutterActor
16166 * @margin: a #ClutterMargin
16168 * Sets all the components of the margin of a #ClutterActor.
16173 clutter_actor_set_margin (ClutterActor *self,
16174 const ClutterMargin *margin)
16176 ClutterLayoutInfo *info;
16180 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16181 g_return_if_fail (margin != NULL);
16183 obj = G_OBJECT (self);
16186 g_object_freeze_notify (obj);
16188 info = _clutter_actor_get_layout_info (self);
16190 if (info->margin.top != margin->top)
16192 info->margin.top = margin->top;
16193 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16197 if (info->margin.right != margin->right)
16199 info->margin.right = margin->right;
16200 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16204 if (info->margin.bottom != margin->bottom)
16206 info->margin.bottom = margin->bottom;
16207 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16211 if (info->margin.left != margin->left)
16213 info->margin.left = margin->left;
16214 g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16219 clutter_actor_queue_relayout (self);
16221 g_object_thaw_notify (obj);
16225 * clutter_actor_get_margin:
16226 * @self: a #ClutterActor
16227 * @margin: (out caller-allocates): return location for a #ClutterMargin
16229 * Retrieves all the components of the margin of a #ClutterActor.
16234 clutter_actor_get_margin (ClutterActor *self,
16235 ClutterMargin *margin)
16237 const ClutterLayoutInfo *info;
16239 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16240 g_return_if_fail (margin != NULL);
16242 info = _clutter_actor_get_layout_info_or_defaults (self);
16244 *margin = info->margin;
16248 * clutter_actor_set_margin_top:
16249 * @self: a #ClutterActor
16250 * @margin: the top margin
16252 * Sets the margin from the top of a #ClutterActor.
16257 clutter_actor_set_margin_top (ClutterActor *self,
16260 ClutterLayoutInfo *info;
16262 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16263 g_return_if_fail (margin >= 0.f);
16265 info = _clutter_actor_get_layout_info (self);
16267 if (info->margin.top == margin)
16270 info->margin.top = margin;
16272 clutter_actor_queue_relayout (self);
16274 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16278 * clutter_actor_get_margin_top:
16279 * @self: a #ClutterActor
16281 * Retrieves the top margin of a #ClutterActor.
16283 * Return value: the top margin
16288 clutter_actor_get_margin_top (ClutterActor *self)
16290 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16292 return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16296 * clutter_actor_set_margin_bottom:
16297 * @self: a #ClutterActor
16298 * @margin: the bottom margin
16300 * Sets the margin from the bottom of a #ClutterActor.
16305 clutter_actor_set_margin_bottom (ClutterActor *self,
16308 ClutterLayoutInfo *info;
16310 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16311 g_return_if_fail (margin >= 0.f);
16313 info = _clutter_actor_get_layout_info (self);
16315 if (info->margin.bottom == margin)
16318 info->margin.bottom = margin;
16320 clutter_actor_queue_relayout (self);
16322 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16326 * clutter_actor_get_margin_bottom:
16327 * @self: a #ClutterActor
16329 * Retrieves the bottom margin of a #ClutterActor.
16331 * Return value: the bottom margin
16336 clutter_actor_get_margin_bottom (ClutterActor *self)
16338 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16340 return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16344 * clutter_actor_set_margin_left:
16345 * @self: a #ClutterActor
16346 * @margin: the left margin
16348 * Sets the margin from the left of a #ClutterActor.
16353 clutter_actor_set_margin_left (ClutterActor *self,
16356 ClutterLayoutInfo *info;
16358 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16359 g_return_if_fail (margin >= 0.f);
16361 info = _clutter_actor_get_layout_info (self);
16363 if (info->margin.left == margin)
16366 info->margin.left = margin;
16368 clutter_actor_queue_relayout (self);
16370 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16374 * clutter_actor_get_margin_left:
16375 * @self: a #ClutterActor
16377 * Retrieves the left margin of a #ClutterActor.
16379 * Return value: the left margin
16384 clutter_actor_get_margin_left (ClutterActor *self)
16386 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16388 return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16392 * clutter_actor_set_margin_right:
16393 * @self: a #ClutterActor
16394 * @margin: the right margin
16396 * Sets the margin from the right of a #ClutterActor.
16401 clutter_actor_set_margin_right (ClutterActor *self,
16404 ClutterLayoutInfo *info;
16406 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16407 g_return_if_fail (margin >= 0.f);
16409 info = _clutter_actor_get_layout_info (self);
16411 if (info->margin.right == margin)
16414 info->margin.right = margin;
16416 clutter_actor_queue_relayout (self);
16418 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16422 * clutter_actor_get_margin_right:
16423 * @self: a #ClutterActor
16425 * Retrieves the right margin of a #ClutterActor.
16427 * Return value: the right margin
16432 clutter_actor_get_margin_right (ClutterActor *self)
16434 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16436 return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16440 clutter_actor_set_background_color_internal (ClutterActor *self,
16441 const ClutterColor *color)
16443 ClutterActorPrivate *priv = self->priv;
16446 if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16449 obj = G_OBJECT (self);
16451 priv->bg_color = *color;
16452 priv->bg_color_set = TRUE;
16454 clutter_actor_queue_redraw (self);
16456 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16457 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16461 * clutter_actor_set_background_color:
16462 * @self: a #ClutterActor
16463 * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16466 * Sets the background color of a #ClutterActor.
16468 * The background color will be used to cover the whole allocation of the
16469 * actor. The default background color of an actor is transparent.
16471 * To check whether an actor has a background color, you can use the
16472 * #ClutterActor:background-color-set actor property.
16474 * The #ClutterActor:background-color property is animatable.
16479 clutter_actor_set_background_color (ClutterActor *self,
16480 const ClutterColor *color)
16482 ClutterActorPrivate *priv;
16484 GParamSpec *bg_color_pspec;
16486 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16488 obj = G_OBJECT (self);
16494 priv->bg_color_set = FALSE;
16495 g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16496 clutter_actor_queue_redraw (self);
16500 bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16501 if (clutter_actor_get_easing_duration (self) != 0)
16503 ClutterTransition *transition;
16505 transition = _clutter_actor_get_transition (self, bg_color_pspec);
16506 if (transition == NULL)
16508 transition = _clutter_actor_create_transition (self, bg_color_pspec,
16511 clutter_timeline_start (CLUTTER_TIMELINE (transition));
16514 _clutter_actor_update_transition (self, bg_color_pspec, color);
16516 clutter_actor_queue_redraw (self);
16519 clutter_actor_set_background_color_internal (self, color);
16523 * clutter_actor_get_background_color:
16524 * @self: a #ClutterActor
16525 * @color: (out caller-allocates): return location for a #ClutterColor
16527 * Retrieves the color set using clutter_actor_set_background_color().
16532 clutter_actor_get_background_color (ClutterActor *self,
16533 ClutterColor *color)
16535 g_return_if_fail (CLUTTER_IS_ACTOR (self));
16536 g_return_if_fail (color != NULL);
16538 *color = self->priv->bg_color;
16542 * clutter_actor_get_previous_sibling:
16543 * @self: a #ClutterActor
16545 * Retrieves the sibling of @self that comes before it in the list
16546 * of children of @self's parent.
16548 * The returned pointer is only valid until the scene graph changes; it
16549 * is not safe to modify the list of children of @self while iterating
16552 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16557 clutter_actor_get_previous_sibling (ClutterActor *self)
16559 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16561 return self->priv->prev_sibling;
16565 * clutter_actor_get_next_sibling:
16566 * @self: a #ClutterActor
16568 * Retrieves the sibling of @self that comes after it in the list
16569 * of children of @self's parent.
16571 * The returned pointer is only valid until the scene graph changes; it
16572 * is not safe to modify the list of children of @self while iterating
16575 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16580 clutter_actor_get_next_sibling (ClutterActor *self)
16582 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16584 return self->priv->next_sibling;
16588 * clutter_actor_get_first_child:
16589 * @self: a #ClutterActor
16591 * Retrieves the first child of @self.
16593 * The returned pointer is only valid until the scene graph changes; it
16594 * is not safe to modify the list of children of @self while iterating
16597 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16602 clutter_actor_get_first_child (ClutterActor *self)
16604 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16606 return self->priv->first_child;
16610 * clutter_actor_get_last_child:
16611 * @self: a #ClutterActor
16613 * Retrieves the last child of @self.
16615 * The returned pointer is only valid until the scene graph changes; it
16616 * is not safe to modify the list of children of @self while iterating
16619 * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16624 clutter_actor_get_last_child (ClutterActor *self)
16626 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16628 return self->priv->last_child;
16631 /* easy way to have properly named fields instead of the dummy ones
16632 * we use in the public structure
16634 typedef struct _RealActorIter
16636 ClutterActor *root; /* dummy1 */
16637 ClutterActor *current; /* dummy2 */
16638 gpointer padding_1; /* dummy3 */
16639 gint age; /* dummy4 */
16640 gpointer padding_2; /* dummy5 */
16644 * clutter_actor_iter_init:
16645 * @iter: a #ClutterActorIter
16646 * @root: a #ClutterActor
16648 * Initializes a #ClutterActorIter, which can then be used to iterate
16649 * efficiently over a section of the scene graph, and associates it
16652 * Modifying the scene graph section that contains @root will invalidate
16656 * ClutterActorIter iter;
16657 * ClutterActor *child;
16659 * clutter_actor_iter_init (&iter, container);
16660 * while (clutter_actor_iter_next (&iter, &child))
16662 * /* do something with child */
16669 clutter_actor_iter_init (ClutterActorIter *iter,
16670 ClutterActor *root)
16672 RealActorIter *ri = (RealActorIter *) iter;
16674 g_return_if_fail (iter != NULL);
16675 g_return_if_fail (CLUTTER_IS_ACTOR (root));
16678 ri->current = NULL;
16679 ri->age = root->priv->age;
16683 * clutter_actor_iter_next:
16684 * @iter: a #ClutterActorIter
16685 * @child: (out): return location for a #ClutterActor
16687 * Advances the @iter and retrieves the next child of the root #ClutterActor
16688 * that was used to initialize the #ClutterActorIterator.
16690 * If the iterator can advance, this function returns %TRUE and sets the
16693 * If the iterator cannot advance, this function returns %FALSE, and
16694 * the contents of @child are undefined.
16696 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16701 clutter_actor_iter_next (ClutterActorIter *iter,
16702 ClutterActor **child)
16704 RealActorIter *ri = (RealActorIter *) iter;
16706 g_return_val_if_fail (iter != NULL, FALSE);
16707 g_return_val_if_fail (ri->root != NULL, FALSE);
16708 #ifndef G_DISABLE_ASSERT
16709 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16712 if (ri->current == NULL)
16713 ri->current = ri->root->priv->first_child;
16715 ri->current = ri->current->priv->next_sibling;
16718 *child = ri->current;
16720 return ri->current != NULL;
16724 * clutter_actor_iter_prev:
16725 * @iter: a #ClutterActorIter
16726 * @child: (out): return location for a #ClutterActor
16728 * Advances the @iter and retrieves the previous child of the root
16729 * #ClutterActor that was used to initialize the #ClutterActorIterator.
16731 * If the iterator can advance, this function returns %TRUE and sets the
16734 * If the iterator cannot advance, this function returns %FALSE, and
16735 * the contents of @child are undefined.
16737 * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16742 clutter_actor_iter_prev (ClutterActorIter *iter,
16743 ClutterActor **child)
16745 RealActorIter *ri = (RealActorIter *) iter;
16747 g_return_val_if_fail (iter != NULL, FALSE);
16748 g_return_val_if_fail (ri->root != NULL, FALSE);
16749 #ifndef G_DISABLE_ASSERT
16750 g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16753 if (ri->current == NULL)
16754 ri->current = ri->root->priv->last_child;
16756 ri->current = ri->current->priv->prev_sibling;
16759 *child = ri->current;
16761 return ri->current != NULL;
16765 * clutter_actor_iter_remove:
16766 * @iter: a #ClutterActorIter
16768 * Safely removes the #ClutterActor currently pointer to by the iterator
16771 * This function can only be called after clutter_actor_iter_next() or
16772 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16773 * than once for the same actor.
16775 * This function will call clutter_actor_remove_child() internally.
16780 clutter_actor_iter_remove (ClutterActorIter *iter)
16782 RealActorIter *ri = (RealActorIter *) iter;
16785 g_return_if_fail (iter != NULL);
16786 g_return_if_fail (ri->root != NULL);
16787 #ifndef G_DISABLE_ASSERT
16788 g_return_if_fail (ri->age == ri->root->priv->age);
16790 g_return_if_fail (ri->current != NULL);
16796 ri->current = cur->priv->prev_sibling;
16798 clutter_actor_remove_child_internal (ri->root, cur,
16799 REMOVE_CHILD_DEFAULT_FLAGS);
16806 * clutter_actor_iter_destroy:
16807 * @iter: a #ClutterActorIter
16809 * Safely destroys the #ClutterActor currently pointer to by the iterator
16812 * This function can only be called after clutter_actor_iter_next() or
16813 * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16814 * than once for the same actor.
16816 * This function will call clutter_actor_destroy() internally.
16821 clutter_actor_iter_destroy (ClutterActorIter *iter)
16823 RealActorIter *ri = (RealActorIter *) iter;
16826 g_return_if_fail (iter != NULL);
16827 g_return_if_fail (ri->root != NULL);
16828 #ifndef G_DISABLE_ASSERT
16829 g_return_if_fail (ri->age == ri->root->priv->age);
16831 g_return_if_fail (ri->current != NULL);
16837 ri->current = cur->priv->prev_sibling;
16839 clutter_actor_destroy (cur);
16845 static const ClutterAnimationInfo default_animation_info = {
16846 NULL, /* transitions */
16848 NULL, /* cur_state */
16852 clutter_animation_info_free (gpointer data)
16856 ClutterAnimationInfo *info = data;
16858 if (info->transitions != NULL)
16859 g_hash_table_unref (info->transitions);
16861 if (info->states != NULL)
16862 g_array_unref (info->states);
16864 g_slice_free (ClutterAnimationInfo, info);
16868 const ClutterAnimationInfo *
16869 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16871 const ClutterAnimationInfo *res;
16872 GObject *obj = G_OBJECT (self);
16874 res = g_object_get_qdata (obj, quark_actor_animation_info);
16878 return &default_animation_info;
16881 ClutterAnimationInfo *
16882 _clutter_actor_get_animation_info (ClutterActor *self)
16884 GObject *obj = G_OBJECT (self);
16885 ClutterAnimationInfo *res;
16887 res = g_object_get_qdata (obj, quark_actor_animation_info);
16890 res = g_slice_new (ClutterAnimationInfo);
16892 *res = default_animation_info;
16894 g_object_set_qdata_full (obj, quark_actor_animation_info,
16896 clutter_animation_info_free);
16902 ClutterTransition *
16903 _clutter_actor_get_transition (ClutterActor *actor,
16906 const ClutterAnimationInfo *info;
16908 info = _clutter_actor_get_animation_info_or_defaults (actor);
16910 if (info->transitions == NULL)
16913 return g_hash_table_lookup (info->transitions, pspec->name);
16916 typedef struct _TransitionClosure
16918 ClutterActor *actor;
16919 ClutterTransition *transition;
16921 gulong completed_id;
16922 } TransitionClosure;
16925 transition_closure_free (gpointer data)
16927 if (G_LIKELY (data != NULL))
16929 TransitionClosure *clos = data;
16931 g_signal_handler_disconnect (clos->transition, clos->completed_id);
16932 g_free (clos->name);
16934 g_slice_free (TransitionClosure, clos);
16939 on_transition_completed (ClutterTransition *transition,
16940 TransitionClosure *clos)
16942 ClutterAnimationInfo *info;
16944 info = _clutter_actor_get_animation_info (clos->actor);
16946 /* this will take care of cleaning clos for us */
16947 g_hash_table_remove (info->transitions, clos->name);
16951 _clutter_actor_update_transition (ClutterActor *actor,
16955 TransitionClosure *clos;
16956 ClutterInterval *interval;
16957 const ClutterAnimationInfo *info;
16960 GValue initial = G_VALUE_INIT;
16961 GValue final = G_VALUE_INIT;
16962 char *error = NULL;
16964 info = _clutter_actor_get_animation_info_or_defaults (actor);
16966 if (info->transitions == NULL)
16969 clos = g_hash_table_lookup (info->transitions, pspec->name);
16973 va_start (var_args, pspec);
16975 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
16977 g_value_init (&initial, ptype);
16978 clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
16982 G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
16985 g_critical ("%s: %s", G_STRLOC, error);
16990 interval = clutter_transition_get_interval (clos->transition);
16991 clutter_interval_set_initial_value (interval, &initial);
16992 clutter_interval_set_final_value (interval, &final);
16994 clutter_timeline_rewind (CLUTTER_TIMELINE (clos->transition));
16997 g_value_unset (&initial);
16998 g_value_unset (&final);
17004 * _clutter_actor_create_transition:
17005 * @actor: a #ClutterActor
17006 * @pspec: the property used for the transition
17007 * @...: initial and final state
17009 * Creates a #ClutterTransition for the property represented by @pspec.
17011 * Return value: a #ClutterTransition
17013 ClutterTransition *
17014 _clutter_actor_create_transition (ClutterActor *actor,
17018 ClutterAnimationInfo *info;
17019 ClutterTransition *res = NULL;
17020 gboolean call_restore = FALSE;
17021 TransitionClosure *clos;
17024 info = _clutter_actor_get_animation_info (actor);
17026 if (info->states == NULL)
17028 clutter_actor_save_easing_state (actor);
17029 call_restore = TRUE;
17032 if (info->transitions == NULL)
17033 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17035 transition_closure_free);
17037 va_start (var_args, pspec);
17039 clos = g_hash_table_lookup (info->transitions, pspec->name);
17042 ClutterInterval *interval;
17043 GValue initial = G_VALUE_INIT;
17044 GValue final = G_VALUE_INIT;
17048 ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17050 G_VALUE_COLLECT_INIT (&initial, ptype,
17055 g_critical ("%s: %s", G_STRLOC, error);
17060 G_VALUE_COLLECT_INIT (&final, ptype,
17066 g_critical ("%s: %s", G_STRLOC, error);
17067 g_value_unset (&initial);
17072 interval = clutter_interval_new_with_values (ptype, &initial, &final);
17074 g_value_unset (&initial);
17075 g_value_unset (&final);
17077 res = clutter_property_transition_new (CLUTTER_ANIMATABLE (actor),
17080 clutter_transition_set_interval (res, interval);
17081 clutter_transition_set_remove_on_complete (res, TRUE);
17083 clutter_actor_add_transition (actor, pspec->name, res);
17086 res = clos->transition;
17090 clutter_actor_restore_easing_state (actor);
17098 * clutter_actor_add_transition:
17099 * @self: a #ClutterActor
17100 * @name: the name of the transition to add
17101 * @transition: the #ClutterTransition to add
17103 * Adds a @transition to the #ClutterActor's list of animations.
17105 * The @name string is a per-actor unique identifier of the @transition: only
17106 * one #ClutterTransition can be associated to the specified @name.
17108 * The @transition will be given the easing duration, mode, and delay
17109 * associated to the actor's current easing state; it is possible to modify
17110 * these values after calling clutter_actor_add_transition().
17112 * This function is usually called implicitly when modifying an animatable
17118 clutter_actor_add_transition (ClutterActor *self,
17120 ClutterTransition *transition)
17122 ClutterTimeline *timeline;
17123 TransitionClosure *clos;
17124 ClutterAnimationInfo *info;
17126 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17127 g_return_if_fail (name != NULL);
17128 g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17130 info = _clutter_actor_get_animation_info (self);
17132 if (info->cur_state == NULL)
17134 g_warning ("No easing state is defined for the actor '%s'; you "
17135 "must call clutter_actor_save_easing_state() before "
17136 "calling clutter_actor_add_transition().",
17137 _clutter_actor_get_debug_name (self));
17141 if (info->transitions == NULL)
17142 info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17144 transition_closure_free);
17146 if (g_hash_table_lookup (info->transitions, name) != NULL)
17148 g_warning ("A transition with name '%s' already exists for "
17151 _clutter_actor_get_debug_name (self));
17155 timeline = CLUTTER_TIMELINE (transition);
17157 clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17158 clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17159 clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17161 clos = g_slice_new (TransitionClosure);
17162 clos->actor = self;
17163 clos->transition = transition;
17164 clos->name = g_strdup (name);
17165 clos->completed_id = g_signal_connect (timeline, "completed",
17166 G_CALLBACK (on_transition_completed),
17169 g_hash_table_insert (info->transitions, clos->name, clos);
17173 * clutter_actor_remove_transition:
17174 * @self: a #ClutterActor
17175 * @name: the name of the transition to remove
17177 * Removes the transition stored inside a #ClutterActor using @name
17183 clutter_actor_remove_transition (ClutterActor *self,
17186 const ClutterAnimationInfo *info;
17188 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17189 g_return_if_fail (name != NULL);
17191 info = _clutter_actor_get_animation_info_or_defaults (self);
17193 if (info->transitions == NULL)
17196 g_hash_table_remove (info->transitions, name);
17200 * clutter_actor_remove_all_transitions:
17201 * @self: a #ClutterActor
17203 * Removes all transitions associated to @self.
17208 clutter_actor_remove_all_transitions (ClutterActor *self)
17210 const ClutterAnimationInfo *info;
17212 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17214 info = _clutter_actor_get_animation_info_or_defaults (self);
17215 if (info->transitions == NULL)
17218 g_hash_table_remove_all (info->transitions);
17222 * clutter_actor_set_easing_duration:
17223 * @self: a #ClutterActor
17224 * @msecs: the duration of the easing, or %NULL
17226 * Sets the duration of the tweening for animatable properties
17227 * of @self for the current easing state.
17229 * Calling this function will implicitly call
17230 * clutter_actor_save_easing_state() if no previous call to
17231 * that function was made.
17236 clutter_actor_set_easing_duration (ClutterActor *self,
17239 ClutterAnimationInfo *info;
17241 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17243 info = _clutter_actor_get_animation_info (self);
17245 if (info->states == NULL)
17246 clutter_actor_save_easing_state (self);
17248 if (info->cur_state->easing_duration != msecs)
17249 info->cur_state->easing_duration = msecs;
17253 * clutter_actor_get_easing_duration:
17254 * @self: a #ClutterActor
17256 * Retrieves the duration of the tweening for animatable
17257 * properties of @self for the current easing state.
17259 * Return value: the duration of the tweening, in milliseconds
17264 clutter_actor_get_easing_duration (ClutterActor *self)
17266 const ClutterAnimationInfo *info;
17268 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17270 info = _clutter_actor_get_animation_info_or_defaults (self);
17272 if (info->cur_state != NULL)
17273 return info->cur_state->easing_duration;
17279 * clutter_actor_set_easing_mode:
17280 * @self: a #ClutterActor
17281 * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17283 * Sets the easing mode for the tweening of animatable properties
17286 * Calling this function will implicitly call
17287 * clutter_actor_save_easing_state() if no previous calls to
17288 * that function were made.
17293 clutter_actor_set_easing_mode (ClutterActor *self,
17294 ClutterAnimationMode mode)
17296 ClutterAnimationInfo *info;
17298 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17299 g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17300 g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17302 info = _clutter_actor_get_animation_info (self);
17304 if (info->states == NULL)
17305 clutter_actor_save_easing_state (self);
17307 if (info->cur_state->easing_mode != mode)
17308 info->cur_state->easing_mode = mode;
17312 * clutter_actor_get_easing_mode:
17313 * @self: a #ClutterActor
17315 * Retrieves the easing mode for the tweening of animatable properties
17316 * of @self for the current easing state.
17318 * Return value: an easing mode
17322 ClutterAnimationMode
17323 clutter_actor_get_easing_mode (ClutterActor *self)
17325 const ClutterAnimationInfo *info;
17327 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17329 info = _clutter_actor_get_animation_info_or_defaults (self);
17331 if (info->cur_state != NULL)
17332 return info->cur_state->easing_mode;
17334 return CLUTTER_EASE_OUT_CUBIC;
17338 * clutter_actor_set_easing_delay:
17339 * @self: a #ClutterActor
17340 * @msecs: the delay before the start of the tweening, in milliseconds
17342 * Sets the delay that should be applied before tweening animatable
17345 * Calling this function will implicitly call
17346 * clutter_actor_save_easing_state() if no previous calls to
17347 * that function were made.
17352 clutter_actor_set_easing_delay (ClutterActor *self,
17355 ClutterAnimationInfo *info;
17357 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17359 info = _clutter_actor_get_animation_info (self);
17361 if (info->states == NULL)
17362 clutter_actor_save_easing_state (self);
17364 if (info->cur_state->easing_delay != msecs)
17365 info->cur_state->easing_delay = msecs;
17369 * clutter_actor_get_easing_delay:
17370 * @self: a #ClutterActor
17372 * Retrieves the delay that should be applied when tweening animatable
17375 * Return value: a delay, in milliseconds
17380 clutter_actor_get_easing_delay (ClutterActor *self)
17382 const ClutterAnimationInfo *info;
17384 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17386 info = _clutter_actor_get_animation_info_or_defaults (self);
17388 if (info->cur_state != NULL)
17389 return info->cur_state->easing_delay;
17395 * clutter_actor_get_transition:
17396 * @self: a #ClutterActor
17397 * @name: the name of the transition
17399 * Retrieves the #ClutterTransition of a #ClutterActor by using the
17400 * transition @name.
17402 * Transitions created for animatable properties use the name of the
17403 * property itself, for instance the code below:
17406 * clutter_actor_set_easing_duration (actor, 1000);
17407 * clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17409 * transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17410 * g_signal_connect (transition, "completed",
17411 * G_CALLBACK (on_transition_complete),
17415 * will call the <function>on_transition_complete</function> callback when
17416 * the transition is complete.
17418 * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17419 * was found to match the passed name; the returned instance is owned
17420 * by Clutter and it should not be freed
17424 ClutterTransition *
17425 clutter_actor_get_transition (ClutterActor *self,
17428 TransitionClosure *clos;
17429 const ClutterAnimationInfo *info;
17431 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17432 g_return_val_if_fail (name != NULL, NULL);
17434 info = _clutter_actor_get_animation_info_or_defaults (self);
17436 if (info->transitions == NULL)
17439 clos = g_hash_table_lookup (info->transitions, name);
17443 return clos->transition;
17447 * clutter_actor_save_easing_state:
17448 * @self: a #ClutterActor
17450 * Saves the current easing state for animatable properties, and creates
17451 * a new state with the default values for easing mode and duration.
17456 clutter_actor_save_easing_state (ClutterActor *self)
17458 ClutterAnimationInfo *info;
17461 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17463 info = _clutter_actor_get_animation_info (self);
17465 if (info->states == NULL)
17466 info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17468 new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17469 new_state.easing_duration = 250;
17470 new_state.easing_delay = 0;
17472 g_array_append_val (info->states, new_state);
17474 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17478 * clutter_actor_restore_easing_state:
17479 * @self: a #ClutterActor
17481 * Restores the easing state as it was prior to a call to
17482 * clutter_actor_save_easing_state().
17487 clutter_actor_restore_easing_state (ClutterActor *self)
17489 ClutterAnimationInfo *info;
17491 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17493 info = _clutter_actor_get_animation_info (self);
17495 if (info->states == NULL)
17497 g_critical ("The function clutter_actor_restore_easing_state() has "
17498 "called without a previous call to "
17499 "clutter_actor_save_easing_state().");
17503 g_array_remove_index (info->states, info->states->len - 1);
17504 info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17508 * clutter_actor_set_content:
17509 * @self: a #ClutterActor
17510 * @content: (allow-none): a #ClutterContent, or %NULL
17512 * Sets the contents of a #ClutterActor.
17517 clutter_actor_set_content (ClutterActor *self,
17518 ClutterContent *content)
17520 ClutterActorPrivate *priv;
17522 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17523 g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17527 if (priv->content != NULL)
17529 _clutter_content_detached (priv->content, self);
17530 g_object_unref (priv->content);
17533 priv->content = content;
17535 if (priv->content != NULL)
17537 g_object_ref (priv->content);
17538 _clutter_content_attached (priv->content, self);
17541 /* given that the content is always painted within the allocation,
17542 * we only need to queue a redraw here
17544 clutter_actor_queue_redraw (self);
17546 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17548 /* if the content gravity is not resize-fill, and the new content has a
17549 * different preferred size than the previous one, then the content box
17550 * may have been changed. since we compute that lazily, we just notify
17551 * here, and let whomever watches :content-box do whatever they need to
17554 if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17555 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17559 * clutter_actor_get_content:
17560 * @self: a #ClutterActor
17562 * Retrieves the contents of @self.
17564 * Return value: (transfer none): a pointer to the #ClutterContent instance,
17565 * or %NULL if none was set
17570 clutter_actor_get_content (ClutterActor *self)
17572 g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17574 return self->priv->content;
17578 * clutter_actor_set_content_gravity:
17579 * @self: a #ClutterActor
17580 * @gravity: the #ClutterContentGravity
17582 * Sets the gravity of the #ClutterContent used by @self.
17584 * See the description of the #ClutterActor:content-gravity property for
17585 * more information.
17590 clutter_actor_set_content_gravity (ClutterActor *self,
17591 ClutterContentGravity gravity)
17593 ClutterActorPrivate *priv;
17595 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17599 if (priv->content_gravity == gravity)
17602 priv->content_gravity = gravity;
17604 clutter_actor_queue_redraw (self);
17606 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17607 g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17611 * clutter_actor_get_content_gravity:
17612 * @self: a #ClutterActor
17614 * Retrieves the content gravity as set using
17615 * clutter_actor_get_content_gravity().
17617 * Return value: the content gravity
17621 ClutterContentGravity
17622 clutter_actor_get_content_gravity (ClutterActor *self)
17624 g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17625 CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17627 return self->priv->content_gravity;
17631 * clutter_actor_get_content_box:
17632 * @self: a #ClutterActor
17633 * @box: (out caller-allocates): the return location for the bounding
17634 * box for the #ClutterContent
17636 * Retrieves the bounding box for the #ClutterContent of @self.
17638 * The bounding box is relative to the actor's allocation.
17640 * If no #ClutterContent is set for @self, or if @self has not been
17641 * allocated yet, then the result is undefined.
17643 * The content box is guaranteed to be, at most, as big as the allocation
17644 * of the #ClutterActor.
17646 * If the #ClutterContent used by the actor has a preferred size, then
17647 * it is possible to modify the content box by using the
17648 * #ClutterActor:content-gravity property.
17653 clutter_actor_get_content_box (ClutterActor *self,
17654 ClutterActorBox *box)
17656 ClutterActorPrivate *priv;
17657 gfloat content_w, content_h;
17658 gfloat alloc_w, alloc_h;
17660 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17661 g_return_if_fail (box != NULL);
17667 box->x2 = priv->allocation.x2 - priv->allocation.x1;
17668 box->y2 = priv->allocation.y2 - priv->allocation.y1;
17670 if (priv->content == NULL)
17673 /* no need to do any more work */
17674 if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17677 /* if the content does not have a preferred size then there is
17678 * no point in computing the content box
17680 if (!clutter_content_get_preferred_size (priv->content,
17688 switch (priv->content_gravity)
17690 case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17691 box->x2 = box->x1 + MIN (content_w, alloc_w);
17692 box->y2 = box->y1 + MIN (content_h, alloc_h);
17695 case CLUTTER_CONTENT_GRAVITY_TOP:
17696 if (alloc_w > content_w)
17698 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17699 box->x2 = box->x1 + content_w;
17701 box->y2 = box->y1 + MIN (content_h, alloc_h);
17704 case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17705 if (alloc_w > content_w)
17707 box->x1 += (alloc_w - content_w);
17708 box->x2 = box->x1 + content_w;
17710 box->y2 = box->y1 + MIN (content_h, alloc_h);
17713 case CLUTTER_CONTENT_GRAVITY_LEFT:
17714 box->x2 = box->x1 + MIN (content_w, alloc_w);
17715 if (alloc_h > content_h)
17717 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17718 box->y2 = box->y1 + content_h;
17722 case CLUTTER_CONTENT_GRAVITY_CENTER:
17723 if (alloc_w > content_w)
17725 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17726 box->x2 = box->x1 + content_w;
17728 if (alloc_h > content_h)
17730 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17731 box->y2 = box->y1 + content_h;
17735 case CLUTTER_CONTENT_GRAVITY_RIGHT:
17736 if (alloc_w > content_w)
17738 box->x1 += (alloc_w - content_w);
17739 box->x2 = box->x1 + content_w;
17741 if (alloc_h > content_h)
17743 box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17744 box->y2 = box->y1 + content_h;
17748 case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17749 box->x2 = box->x1 + MIN (content_w, alloc_w);
17750 if (alloc_h > content_h)
17752 box->y1 += (alloc_h - content_h);
17753 box->y2 = box->y1 + content_h;
17757 case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17758 if (alloc_w > content_w)
17760 box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17761 box->x2 = box->x1 + content_w;
17763 if (alloc_h > content_h)
17765 box->y1 += (alloc_h - content_h);
17766 box->y2 = box->y1 + content_h;
17770 case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17771 if (alloc_w > content_w)
17773 box->x1 += (alloc_w - content_w);
17774 box->x2 = box->x1 + content_w;
17776 if (alloc_h > content_h)
17778 box->y1 += (alloc_h - content_h);
17779 box->y2 = box->y1 + content_h;
17783 case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17784 g_assert_not_reached ();
17787 case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17789 double r_c = content_w / content_h;
17790 double r_a = alloc_w / alloc_h;
17799 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17800 box->y2 = box->y1 + (alloc_w * r_c);
17807 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17808 box->x2 = box->x1 + (alloc_h * r_c);
17818 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17819 box->x2 = box->x1 + (alloc_h * r_c);
17826 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17827 box->y2 = box->y1 + (alloc_w * r_c);
17836 * clutter_actor_set_content_scaling_filters:
17837 * @self: a #ClutterActor
17838 * @min_filter: the minification filter for the content
17839 * @mag_filter: the magnification filter for the content
17841 * Sets the minification and magnification filter to be applied when
17842 * scaling the #ClutterActor:content of a #ClutterActor.
17844 * The #ClutterActor:minification-filter will be used when reducing
17845 * the size of the content; the #ClutterActor:magnification-filter
17846 * will be used when increasing the size of the content.
17851 clutter_actor_set_content_scaling_filters (ClutterActor *self,
17852 ClutterScalingFilter min_filter,
17853 ClutterScalingFilter mag_filter)
17855 ClutterActorPrivate *priv;
17859 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17862 obj = G_OBJECT (self);
17864 g_object_freeze_notify (obj);
17868 if (priv->min_filter != min_filter)
17870 priv->min_filter = min_filter;
17873 g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
17876 if (priv->mag_filter != mag_filter)
17878 priv->mag_filter = mag_filter;
17881 g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
17885 clutter_actor_queue_redraw (self);
17887 g_object_thaw_notify (obj);
17891 * clutter_actor_get_content_scaling_filters:
17892 * @self: a #ClutterActor
17893 * @min_filter: (out) (allow-none): return location for the minification
17895 * @mag_filter: (out) (allow-none): return location for the magnification
17898 * Retrieves the values set using clutter_actor_set_content_scaling_filters().
17903 clutter_actor_get_content_scaling_filters (ClutterActor *self,
17904 ClutterScalingFilter *min_filter,
17905 ClutterScalingFilter *mag_filter)
17907 g_return_if_fail (CLUTTER_IS_ACTOR (self));
17909 if (min_filter != NULL)
17910 *min_filter = self->priv->min_filter;
17912 if (mag_filter != NULL)
17913 *mag_filter = self->priv->mag_filter;