b887bddbb1
* clutter/clutter-stage.c (clutter_stage_get_default): Don't grab the floating reference when creating the default stage. The stage manager will take a reference to it so it will behave as any other stage. (clutter_stage_new): Don't take the floating reference to the new stage but let the stage manager keep it instead. * clutter/clutter-stage-manager.c (_clutter_stage_manager_add_stage): Take a reference to the stage when it is added to the list. (_clutter_stage_manager_remove_stage): Unref the stage when it is removed from the list. (clutter_stage_manager_dispose): Keep track of the 'next' pointer as a separate variable so we can cope when the stage being destroyed removes itself from the list as the list is being iterated. * clutter/clutter-actor.c (clutter_actor_destroy): Take a reference at the beginning of the function even if there is no parent container so that overall the reference count is not changed when the actor is unref'd again at the bottom of the function. Previously it would have a net effect of leaving the reference count alone unless it is a top level actor in which case it would unref it.
5936 lines
155 KiB
C
5936 lines
155 KiB
C
/*
|
|
* Clutter.
|
|
*
|
|
* An OpenGL based 'interactive canvas' library.
|
|
*
|
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
|
*
|
|
* Copyright (C) 2006 OpenedHand
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:clutter-actor
|
|
* @short_description: Base abstract class for all visual stage actors.
|
|
*
|
|
* #ClutterActor is a base abstract class for all visual elements on the
|
|
* stage. Every object that must appear on the main #ClutterStage must also
|
|
* be a #ClutterActor, either by using one of the classes provided by
|
|
* Clutter, or by implementing a new #ClutterActor subclass.
|
|
*
|
|
* Every actor is a 2D surface in a 3D environment. The surface is contained
|
|
* inside its bounding box, described by the #ClutterActorBox structure:
|
|
*
|
|
* <figure id="actor-box">
|
|
* <title>Bounding box of an Actor</title>
|
|
* <graphic fileref="actor-box.png" format="PNG"/>
|
|
* </figure>
|
|
*
|
|
* The OpenGL modelview matrix for the actor is constructed from
|
|
* the actor settings by the following order of operations:
|
|
* <orderedlist>
|
|
* <listitem><para>Translation by actor x, y coords,</para></listitem>
|
|
* <listitem><para>Scaling by scale_x, scale_y,</para></listitem>
|
|
* <listitem><para>Negative translation by anchor point x,
|
|
* y,</para></listitem>
|
|
* <listitem><para>Rotation around z axis,</para></listitem>
|
|
* <listitem><para>Rotation around y axis,</para></listitem>
|
|
* <listitem><para>Rotation around x axis,</para></listitem>
|
|
* <listitem><para>Translation by actor depth (z),</para></listitem>
|
|
* <listitem><para>Clip stencil is applied (not an operation on the matrix
|
|
* as such, but done as part of the transform set up).</para></listitem>
|
|
* </orderedlist>
|
|
*
|
|
* <note>The position of any children is referenced from the top-left corner of
|
|
* the parent, not the parent's anchor point.</note>
|
|
*
|
|
* Events are handled in the following ways:
|
|
* <orderedlist>
|
|
* <listitem><para>Actors emit pointer events if set reactive, see
|
|
* clutter_actor_set_reactive()</para></listitem>
|
|
* <listitem><para>The stage is always reactive</para></listitem>
|
|
* <listitem><para>Events are handled by connecting signal handlers to
|
|
* the numerous event signal types.</para></listitem>
|
|
* <listitem><para>Event handlers must return %TRUE if they handled
|
|
* the event and wish to block the event emission chain, or %FALSE
|
|
* if the emission chain must continue</para></listitem>
|
|
* <listitem><para>Keyboard events are emitted if actor has focus, see
|
|
* clutter_stage_set_key_focus()</para></listitem>
|
|
* <listitem><para>Motion events (motion, enter, leave) are not emitted
|
|
* if clutter_set_motion_events_enabled() is called with %FALSE.
|
|
* See clutter_set_motion_events_enabled() documentation for more
|
|
* information.</para></listitem>
|
|
* <listitem><para>Once emitted, an event emission chain has two
|
|
* phases: capture and bubble. An emitted event starts in the capture
|
|
* phase (see ClutterActor::captured-event) beginning at the stage and
|
|
* traversing every child actor until the event source actor is reached.
|
|
* The emission then enters the bubble phase, traversing back up the
|
|
* chain via parents until it reaches the stage. Any event handler can
|
|
* abort this chain by returning %TRUE (meaning "event handled").
|
|
* </para></listitem>
|
|
* <listitem><para>Pointer events will 'pass through' non reactive
|
|
* overlapping actors.</para></listitem>
|
|
* </orderedlist>
|
|
*
|
|
* <figure id="event-flow">
|
|
* <title>Event flow in Clutter</title>
|
|
* <graphic fileref="event-flow.png" format="PNG"/>
|
|
* </figure>
|
|
*
|
|
* Every '?' box in the diagram above is an entry point for application
|
|
* code.
|
|
*
|
|
* For implementing a new actor class, please read <link
|
|
* linkend="clutter-subclassing-ClutterActor">the corresponding section</link>
|
|
* of the API reference.
|
|
*/
|
|
|
|
/**
|
|
* CLUTTER_ACTOR_IS_MAPPED:
|
|
* @e: a #ClutterActor
|
|
*
|
|
* Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
|
|
/**
|
|
* CLUTTER_ACTOR_IS_REALIZED:
|
|
* @e: a #ClutterActor
|
|
*
|
|
* Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
|
|
/**
|
|
* CLUTTER_ACTOR_IS_VISIBLE:
|
|
* @e: a #ClutterActor
|
|
*
|
|
* Evaluates to %TRUE if the actor is both realized and mapped.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
|
|
/**
|
|
* CLUTTER_ACTOR_IS_REACTIVE:
|
|
* @e: a #ClutterActor
|
|
*
|
|
* Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "clutter-actor.h"
|
|
#include "clutter-container.h"
|
|
#include "clutter-main.h"
|
|
#include "clutter-enum-types.h"
|
|
#include "clutter-scriptable.h"
|
|
#include "clutter-script.h"
|
|
#include "clutter-marshal.h"
|
|
#include "clutter-private.h"
|
|
#include "clutter-debug.h"
|
|
#include "clutter-units.h"
|
|
#include "cogl/cogl.h"
|
|
|
|
typedef struct _ShaderData ShaderData;
|
|
|
|
#define CLUTTER_ACTOR_GET_PRIVATE(obj) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
|
|
|
|
struct _ClutterActorPrivate
|
|
{
|
|
ClutterActorBox coords;
|
|
|
|
ClutterUnit clip[4];
|
|
guint has_clip : 1;
|
|
|
|
/* Rotation angles */
|
|
ClutterFixed rxang;
|
|
ClutterFixed ryang;
|
|
ClutterFixed rzang;
|
|
|
|
/* Rotation center: X axis */
|
|
ClutterUnit rxy;
|
|
ClutterUnit rxz;
|
|
|
|
/* Rotation center: Y axis */
|
|
ClutterUnit ryx;
|
|
ClutterUnit ryz;
|
|
|
|
/* Rotation center: Z axis */
|
|
ClutterUnit rzx;
|
|
ClutterUnit rzy;
|
|
|
|
/* Anchor point coordinates */
|
|
ClutterUnit anchor_x;
|
|
ClutterUnit anchor_y;
|
|
|
|
/* depth */
|
|
ClutterUnit z;
|
|
|
|
guint8 opacity;
|
|
|
|
ClutterActor *parent_actor;
|
|
|
|
gchar *name;
|
|
guint32 id; /* Unique ID */
|
|
|
|
ClutterFixed scale_x;
|
|
ClutterFixed scale_y;
|
|
|
|
ShaderData *shader_data;
|
|
|
|
gboolean show_on_set_parent;
|
|
};
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
|
|
PROP_NAME,
|
|
|
|
PROP_X,
|
|
PROP_Y,
|
|
PROP_WIDTH,
|
|
PROP_HEIGHT,
|
|
PROP_DEPTH,
|
|
|
|
PROP_CLIP,
|
|
PROP_HAS_CLIP,
|
|
|
|
PROP_OPACITY,
|
|
PROP_VISIBLE,
|
|
PROP_REACTIVE,
|
|
|
|
PROP_SCALE_X,
|
|
PROP_SCALE_Y,
|
|
|
|
PROP_ROTATION_ANGLE_X,
|
|
PROP_ROTATION_ANGLE_Y,
|
|
PROP_ROTATION_ANGLE_Z,
|
|
PROP_ROTATION_CENTER_X,
|
|
PROP_ROTATION_CENTER_Y,
|
|
PROP_ROTATION_CENTER_Z,
|
|
|
|
PROP_ANCHOR_X,
|
|
PROP_ANCHOR_Y,
|
|
|
|
PROP_SHOW_ON_SET_PARENT
|
|
};
|
|
|
|
enum
|
|
{
|
|
SHOW,
|
|
HIDE,
|
|
DESTROY,
|
|
PARENT_SET,
|
|
FOCUS_IN,
|
|
FOCUS_OUT,
|
|
|
|
EVENT,
|
|
CAPTURED_EVENT,
|
|
BUTTON_PRESS_EVENT,
|
|
BUTTON_RELEASE_EVENT,
|
|
SCROLL_EVENT,
|
|
KEY_PRESS_EVENT,
|
|
KEY_RELEASE_EVENT,
|
|
MOTION_EVENT,
|
|
ENTER_EVENT,
|
|
LEAVE_EVENT,
|
|
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static guint actor_signals[LAST_SIGNAL] = { 0, };
|
|
|
|
static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
|
|
|
|
static void _clutter_actor_apply_modelview_transform (ClutterActor *self);
|
|
static void _clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
|
|
ClutterActor *ancestor);
|
|
|
|
static void clutter_actor_shader_pre_paint (ClutterActor *actor,
|
|
gboolean repeat);
|
|
static void clutter_actor_shader_post_paint (ClutterActor *actor);
|
|
|
|
static void destroy_shader_data (ClutterActor *self);
|
|
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ClutterActor,
|
|
clutter_actor,
|
|
G_TYPE_INITIALLY_UNOWNED,
|
|
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
|
|
clutter_scriptable_iface_init));
|
|
|
|
|
|
static void
|
|
clutter_actor_real_show (ClutterActor *self)
|
|
{
|
|
if (!CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
{
|
|
if (!CLUTTER_ACTOR_IS_REALIZED (self))
|
|
clutter_actor_realize (self);
|
|
|
|
/* the mapped flag on the top-level actors is set by the
|
|
* per-backend implementation because it might be asynchronous
|
|
*/
|
|
if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL))
|
|
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
clutter_actor_queue_redraw (self);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_show:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Flags an actor to be displayed. An actor that isn't shown will not
|
|
* be rendered on the stage.
|
|
*
|
|
* Actors are visible by default.
|
|
*
|
|
* If this function is called on an actor without a parent, the
|
|
* ClutterActor:show-on-set-parent will be set to %TRUE as a side effect.
|
|
*/
|
|
void
|
|
clutter_actor_show (ClutterActor *self)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
if (!priv->show_on_set_parent && !priv->parent_actor)
|
|
{
|
|
priv->show_on_set_parent = TRUE;
|
|
g_object_notify (G_OBJECT (self), "show-on-set-parent");
|
|
}
|
|
|
|
if (!CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
{
|
|
g_signal_emit (self, actor_signals[SHOW], 0);
|
|
g_object_notify (G_OBJECT (self), "visible");
|
|
}
|
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_show_all:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* Call show() on all children of an actor (if any).
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
void
|
|
clutter_actor_show_all (ClutterActor *self)
|
|
{
|
|
ClutterActorClass *klass;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
klass = CLUTTER_ACTOR_GET_CLASS (self);
|
|
if (klass->show_all)
|
|
klass->show_all (self);
|
|
}
|
|
|
|
void
|
|
clutter_actor_real_hide (ClutterActor *self)
|
|
{
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
{
|
|
/* see comment in clutter_actor_real_show() on why we don't set
|
|
* the mapped flag on the top-level actors
|
|
*/
|
|
if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL))
|
|
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
|
|
|
|
clutter_actor_queue_redraw (self);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_hide:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Flags an actor to be hidden. A hidden actor will not be
|
|
* rendered on the stage.
|
|
*
|
|
* Actors are visible by default.
|
|
*
|
|
* If this function is called on an actor without a parent, the
|
|
* ClutterActor:show-on-set-parent property will be set to %FALSE
|
|
* as a side-effect.
|
|
*/
|
|
void
|
|
clutter_actor_hide (ClutterActor *self)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
if (priv->show_on_set_parent && !priv->parent_actor)
|
|
{
|
|
priv->show_on_set_parent = FALSE;
|
|
g_object_notify (G_OBJECT (self), "show-on-set-parent");
|
|
}
|
|
|
|
if (CLUTTER_ACTOR_IS_MAPPED (self))
|
|
{
|
|
g_signal_emit (self, actor_signals[HIDE], 0);
|
|
g_object_notify (G_OBJECT (self), "visible");
|
|
}
|
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_hide_all:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* Call hide() on all child actors (if any).
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
void
|
|
clutter_actor_hide_all (ClutterActor *self)
|
|
{
|
|
ClutterActorClass *klass;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
klass = CLUTTER_ACTOR_GET_CLASS (self);
|
|
if (klass->hide_all)
|
|
klass->hide_all (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_realize:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Creates any underlying graphics resources needed by the actor to be
|
|
* displayed.
|
|
**/
|
|
void
|
|
clutter_actor_realize (ClutterActor *self)
|
|
{
|
|
ClutterActorClass *klass;
|
|
|
|
if (CLUTTER_ACTOR_IS_REALIZED (self))
|
|
return;
|
|
|
|
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
|
|
|
|
klass = CLUTTER_ACTOR_GET_CLASS (self);
|
|
|
|
if (klass->realize)
|
|
(klass->realize) (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_unrealize:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Frees up any underlying graphics resources needed by the actor to be
|
|
* displayed.
|
|
**/
|
|
void
|
|
clutter_actor_unrealize (ClutterActor *self)
|
|
{
|
|
ClutterActorClass *klass;
|
|
ClutterActorPrivate *priv;
|
|
|
|
priv = self->priv;
|
|
|
|
if (!CLUTTER_ACTOR_IS_REALIZED (self))
|
|
return;
|
|
|
|
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
|
|
|
|
klass = CLUTTER_ACTOR_GET_CLASS (self);
|
|
|
|
if (klass->unrealize)
|
|
(klass->unrealize) (self);
|
|
}
|
|
|
|
static void
|
|
clutter_actor_real_pick (ClutterActor *self,
|
|
const ClutterColor *color)
|
|
{
|
|
if (clutter_actor_should_pick_paint (self))
|
|
{
|
|
cogl_color (color);
|
|
cogl_rectangle (0, 0,
|
|
clutter_actor_get_width(self),
|
|
clutter_actor_get_height(self));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_pick:
|
|
* @self: A #ClutterActor
|
|
* @color: A #ClutterColor
|
|
*
|
|
* Renders a silhouette of the actor using the supplied color. Used
|
|
* internally for mapping pointer events to actors.
|
|
*
|
|
* This function should never be called directly by applications.
|
|
*
|
|
* Subclasses overiding the ClutterActor::pick() method should call
|
|
* clutter_actor_should_pick_paint() to decide whether to render their
|
|
* silhouette. Containers should always recursively call pick for
|
|
* each child.
|
|
*
|
|
* Since 0.4
|
|
**/
|
|
void
|
|
clutter_actor_pick (ClutterActor *self,
|
|
const ClutterColor *color)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
g_return_if_fail (color != NULL);
|
|
|
|
CLUTTER_ACTOR_GET_CLASS (self)->pick(self, color);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_should_pick_paint:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Utility call for subclasses overiding the pick method.
|
|
*
|
|
* This function should never be called directly by applications.
|
|
*
|
|
* Return value: %TRUE if the actor should paint its silhouette,
|
|
* %FALSE otherwise
|
|
*/
|
|
gboolean
|
|
clutter_actor_should_pick_paint (ClutterActor *self)
|
|
{
|
|
ClutterMainContext *context;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
|
|
|
context = clutter_context_get_default ();
|
|
|
|
if (CLUTTER_ACTOR_IS_MAPPED (self) &&
|
|
(G_UNLIKELY (context->pick_mode == CLUTTER_PICK_ALL) ||
|
|
CLUTTER_ACTOR_IS_REACTIVE (self)))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Utility functions for manipulating transformation matrix
|
|
*
|
|
* Matrix: 4x4 of ClutterFixed
|
|
*/
|
|
#define M(m,row,col) (m)[(col) * 4 + (row)]
|
|
|
|
/* Transform point (x,y,z) by matrix */
|
|
static void
|
|
mtx_transform (ClutterFixed m[16],
|
|
ClutterFixed *x, ClutterFixed *y, ClutterFixed *z,
|
|
ClutterFixed *w)
|
|
{
|
|
ClutterFixed _x, _y, _z, _w;
|
|
_x = *x;
|
|
_y = *y;
|
|
_z = *z;
|
|
_w = *w;
|
|
|
|
/* We care lot about precission here, so have to use QMUL */
|
|
*x = CFX_QMUL (M (m,0,0), _x) + CFX_QMUL (M (m,0,1), _y) +
|
|
CFX_QMUL (M (m,0,2), _z) + CFX_QMUL (M (m,0,3), _w);
|
|
|
|
*y = CFX_QMUL (M (m,1,0), _x) + CFX_QMUL (M (m,1,1), _y) +
|
|
CFX_QMUL (M (m,1,2), _z) + CFX_QMUL (M (m,1,3), _w);
|
|
|
|
*z = CFX_QMUL (M (m,2,0), _x) + CFX_QMUL (M (m,2,1), _y) +
|
|
CFX_QMUL (M (m,2,2), _z) + CFX_QMUL (M (m,2,3), _w);
|
|
|
|
*w = CFX_QMUL (M (m,3,0), _x) + CFX_QMUL (M (m,3,1), _y) +
|
|
CFX_QMUL (M (m,3,2), _z) + CFX_QMUL (M (m,3,3), _w);
|
|
|
|
/* Specially for Matthew: was going to put a comment here, but could not
|
|
* think of anything at all to say ;)
|
|
*/
|
|
}
|
|
|
|
#undef M
|
|
|
|
/* Applies the transforms associated with this actor and its ancestors,
|
|
* retrieves the resulting OpenGL modelview matrix, and uses the matrix
|
|
* to transform the supplied point
|
|
*/
|
|
static void
|
|
clutter_actor_transform_point_relative (ClutterActor *actor,
|
|
ClutterActor *ancestor,
|
|
ClutterUnit *x,
|
|
ClutterUnit *y,
|
|
ClutterUnit *z,
|
|
ClutterUnit *w)
|
|
{
|
|
ClutterFixed mtx[16];
|
|
ClutterActorPrivate *priv;
|
|
|
|
priv = actor->priv;
|
|
|
|
cogl_push_matrix();
|
|
_clutter_actor_apply_modelview_transform_recursive (actor, ancestor);
|
|
|
|
cogl_get_modelview_matrix (mtx);
|
|
|
|
mtx_transform (mtx, x, y, z, w);
|
|
|
|
cogl_pop_matrix();
|
|
}
|
|
|
|
/* Applies the transforms associated with this actor and its ancestors,
|
|
* retrieves the resulting OpenGL modelview matrix, and uses the matrix
|
|
* to transform the supplied point
|
|
*/
|
|
static void
|
|
clutter_actor_transform_point (ClutterActor *actor,
|
|
ClutterUnit *x,
|
|
ClutterUnit *y,
|
|
ClutterUnit *z,
|
|
ClutterUnit *w)
|
|
{
|
|
ClutterFixed mtx[16];
|
|
ClutterActorPrivate *priv;
|
|
|
|
priv = actor->priv;
|
|
|
|
cogl_push_matrix();
|
|
_clutter_actor_apply_modelview_transform_recursive (actor, NULL);
|
|
|
|
cogl_get_modelview_matrix (mtx);
|
|
|
|
mtx_transform (mtx, x, y, z, w);
|
|
|
|
cogl_pop_matrix();
|
|
}
|
|
|
|
/* Help macros to scale from OpenGL <-1,1> coordinates system to our
|
|
* X-window based <0,window-size> coordinates
|
|
*/
|
|
#define MTX_GL_SCALE_X(x,w,v1,v2) (CFX_MUL (((CFX_DIV ((x), (w)) + CFX_ONE) >> 1), (v1)) + (v2))
|
|
#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - CFX_MUL (((CFX_DIV ((y), (w)) + CFX_ONE) >> 1), (v1)) + (v2))
|
|
#define MTX_GL_SCALE_Z(z,w,v1,v2) (MTX_GL_SCALE_X ((z), (w), (v1), (v2)))
|
|
|
|
/**
|
|
* clutter_actor_apply_relative_transform_to_point:
|
|
* @self: A #ClutterActor
|
|
* @ancestor: A #ClutterActor ancestor, or %NULL to use the
|
|
* default #ClutterStage
|
|
* @point: A point as #ClutterVertex
|
|
* @vertex: The translated #ClutterVertex
|
|
*
|
|
* Transforms @point in coordinates relative to the actor into
|
|
* ancestor-relative coordinates using the relevant transform
|
|
* stack (i.e. scale, rotation, etc).
|
|
*
|
|
* If @ancestor is %NULL the ancestor will be the #ClutterStage. In
|
|
* this case, the coordinates returned will be the coordinates on
|
|
* the stage before the projection is applied. This is different from
|
|
* the behaviour of clutter_actor_apply_transform_to_point().
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
|
|
ClutterActor *ancestor,
|
|
ClutterVertex *point,
|
|
ClutterVertex *vertex)
|
|
{
|
|
ClutterFixed v[4];
|
|
ClutterFixed w = CFX_ONE;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
|
|
|
|
/* First we tranform the point using the OpenGL modelview matrix */
|
|
clutter_actor_transform_point_relative (self, ancestor,
|
|
&point->x, &point->y, &point->z,
|
|
&w);
|
|
|
|
cogl_get_viewport (v);
|
|
|
|
/*
|
|
* The w[3] parameter should always be 1.0 here, so we ignore it; otherwise
|
|
* we would have to divide the original verts with it.
|
|
*/
|
|
vertex->x = CFX_MUL ((point->x + CFX_ONE/2), v[2]);
|
|
vertex->y = CFX_MUL ((CFX_ONE/2 - point->y), v[3]);
|
|
vertex->z = CFX_MUL ((point->z + CFX_ONE/2), v[2]);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_apply_transform_to_point:
|
|
* @self: A #ClutterActor
|
|
* @point: A point as #ClutterVertex
|
|
* @vertex: The translated #ClutterVertex
|
|
*
|
|
* Transforms @point in coordinates relative to the actor
|
|
* into screen-relative coordinates with the current actor
|
|
* transformation (i.e. scale, rotation, etc)
|
|
*
|
|
* Since: 0.4
|
|
**/
|
|
void
|
|
clutter_actor_apply_transform_to_point (ClutterActor *self,
|
|
ClutterVertex *point,
|
|
ClutterVertex *vertex)
|
|
{
|
|
ClutterFixed mtx_p[16];
|
|
ClutterFixed v[4];
|
|
ClutterFixed w = CFX_ONE;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
/* First we tranform the point using the OpenGL modelview matrix */
|
|
clutter_actor_transform_point (self, &point->x, &point->y, &point->z, &w);
|
|
|
|
cogl_get_projection_matrix (mtx_p);
|
|
cogl_get_viewport (v);
|
|
|
|
/* Now, transform it again with the projection matrix */
|
|
mtx_transform (mtx_p, &point->x, &point->y, &point->z, &w);
|
|
|
|
/* Finaly translate from OpenGL coords to window coords */
|
|
vertex->x = MTX_GL_SCALE_X (point->x, w, v[2], v[0]);
|
|
vertex->y = MTX_GL_SCALE_Y (point->y, w, v[3], v[1]);
|
|
vertex->z = MTX_GL_SCALE_Z (point->z, w, v[2], v[0]);
|
|
}
|
|
|
|
/* Recursively tranform supplied vertices with the tranform for the current
|
|
* actor and up to the ancestor (like clutter_actor_transform_point() but
|
|
* for all the vertices in one go).
|
|
*/
|
|
static void
|
|
clutter_actor_transform_vertices_relative (ClutterActor *self,
|
|
ClutterActor *ancestor,
|
|
ClutterVertex verts[4],
|
|
ClutterFixed w[4])
|
|
{
|
|
ClutterFixed mtx[16];
|
|
ClutterFixed _x, _y, _z, _w;
|
|
ClutterActorBox coords;
|
|
|
|
/*
|
|
* Need to query coords here, so that we get coorect values for actors that
|
|
* do not modify priv->coords.
|
|
*/
|
|
clutter_actor_query_coords (self, &coords);
|
|
|
|
cogl_push_matrix();
|
|
_clutter_actor_apply_modelview_transform_recursive (self, ancestor);
|
|
|
|
cogl_get_modelview_matrix (mtx);
|
|
|
|
_x = 0;
|
|
_y = 0;
|
|
_z = 0;
|
|
_w = CFX_ONE;
|
|
|
|
mtx_transform (mtx, &_x, &_y, &_z, &_w);
|
|
|
|
verts[0].x = _x;
|
|
verts[0].y = _y;
|
|
verts[0].z = _z;
|
|
w[0] = _w;
|
|
|
|
_x = coords.x2 - coords.x1;
|
|
_y = 0;
|
|
_z = 0;
|
|
_w = CFX_ONE;
|
|
|
|
mtx_transform (mtx, &_x, &_y, &_z, &_w);
|
|
|
|
verts[1].x = _x;
|
|
verts[1].y = _y;
|
|
verts[1].z = _z;
|
|
w[1] = _w;
|
|
|
|
_x = 0;
|
|
_y = coords.y2 - coords.y1;
|
|
_z = 0;
|
|
_w = CFX_ONE;
|
|
|
|
mtx_transform (mtx, &_x, &_y, &_z, &_w);
|
|
|
|
verts[2].x = _x;
|
|
verts[2].y = _y;
|
|
verts[2].z = _z;
|
|
w[2] = _w;
|
|
|
|
_x = coords.x2 - coords.x1;
|
|
_y = coords.y2 - coords.y1;
|
|
_z = 0;
|
|
_w = CFX_ONE;
|
|
|
|
mtx_transform (mtx, &_x, &_y, &_z, &_w);
|
|
|
|
verts[3].x = _x;
|
|
verts[3].y = _y;
|
|
verts[3].z = _z;
|
|
w[3] = _w;
|
|
|
|
cogl_pop_matrix();
|
|
}
|
|
|
|
/* Recursively tranform supplied vertices with the tranform for the current
|
|
* actor and all its ancestors (like clutter_actor_transform_point() but
|
|
* for all the vertices in one go).
|
|
*/
|
|
static void
|
|
clutter_actor_transform_vertices (ClutterActor *self,
|
|
ClutterVertex verts[4],
|
|
ClutterFixed w[4])
|
|
{
|
|
ClutterFixed mtx[16];
|
|
ClutterFixed _x, _y, _z, _w;
|
|
ClutterActorBox coords;
|
|
|
|
/*
|
|
* Need to query coords here, so that we get coorect values for actors that
|
|
* do not modify priv->coords.
|
|
*/
|
|
clutter_actor_query_coords (self, &coords);
|
|
|
|
cogl_push_matrix();
|
|
_clutter_actor_apply_modelview_transform_recursive (self, NULL);
|
|
|
|
cogl_get_modelview_matrix (mtx);
|
|
|
|
_x = 0;
|
|
_y = 0;
|
|
_z = 0;
|
|
_w = CFX_ONE;
|
|
|
|
mtx_transform (mtx, &_x, &_y, &_z, &_w);
|
|
|
|
verts[0].x = _x;
|
|
verts[0].y = _y;
|
|
verts[0].z = _z;
|
|
w[0] = _w;
|
|
|
|
_x = coords.x2 - coords.x1;
|
|
_y = 0;
|
|
_z = 0;
|
|
_w = CFX_ONE;
|
|
|
|
mtx_transform (mtx, &_x, &_y, &_z, &_w);
|
|
|
|
verts[1].x = _x;
|
|
verts[1].y = _y;
|
|
verts[1].z = _z;
|
|
w[1] = _w;
|
|
|
|
_x = 0;
|
|
_y = coords.y2 - coords.y1;
|
|
_z = 0;
|
|
_w = CFX_ONE;
|
|
|
|
mtx_transform (mtx, &_x, &_y, &_z, &_w);
|
|
|
|
verts[2].x = _x;
|
|
verts[2].y = _y;
|
|
verts[2].z = _z;
|
|
w[2] = _w;
|
|
|
|
_x = coords.x2 - coords.x1;
|
|
_y = coords.y2 - coords.y1;
|
|
_z = 0;
|
|
_w = CFX_ONE;
|
|
|
|
mtx_transform (mtx, &_x, &_y, &_z, &_w);
|
|
|
|
verts[3].x = _x;
|
|
verts[3].y = _y;
|
|
verts[3].z = _z;
|
|
w[3] = _w;
|
|
|
|
cogl_pop_matrix();
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_relative_vertices:
|
|
* @self: A #ClutterActor
|
|
* @ancestor: A #ClutterActor to calculate the vertices against, or %NULL
|
|
* to use the default #ClutterStage
|
|
* @verts: return location for an array of 4 #ClutterVertex in which
|
|
* to store the result.
|
|
*
|
|
* Calculates the transformed coordinates of the four corners of the
|
|
* actor in the plane of @ancestor. The returned vertices relate to
|
|
* the #ClutterActorBox coordinates as follows:
|
|
* <itemizedlist>
|
|
* <listitem><para>v[0] contains (x1, y1)</para></listitem>
|
|
* <listitem><para>v[1] contains (x2, y1)</para></listitem>
|
|
* <listitem><para>v[2] contains (x1, y2)</para></listitem>
|
|
* <listitem><para>v[3] contains (x2, y2)</para></listitem>
|
|
* </itemizedlist>
|
|
*
|
|
* If @ancestor is %NULL the ancestor will be the #ClutterStage. In
|
|
* this case, the coordinates returned will be the coordinates on
|
|
* the stage before the projection is applied. This is different from
|
|
* the behaviour of clutter_actor_get_vertices().
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_get_relative_vertices (ClutterActor *self,
|
|
ClutterActor *ancestor,
|
|
ClutterVertex verts[4])
|
|
{
|
|
ClutterFixed v[4];
|
|
ClutterFixed w[4];
|
|
ClutterActorPrivate *priv;
|
|
ClutterActor *stage;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
|
|
|
|
priv = self->priv;
|
|
|
|
/* We essentially have to dupe some code from clutter_redraw() here
|
|
* to make sure GL Matrices etc are initialised if we're called and we
|
|
* havn't yet rendered anything.
|
|
*
|
|
* Simply duping code for now in wait for Cogl cleanup that can hopefully
|
|
* address this in a nicer way.
|
|
*/
|
|
stage = clutter_actor_get_stage (self);
|
|
|
|
/* FIXME: if were not yet added to a stage, its probably unsafe to
|
|
* return default - idealy the func should fail.
|
|
*/
|
|
if (stage == NULL)
|
|
stage = clutter_stage_get_default ();
|
|
|
|
clutter_stage_ensure_current (CLUTTER_STAGE(stage));
|
|
|
|
if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
|
|
{
|
|
ClutterPerspective perspective;
|
|
|
|
clutter_stage_get_perspectivex (CLUTTER_STAGE (stage), &perspective);
|
|
|
|
cogl_setup_viewport (clutter_actor_get_width (stage),
|
|
clutter_actor_get_height (stage),
|
|
perspective.fovy,
|
|
perspective.aspect,
|
|
perspective.z_near,
|
|
perspective.z_far);
|
|
|
|
CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
|
|
}
|
|
|
|
clutter_actor_transform_vertices_relative (self, ancestor, verts, w);
|
|
cogl_get_viewport (v);
|
|
|
|
/*
|
|
* The w[3] parameter should always be 1.0 here, so we ignore it; otherwise
|
|
* we would have to devide the original verts with it.
|
|
*/
|
|
verts[0].x = CFX_MUL ((verts[0].x + CFX_ONE/2), v[2]);
|
|
verts[0].y = CFX_MUL ((CFX_ONE/2 - verts[0].y), v[3]);
|
|
verts[0].z = CFX_MUL ((verts[0].z + CFX_ONE/2), v[2]);
|
|
|
|
verts[1].x = CFX_MUL ((verts[1].x + CFX_ONE/2), v[2]);
|
|
verts[1].y = CFX_MUL ((CFX_ONE/2 - verts[1].y), v[3]);
|
|
verts[1].z = CFX_MUL ((verts[1].z + CFX_ONE/2), v[2]);
|
|
|
|
verts[2].x = CFX_MUL ((verts[2].x + CFX_ONE/2), v[2]);
|
|
verts[2].y = CFX_MUL ((CFX_ONE/2 - verts[2].y), v[3]);
|
|
verts[2].z = CFX_MUL ((verts[2].z + CFX_ONE/2), v[2]);
|
|
|
|
verts[3].x = CFX_MUL ((verts[3].x + CFX_ONE/2), v[2]);
|
|
verts[3].y = CFX_MUL ((CFX_ONE/2 - verts[3].y), v[3]);
|
|
verts[3].z = CFX_MUL ((verts[3].z + CFX_ONE/2), v[2]);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_vertices:
|
|
* @self: A #ClutterActor
|
|
* @verts: Pointer to a location of an array of 4 #ClutterVertex where to
|
|
* store the result.
|
|
*
|
|
* Calculates the transformed screen coordinates of the four corners of
|
|
* the actor; the returned vertices relate to the #ClutterActorBox
|
|
* coordinates as follows:
|
|
* <itemizedlist>
|
|
* <listitem><para>v[0] contains (x1, y1)</para></listitem>
|
|
* <listitem><para>v[1] contains (x2, y1)</para></listitem>
|
|
* <listitem><para>v[2] contains (x1, y2)</para></listitem>
|
|
* <listitem><para>v[3] contains (x2, y2)</para></listitem>
|
|
* </itemizedlist>
|
|
*
|
|
* Since: 0.4
|
|
*/
|
|
void
|
|
clutter_actor_get_vertices (ClutterActor *self,
|
|
ClutterVertex verts[4])
|
|
{
|
|
ClutterFixed mtx_p[16];
|
|
ClutterFixed v[4];
|
|
ClutterFixed w[4];
|
|
ClutterActorPrivate *priv;
|
|
ClutterActor *stage;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
/* We essentially have to dupe some code from clutter_redraw() here
|
|
* to make sure GL Matrices etc are initialised if we're called and we
|
|
* havn't yet rendered anything.
|
|
*
|
|
* Simply duping code for now in wait for Cogl cleanup that can hopefully
|
|
* address this in a nicer way.
|
|
*/
|
|
stage = clutter_actor_get_stage (self);
|
|
|
|
/* FIXME: if were not yet added to a stage, its probably unsafe to
|
|
* return default - idealy the func should fail.
|
|
*/
|
|
if (stage == NULL)
|
|
stage = clutter_stage_get_default ();
|
|
|
|
clutter_stage_ensure_current (CLUTTER_STAGE(stage));
|
|
|
|
if (CLUTTER_PRIVATE_FLAGS (stage) & CLUTTER_ACTOR_SYNC_MATRICES)
|
|
{
|
|
ClutterPerspective perspective;
|
|
|
|
clutter_stage_get_perspectivex (CLUTTER_STAGE (stage), &perspective);
|
|
|
|
cogl_setup_viewport (clutter_actor_get_width (stage),
|
|
clutter_actor_get_height (stage),
|
|
perspective.fovy,
|
|
perspective.aspect,
|
|
perspective.z_near,
|
|
perspective.z_far);
|
|
|
|
CLUTTER_UNSET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
|
|
}
|
|
|
|
clutter_actor_transform_vertices (self, verts, w);
|
|
cogl_get_projection_matrix (mtx_p);
|
|
cogl_get_viewport (v);
|
|
|
|
mtx_transform (mtx_p,
|
|
&verts[0].x,
|
|
&verts[0].y,
|
|
&verts[0].z,
|
|
&w[0]);
|
|
|
|
verts[0].x = MTX_GL_SCALE_X (verts[0].x, w[0], v[2], v[0]);
|
|
verts[0].y = MTX_GL_SCALE_Y (verts[0].y, w[0], v[3], v[1]);
|
|
verts[0].z = MTX_GL_SCALE_Z (verts[0].z, w[0], v[2], v[0]);
|
|
|
|
mtx_transform (mtx_p,
|
|
&verts[1].x,
|
|
&verts[1].y,
|
|
&verts[1].z,
|
|
&w[1]);
|
|
|
|
verts[1].x = MTX_GL_SCALE_X (verts[1].x, w[1], v[2], v[0]);
|
|
verts[1].y = MTX_GL_SCALE_Y (verts[1].y, w[1], v[3], v[1]);
|
|
verts[1].z = MTX_GL_SCALE_Z (verts[1].z, w[1], v[2], v[0]);
|
|
|
|
mtx_transform (mtx_p,
|
|
&verts[2].x,
|
|
&verts[2].y,
|
|
&verts[2].z,
|
|
&w[2]);
|
|
|
|
verts[2].x = MTX_GL_SCALE_X (verts[2].x, w[2], v[2], v[0]);
|
|
verts[2].y = MTX_GL_SCALE_Y (verts[2].y, w[2], v[3], v[1]);
|
|
verts[2].z = MTX_GL_SCALE_Z (verts[2].z, w[2], v[2], v[0]);
|
|
|
|
mtx_transform (mtx_p,
|
|
&verts[3].x,
|
|
&verts[3].y,
|
|
&verts[3].z,
|
|
&w[3]);
|
|
|
|
verts[3].x = MTX_GL_SCALE_X (verts[3].x, w[3], v[2], v[0]);
|
|
verts[3].y = MTX_GL_SCALE_Y (verts[3].y, w[3], v[3], v[1]);
|
|
verts[3].z = MTX_GL_SCALE_Z (verts[3].z, w[3], v[2], v[0]);
|
|
}
|
|
|
|
/* Applies the transforms associated with this actor to the
|
|
* OpenGL modelview matrix.
|
|
*
|
|
* This function does not push/pop matrix; it is the responsibility
|
|
* of the caller to do so as appropriate
|
|
*/
|
|
static void
|
|
_clutter_actor_apply_modelview_transform (ClutterActor * self)
|
|
{
|
|
ClutterActorPrivate *priv = self->priv;
|
|
gboolean is_stage = CLUTTER_IS_STAGE (self);
|
|
|
|
if (!is_stage)
|
|
{
|
|
cogl_translatex (CLUTTER_UNITS_TO_FIXED (priv->coords.x1),
|
|
CLUTTER_UNITS_TO_FIXED (priv->coords.y1),
|
|
0);
|
|
}
|
|
|
|
/*
|
|
* because the rotation involves translations, we must scale before
|
|
* applying the rotations (if we apply the scale after the rotations,
|
|
* the translations included in the rotation are not scaled and so the
|
|
* entire object will move on the screen as a result of rotating it).
|
|
*/
|
|
if (priv->scale_x != CFX_ONE ||
|
|
priv->scale_y != CFX_ONE)
|
|
{
|
|
cogl_scale (priv->scale_x, priv->scale_y);
|
|
}
|
|
|
|
if (priv->rzang)
|
|
{
|
|
cogl_translatex (CLUTTER_UNITS_TO_FIXED (priv->rzx),
|
|
CLUTTER_UNITS_TO_FIXED (priv->rzy),
|
|
0);
|
|
|
|
cogl_rotatex (priv->rzang, 0, 0, CFX_ONE);
|
|
|
|
cogl_translatex (CLUTTER_UNITS_TO_FIXED (-priv->rzx),
|
|
CLUTTER_UNITS_TO_FIXED (-priv->rzy),
|
|
0);
|
|
}
|
|
|
|
if (priv->ryang)
|
|
{
|
|
cogl_translatex (CLUTTER_UNITS_TO_FIXED (priv->ryx),
|
|
0,
|
|
CLUTTER_UNITS_TO_FIXED (priv->z + priv->ryz));
|
|
|
|
cogl_rotatex (priv->ryang, 0, CFX_ONE, 0);
|
|
|
|
cogl_translatex (CLUTTER_UNITS_TO_FIXED (-priv->ryx),
|
|
0,
|
|
CLUTTER_UNITS_TO_FIXED (-(priv->z + priv->ryz)));
|
|
}
|
|
|
|
if (priv->rxang)
|
|
{
|
|
cogl_translatex (0,
|
|
CLUTTER_UNITS_TO_FIXED (priv->rxy),
|
|
CLUTTER_UNITS_TO_FIXED (priv->z + priv->rxz));
|
|
|
|
cogl_rotatex (priv->rxang, CFX_ONE, 0, 0);
|
|
|
|
cogl_translatex (0,
|
|
CLUTTER_UNITS_TO_FIXED (-priv->rxy),
|
|
CLUTTER_UNITS_TO_FIXED (-(priv->z + priv->rxz)));
|
|
}
|
|
|
|
if (!is_stage && (priv->anchor_x || priv->anchor_y))
|
|
{
|
|
cogl_translatex (CLUTTER_UNITS_TO_FIXED (-priv->anchor_x),
|
|
CLUTTER_UNITS_TO_FIXED (-priv->anchor_y),
|
|
0);
|
|
}
|
|
|
|
if (priv->z)
|
|
cogl_translatex (0, 0, priv->z);
|
|
}
|
|
|
|
/* Recursively applies the transforms associated with this actor and
|
|
* its ancestors to the OpenGL modelview matrix. Use NULL if you want this
|
|
* to go all the way down to the stage.
|
|
*
|
|
* This function does not push/pop matrix; it is the responsibility
|
|
* of the caller to do so as appropriate
|
|
*/
|
|
static void
|
|
_clutter_actor_apply_modelview_transform_recursive (ClutterActor *self,
|
|
ClutterActor *ancestor)
|
|
{
|
|
ClutterActor *parent, *stage;
|
|
|
|
parent = clutter_actor_get_parent (self);
|
|
|
|
/*
|
|
* If we reached the ancestor, quit
|
|
* NB: NULL ancestor means the stage, and this will not trigger
|
|
* (as it should not)
|
|
*/
|
|
if (self == ancestor)
|
|
return;
|
|
|
|
stage = clutter_actor_get_stage (self);
|
|
|
|
/* FIXME: if were not yet added to a stage, its probably unsafe to
|
|
* return default - idealy the func should fail.
|
|
*/
|
|
if (stage == NULL)
|
|
stage = clutter_stage_get_default ();
|
|
|
|
if (parent)
|
|
_clutter_actor_apply_modelview_transform_recursive (parent, ancestor);
|
|
else if (self != stage)
|
|
_clutter_actor_apply_modelview_transform (stage);
|
|
|
|
_clutter_actor_apply_modelview_transform (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_paint:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Renders the actor to display.
|
|
*
|
|
* This function should not be called directly by applications.
|
|
* Call clutter_actor_queue_redraw() to queue paints, instead.
|
|
*/
|
|
void
|
|
clutter_actor_paint (ClutterActor *self)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
ClutterActorClass *klass;
|
|
ClutterMainContext *context;
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
priv = self->priv;
|
|
|
|
if (!CLUTTER_ACTOR_IS_REALIZED (self))
|
|
{
|
|
CLUTTER_NOTE (PAINT, "Attempting realize via paint()");
|
|
clutter_actor_realize(self);
|
|
|
|
if (!CLUTTER_ACTOR_IS_REALIZED (self))
|
|
{
|
|
CLUTTER_NOTE (PAINT, "Attempt failed, aborting paint");
|
|
return;
|
|
}
|
|
}
|
|
|
|
context = clutter_context_get_default ();
|
|
klass = CLUTTER_ACTOR_GET_CLASS (self);
|
|
|
|
cogl_push_matrix();
|
|
|
|
_clutter_actor_apply_modelview_transform (self);
|
|
|
|
if (priv->has_clip)
|
|
cogl_clip_set (CLUTTER_UNITS_TO_FIXED (priv->clip[0]),
|
|
CLUTTER_UNITS_TO_FIXED (priv->clip[1]),
|
|
CLUTTER_UNITS_TO_FIXED (priv->clip[2]),
|
|
CLUTTER_UNITS_TO_FIXED (priv->clip[3]));
|
|
|
|
if (G_UNLIKELY(context->pick_mode != CLUTTER_PICK_NONE))
|
|
{
|
|
ClutterColor col;
|
|
|
|
_clutter_id_to_color (clutter_actor_get_gid (self), &col);
|
|
|
|
/* Actor will then paint silhouette of itself in supplied
|
|
* color. See clutter_stage_get_actor_at_pos() for where
|
|
* picking is enabled.
|
|
*/
|
|
clutter_actor_pick (self, &col);
|
|
}
|
|
else
|
|
{
|
|
clutter_actor_shader_pre_paint (self, FALSE);
|
|
|
|
if (G_LIKELY (klass->paint))
|
|
klass->paint (self);
|
|
|
|
clutter_actor_shader_post_paint (self);
|
|
}
|
|
|
|
if (priv->has_clip)
|
|
cogl_clip_unset();
|
|
|
|
cogl_pop_matrix();
|
|
}
|
|
|
|
static void
|
|
clutter_actor_real_request_coords (ClutterActor *self,
|
|
ClutterActorBox *box)
|
|
{
|
|
self->priv->coords = *box;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_request_coords:
|
|
* @self: A #ClutterActor
|
|
* @box: A #ClutterActorBox with the new coordinates, in ClutterUnits
|
|
*
|
|
* Requests new untransformed coordinates for the bounding box of
|
|
* a #ClutterActor. The coordinates must be relative to the current
|
|
* parent of the actor.
|
|
*
|
|
* This function should not be called directly by applications;
|
|
* instead, the various position/geometry methods should be used.
|
|
*
|
|
* Note: Actors overriding the ClutterActor::request_coords() virtual
|
|
* function should always chain up to the parent class request_coords()
|
|
* method. Actors should override this function only if they need to
|
|
* recompute some internal state or need to reposition their children.
|
|
*/
|
|
void
|
|
clutter_actor_request_coords (ClutterActor *self,
|
|
ClutterActorBox *box)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
gboolean x_change, y_change, width_change, height_change;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
g_return_if_fail (box != NULL);
|
|
|
|
priv = self->priv;
|
|
|
|
/* avoid calling request coords if the coordinates did not change */
|
|
x_change = (priv->coords.x1 != box->x1);
|
|
y_change = (priv->coords.y1 != box->y1);
|
|
width_change = ((priv->coords.x2 - priv->coords.x1) != (box->x2 - box->x1));
|
|
height_change = ((priv->coords.y2 - priv->coords.y1) != (box->y2 - box->y1));
|
|
|
|
if (x_change || y_change || width_change || height_change)
|
|
{
|
|
g_object_ref (self);
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
CLUTTER_ACTOR_GET_CLASS (self)->request_coords (self, box);
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
clutter_actor_queue_redraw (self);
|
|
|
|
if (x_change)
|
|
g_object_notify (G_OBJECT (self), "x");
|
|
|
|
if (y_change)
|
|
g_object_notify (G_OBJECT (self), "y");
|
|
|
|
if (width_change)
|
|
g_object_notify (G_OBJECT (self), "width");
|
|
|
|
if (height_change)
|
|
g_object_notify (G_OBJECT (self), "height");
|
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
g_object_unref (self);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_query_coords:
|
|
* @self: A #ClutterActor
|
|
* @box: A location to store the actor's #ClutterActorBox
|
|
*
|
|
* Requests the untransformed co-ordinates (in #ClutterUnit<!-- -->s) for
|
|
* the #ClutterActor, relative to any parent.
|
|
*
|
|
* This function should not be called directly by applications.
|
|
* The various position/geometry methods should be used instead.
|
|
*/
|
|
void
|
|
clutter_actor_query_coords (ClutterActor *self,
|
|
ClutterActorBox *box)
|
|
{
|
|
ClutterActorClass *klass;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
g_return_if_fail (box != NULL);
|
|
|
|
klass = CLUTTER_ACTOR_GET_CLASS (self);
|
|
|
|
box->x1 = self->priv->coords.x1;
|
|
box->y1 = self->priv->coords.y1;
|
|
box->x2 = self->priv->coords.x2;
|
|
box->y2 = self->priv->coords.y2;
|
|
|
|
if (klass->query_coords)
|
|
{
|
|
/* FIXME: This is kind of a cludge - we pass out *private*
|
|
* co-ords down to any subclasses so they can modify
|
|
* we then resync any changes. Needed for group class.
|
|
* Need to figure out nicer way.
|
|
*/
|
|
klass->query_coords(self, box);
|
|
|
|
self->priv->coords.x1 = box->x1;
|
|
self->priv->coords.y1 = box->y1;
|
|
self->priv->coords.x2 = box->x2;
|
|
self->priv->coords.y2 = box->y2;
|
|
}
|
|
}
|
|
|
|
/* fixed point, unit based rotation setter, to be used by
|
|
* set_property() so that we don't lose precision in the
|
|
* center coordinates by converting them to and from units
|
|
*/
|
|
static inline void
|
|
clutter_actor_set_rotation_internal (ClutterActor *self,
|
|
ClutterRotateAxis axis,
|
|
ClutterFixed angle,
|
|
ClutterUnit center_x,
|
|
ClutterUnit center_y,
|
|
ClutterUnit center_z)
|
|
{
|
|
ClutterActorPrivate *priv = self->priv;
|
|
|
|
g_object_ref (self);
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
switch (axis)
|
|
{
|
|
case CLUTTER_X_AXIS:
|
|
priv->rxang = angle;
|
|
priv->rxy = center_y;
|
|
priv->rxz = center_z;
|
|
g_object_notify (G_OBJECT (self), "rotation-angle-x");
|
|
g_object_notify (G_OBJECT (self), "rotation-center-x");
|
|
break;
|
|
|
|
case CLUTTER_Y_AXIS:
|
|
priv->ryang = angle;
|
|
priv->ryx = center_x;
|
|
priv->ryz = center_z;
|
|
g_object_notify (G_OBJECT (self), "rotation-angle-y");
|
|
g_object_notify (G_OBJECT (self), "rotation-center-y");
|
|
break;
|
|
case CLUTTER_Z_AXIS:
|
|
priv->rzang = angle;
|
|
priv->rzx = center_x;
|
|
priv->rzy = center_y;
|
|
g_object_notify (G_OBJECT (self), "rotation-angle-z");
|
|
g_object_notify (G_OBJECT (self), "rotation-center-z");
|
|
break;
|
|
}
|
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
g_object_unref (self);
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
clutter_actor_queue_redraw (self);
|
|
}
|
|
|
|
static void
|
|
clutter_actor_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
|
|
ClutterActor *actor;
|
|
ClutterActorPrivate *priv;
|
|
|
|
actor = CLUTTER_ACTOR(object);
|
|
priv = actor->priv;
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_X:
|
|
clutter_actor_set_x (actor, g_value_get_int (value));
|
|
break;
|
|
case PROP_Y:
|
|
clutter_actor_set_y (actor, g_value_get_int (value));
|
|
break;
|
|
case PROP_WIDTH:
|
|
clutter_actor_set_width (actor, g_value_get_int (value));
|
|
break;
|
|
case PROP_HEIGHT:
|
|
clutter_actor_set_height (actor, g_value_get_int (value));
|
|
break;
|
|
case PROP_DEPTH:
|
|
clutter_actor_set_depth (actor, g_value_get_int (value));
|
|
break;
|
|
case PROP_OPACITY:
|
|
clutter_actor_set_opacity (actor, g_value_get_uchar (value));
|
|
break;
|
|
case PROP_NAME:
|
|
clutter_actor_set_name (actor, g_value_get_string (value));
|
|
break;
|
|
case PROP_VISIBLE:
|
|
if (g_value_get_boolean (value) == TRUE)
|
|
clutter_actor_show (actor);
|
|
else
|
|
clutter_actor_hide (actor);
|
|
break;
|
|
case PROP_SCALE_X:
|
|
clutter_actor_set_scalex
|
|
(actor,
|
|
CLUTTER_FLOAT_TO_FIXED (g_value_get_double (value)),
|
|
priv->scale_y);
|
|
break;
|
|
case PROP_SCALE_Y:
|
|
clutter_actor_set_scalex
|
|
(actor,
|
|
priv->scale_x,
|
|
CLUTTER_FLOAT_TO_FIXED (g_value_get_double (value)));
|
|
break;
|
|
case PROP_CLIP:
|
|
{
|
|
ClutterGeometry *geom = g_value_get_boxed (value);
|
|
|
|
clutter_actor_set_clip (actor,
|
|
geom->x, geom->y,
|
|
geom->width, geom->height);
|
|
}
|
|
break;
|
|
case PROP_REACTIVE:
|
|
clutter_actor_set_reactive (actor, g_value_get_boolean (value));
|
|
break;
|
|
case PROP_ROTATION_ANGLE_X:
|
|
{
|
|
ClutterFixed angle;
|
|
|
|
angle = CLUTTER_FLOAT_TO_FIXED (g_value_get_double (value));
|
|
clutter_actor_set_rotation_internal (actor,
|
|
CLUTTER_X_AXIS,
|
|
angle,
|
|
0,
|
|
priv->rxy,
|
|
priv->rxz);
|
|
}
|
|
break;
|
|
case PROP_ROTATION_ANGLE_Y:
|
|
{
|
|
ClutterFixed angle;
|
|
|
|
angle = CLUTTER_FLOAT_TO_FIXED (g_value_get_double (value));
|
|
clutter_actor_set_rotation_internal (actor,
|
|
CLUTTER_Y_AXIS,
|
|
angle,
|
|
priv->ryx,
|
|
0,
|
|
priv->ryz);
|
|
}
|
|
break;
|
|
case PROP_ROTATION_ANGLE_Z:
|
|
{
|
|
ClutterFixed angle;
|
|
|
|
angle = CLUTTER_FLOAT_TO_FIXED (g_value_get_double (value));
|
|
clutter_actor_set_rotation_internal (actor,
|
|
CLUTTER_Z_AXIS,
|
|
angle,
|
|
priv->rzx,
|
|
priv->rzy,
|
|
0);
|
|
}
|
|
break;
|
|
case PROP_ROTATION_CENTER_X:
|
|
{
|
|
ClutterVertex *center;
|
|
|
|
center = g_value_get_boxed (value);
|
|
clutter_actor_set_rotation_internal (actor,
|
|
CLUTTER_X_AXIS,
|
|
priv->rxang,
|
|
0,
|
|
center->y,
|
|
center->z);
|
|
}
|
|
break;
|
|
case PROP_ROTATION_CENTER_Y:
|
|
{
|
|
ClutterVertex *center;
|
|
|
|
center = g_value_get_boxed (value);
|
|
clutter_actor_set_rotation_internal (actor,
|
|
CLUTTER_Y_AXIS,
|
|
priv->ryang,
|
|
center->x,
|
|
0,
|
|
center->z);
|
|
}
|
|
break;
|
|
case PROP_ROTATION_CENTER_Z:
|
|
{
|
|
ClutterVertex *center;
|
|
|
|
center = g_value_get_boxed (value);
|
|
clutter_actor_set_rotation_internal (actor,
|
|
CLUTTER_Z_AXIS,
|
|
priv->rzang,
|
|
center->x,
|
|
center->y,
|
|
0);
|
|
}
|
|
break;
|
|
case PROP_ANCHOR_X:
|
|
priv->anchor_x = CLUTTER_UNITS_FROM_DEVICE (g_value_get_int (value));
|
|
break;
|
|
case PROP_ANCHOR_Y:
|
|
priv->anchor_y = CLUTTER_UNITS_FROM_DEVICE (g_value_get_int (value));
|
|
break;
|
|
case PROP_SHOW_ON_SET_PARENT:
|
|
priv->show_on_set_parent = g_value_get_boolean (value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
clutter_actor_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
ClutterActor *actor;
|
|
ClutterActorPrivate *priv;
|
|
|
|
actor = CLUTTER_ACTOR(object);
|
|
priv = actor->priv;
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_X:
|
|
g_value_set_int (value, clutter_actor_get_x (actor));
|
|
break;
|
|
case PROP_Y:
|
|
g_value_set_int (value, clutter_actor_get_y (actor));
|
|
break;
|
|
case PROP_WIDTH:
|
|
g_value_set_int (value, clutter_actor_get_width (actor));
|
|
break;
|
|
case PROP_HEIGHT:
|
|
g_value_set_int (value, clutter_actor_get_height (actor));
|
|
break;
|
|
case PROP_DEPTH:
|
|
g_value_set_int (value, clutter_actor_get_depth (actor));
|
|
break;
|
|
case PROP_OPACITY:
|
|
g_value_set_uchar (value, priv->opacity);
|
|
break;
|
|
case PROP_NAME:
|
|
g_value_set_string (value, priv->name);
|
|
break;
|
|
case PROP_VISIBLE:
|
|
g_value_set_boolean (value,
|
|
(CLUTTER_ACTOR_IS_VISIBLE (actor) != FALSE));
|
|
break;
|
|
case PROP_HAS_CLIP:
|
|
g_value_set_boolean (value, priv->has_clip);
|
|
break;
|
|
case PROP_CLIP:
|
|
{
|
|
ClutterGeometry clip = { 0, };
|
|
|
|
clip.x = CLUTTER_UNITS_TO_DEVICE (priv->clip[0]);
|
|
clip.y = CLUTTER_UNITS_TO_DEVICE (priv->clip[1]);
|
|
clip.width = CLUTTER_UNITS_TO_DEVICE (priv->clip[2]);
|
|
clip.height = CLUTTER_UNITS_TO_DEVICE (priv->clip[3]);
|
|
|
|
g_value_set_boxed (value, &clip);
|
|
}
|
|
break;
|
|
case PROP_SCALE_X:
|
|
g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->scale_x));
|
|
break;
|
|
case PROP_SCALE_Y:
|
|
g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->scale_y));
|
|
break;
|
|
case PROP_REACTIVE:
|
|
g_value_set_boolean (value, clutter_actor_get_reactive (actor));
|
|
break;
|
|
case PROP_ROTATION_ANGLE_X:
|
|
g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->rxang));
|
|
break;
|
|
case PROP_ROTATION_ANGLE_Y:
|
|
g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->ryang));
|
|
break;
|
|
case PROP_ROTATION_ANGLE_Z:
|
|
g_value_set_double (value, CLUTTER_FIXED_TO_DOUBLE (priv->rzang));
|
|
break;
|
|
case PROP_ROTATION_CENTER_X:
|
|
{
|
|
ClutterVertex center = { 0, };
|
|
|
|
center.y = priv->rxy;
|
|
center.z = priv->rxz;
|
|
|
|
g_value_set_boxed (value, ¢er);
|
|
}
|
|
break;
|
|
case PROP_ROTATION_CENTER_Y:
|
|
{
|
|
ClutterVertex center = { 0, };
|
|
|
|
center.x = priv->ryx;
|
|
center.z = priv->ryz;
|
|
|
|
g_value_set_boxed (value, ¢er);
|
|
}
|
|
break;
|
|
case PROP_ROTATION_CENTER_Z:
|
|
{
|
|
ClutterVertex center = { 0, };
|
|
|
|
center.x = priv->rzx;
|
|
center.y = priv->rzy;
|
|
|
|
g_value_set_boxed (value, ¢er);
|
|
}
|
|
break;
|
|
case PROP_ANCHOR_X:
|
|
g_value_set_int (value, CLUTTER_UNITS_TO_DEVICE (priv->anchor_x));
|
|
break;
|
|
case PROP_ANCHOR_Y:
|
|
g_value_set_int (value, CLUTTER_UNITS_TO_DEVICE (priv->anchor_y));
|
|
break;
|
|
case PROP_SHOW_ON_SET_PARENT:
|
|
g_value_set_boolean (value, priv->show_on_set_parent);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
clutter_actor_dispose (GObject *object)
|
|
{
|
|
ClutterActor *self = CLUTTER_ACTOR (object);
|
|
|
|
CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type `%s' (ref_count:%d)",
|
|
self->priv->id,
|
|
g_type_name (G_OBJECT_TYPE (self)),
|
|
object->ref_count);
|
|
|
|
destroy_shader_data (self);
|
|
|
|
if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION))
|
|
{
|
|
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_DESTRUCTION);
|
|
|
|
g_signal_emit (self, actor_signals[DESTROY], 0);
|
|
|
|
CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_DESTRUCTION);
|
|
}
|
|
|
|
G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
clutter_actor_finalize (GObject *object)
|
|
{
|
|
ClutterActor *actor = CLUTTER_ACTOR (object);
|
|
|
|
CLUTTER_NOTE (MISC, "Finalize object (id=%d) of type `%s'",
|
|
actor->priv->id,
|
|
g_type_name (G_OBJECT_TYPE (actor)));
|
|
|
|
g_free (actor->priv->name);
|
|
clutter_id_pool_remove (CLUTTER_CONTEXT()->id_pool, actor->priv->id);
|
|
|
|
G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
clutter_actor_class_init (ClutterActorClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->set_property = clutter_actor_set_property;
|
|
object_class->get_property = clutter_actor_get_property;
|
|
object_class->dispose = clutter_actor_dispose;
|
|
object_class->finalize = clutter_actor_finalize;
|
|
|
|
g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
|
|
|
|
/**
|
|
* ClutterActor:x:
|
|
*
|
|
* X coordinate of the actor.
|
|
*/
|
|
g_object_class_install_property (object_class,
|
|
PROP_X,
|
|
g_param_spec_int ("x",
|
|
"X co-ord",
|
|
"X co-ord of actor",
|
|
-G_MAXINT, G_MAXINT,
|
|
0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor:y:
|
|
*
|
|
* Y coordinate of the actor.
|
|
*/
|
|
g_object_class_install_property (object_class,
|
|
PROP_Y,
|
|
g_param_spec_int ("y",
|
|
"Y co-ord",
|
|
"Y co-ord of actor",
|
|
-G_MAXINT, G_MAXINT,
|
|
0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor:width:
|
|
*
|
|
* Width of the actor (in pixels).
|
|
*/
|
|
g_object_class_install_property (object_class,
|
|
PROP_WIDTH,
|
|
g_param_spec_int ("width",
|
|
"Width",
|
|
"Width of actor in pixels",
|
|
0, G_MAXINT,
|
|
0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor:height:
|
|
*
|
|
* Height of the actor (in pixels).
|
|
*/
|
|
g_object_class_install_property (object_class,
|
|
PROP_HEIGHT,
|
|
g_param_spec_int ("height",
|
|
"Height",
|
|
"Height of actor in pixels",
|
|
0, G_MAXINT,
|
|
0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor:depth:
|
|
*
|
|
* Depth of the actor.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
g_object_class_install_property (object_class,
|
|
PROP_DEPTH,
|
|
g_param_spec_int ("depth",
|
|
"Depth",
|
|
"Depth of actor",
|
|
-G_MAXINT, G_MAXINT,
|
|
0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor:opacity:
|
|
*
|
|
* Opacity of the actor.
|
|
*/
|
|
g_object_class_install_property (object_class,
|
|
PROP_OPACITY,
|
|
g_param_spec_uchar ("opacity",
|
|
"Opacity",
|
|
"Opacity of actor",
|
|
0, 0xff,
|
|
0xff,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor:visible:
|
|
*
|
|
* Whether the actor is visible or not.
|
|
*/
|
|
g_object_class_install_property (object_class,
|
|
PROP_VISIBLE,
|
|
g_param_spec_boolean ("visible",
|
|
"Visible",
|
|
"Whether the actor is visible or not",
|
|
FALSE,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor:reactive:
|
|
*
|
|
* Whether the actor is reactive to events or not.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
g_object_class_install_property (object_class,
|
|
PROP_REACTIVE,
|
|
g_param_spec_boolean ("reactive",
|
|
"Reactive",
|
|
"Whether the actor is reactive to events or not",
|
|
FALSE,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor:has-clip:
|
|
*
|
|
* Whether the actor has the clip property set or not.
|
|
*/
|
|
g_object_class_install_property (object_class,
|
|
PROP_HAS_CLIP,
|
|
g_param_spec_boolean ("has-clip",
|
|
"Has Clip",
|
|
"Whether the actor has a clip set or not",
|
|
FALSE,
|
|
CLUTTER_PARAM_READABLE));
|
|
/**
|
|
* ClutterActor:clip:
|
|
*
|
|
* The clip region for the actor.
|
|
*/
|
|
g_object_class_install_property (object_class,
|
|
PROP_CLIP,
|
|
g_param_spec_boxed ("clip",
|
|
"Clip",
|
|
"The clip region for the actor",
|
|
CLUTTER_TYPE_GEOMETRY,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor:name:
|
|
*
|
|
* The name of the actor.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
g_object_class_install_property (object_class,
|
|
PROP_NAME,
|
|
g_param_spec_string ("name",
|
|
"Name",
|
|
"Name of the actor",
|
|
NULL,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor::scale-x:
|
|
*
|
|
* The horizontal scale of the actor
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class,
|
|
PROP_SCALE_X,
|
|
g_param_spec_double ("scale-x",
|
|
"Scale-X",
|
|
"Scale factor on the X axis",
|
|
0.0,
|
|
G_MAXDOUBLE,
|
|
1.0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor::scale-y:
|
|
*
|
|
* The vertical scale of the actor
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class,
|
|
PROP_SCALE_Y,
|
|
g_param_spec_double ("scale-y",
|
|
"Scale-Y",
|
|
"Scale factor on the Y axis",
|
|
0.0,
|
|
G_MAXDOUBLE,
|
|
1.0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor::rotation-angle-x:
|
|
*
|
|
* The rotation angle on the X axis.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class,
|
|
PROP_ROTATION_ANGLE_X,
|
|
g_param_spec_double ("rotation-angle-x",
|
|
"Rotation Angle X",
|
|
"The rotation angle on the X axis",
|
|
0.0,
|
|
G_MAXDOUBLE,
|
|
0.0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor::rotation-angle-y:
|
|
*
|
|
* The rotation angle on the Y axis.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class,
|
|
PROP_ROTATION_ANGLE_Y,
|
|
g_param_spec_double ("rotation-angle-y",
|
|
"Rotation Angle Y",
|
|
"The rotation angle on the Y axis",
|
|
0.0,
|
|
G_MAXDOUBLE,
|
|
0.0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor::rotation-angle-z:
|
|
*
|
|
* The rotation angle on the Z axis.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class,
|
|
PROP_ROTATION_ANGLE_Z,
|
|
g_param_spec_double ("rotation-angle-z",
|
|
"Rotation Angle Z",
|
|
"The rotation angle on the Z axis",
|
|
0.0,
|
|
G_MAXDOUBLE,
|
|
0.0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor::rotation-center-x:
|
|
*
|
|
* The rotation center on the X axis.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class,
|
|
PROP_ROTATION_CENTER_X,
|
|
g_param_spec_boxed ("rotation-center-x",
|
|
"Rotation Center X",
|
|
"The rotation center on the X axis",
|
|
CLUTTER_TYPE_VERTEX,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor::rotation-center-y:
|
|
*
|
|
* The rotation center on the Y axis.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class,
|
|
PROP_ROTATION_CENTER_Y,
|
|
g_param_spec_boxed ("rotation-center-y",
|
|
"Rotation Center Y",
|
|
"The rotation center on the Y axis",
|
|
CLUTTER_TYPE_VERTEX,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor::rotation-center-z:
|
|
*
|
|
* The rotation center on the Z axis.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class,
|
|
PROP_ROTATION_CENTER_Z,
|
|
g_param_spec_boxed ("rotation-center-z",
|
|
"Rotation Center Z",
|
|
"The rotation center on the Z axis",
|
|
CLUTTER_TYPE_VERTEX,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor::anchor-x:
|
|
*
|
|
* The X coordinate of an actor's anchor point, relative to
|
|
* the actor coordinate space, in pixels.
|
|
*
|
|
* Since: 0.8
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class,
|
|
PROP_ANCHOR_X,
|
|
g_param_spec_int ("anchor-x",
|
|
"Anchor X",
|
|
"X coordinate of the anchor point",
|
|
-G_MAXINT, G_MAXINT,
|
|
0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
/**
|
|
* ClutterActor::anchor-y:
|
|
*
|
|
* The Y coordinate of an actor's anchor point, relative to
|
|
* the actor coordinate space, in pixels.
|
|
*
|
|
* Since: 0.8
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class,
|
|
PROP_ANCHOR_Y,
|
|
g_param_spec_int ("anchor-y",
|
|
"Anchor Y",
|
|
"Y coordinate of the anchor point",
|
|
-G_MAXINT, G_MAXINT,
|
|
0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
|
|
/**
|
|
* ClutterActor:show-on-set-parent:
|
|
*
|
|
* If %TRUE, the actor is automatically shown when parented.
|
|
*
|
|
* Calling clutter_actor_hide() on an actor which has not been
|
|
* parented will set this property to %FALSE as a side effect.
|
|
*
|
|
* Since: 0.8
|
|
*/
|
|
g_object_class_install_property
|
|
(object_class,
|
|
PROP_SHOW_ON_SET_PARENT,
|
|
g_param_spec_boolean ("show-on-set-parent",
|
|
"Show on set parent",
|
|
"Whether the actor is shown"
|
|
" when parented",
|
|
TRUE,
|
|
CLUTTER_PARAM_READWRITE));
|
|
|
|
|
|
/**
|
|
* ClutterActor::destroy:
|
|
* @actor: the object which received the signal
|
|
*
|
|
* The ::destroy signal is emitted when an actor is destroyed,
|
|
* either by direct invocation of clutter_actor_destroy() or
|
|
* when the #ClutterGroup that contains the actor is destroyed.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
actor_signals[DESTROY] =
|
|
g_signal_new ("destroy",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
|
|
G_STRUCT_OFFSET (ClutterActorClass, destroy),
|
|
NULL, NULL,
|
|
clutter_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
/**
|
|
* ClutterActor::show:
|
|
* @actor: the object which received the signal
|
|
*
|
|
* The ::show signal is emitted when an actor is visible and
|
|
* rendered on the stage.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
actor_signals[SHOW] =
|
|
g_signal_new ("show",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, show),
|
|
NULL, NULL,
|
|
clutter_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
/**
|
|
* ClutterActor::hide:
|
|
* @actor: the object which received the signal
|
|
*
|
|
* The ::hide signal is emitted when an actor is no longer rendered
|
|
* on the stage.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
actor_signals[HIDE] =
|
|
g_signal_new ("hide",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, hide),
|
|
NULL, NULL,
|
|
clutter_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
/**
|
|
* ClutterActor::parent-set:
|
|
* @actor: the object which received the signal
|
|
* @old_parent: the previous parent of the actor, or %NULL
|
|
*
|
|
* This signal is emitted when the parent of the actor changes.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
actor_signals[PARENT_SET] =
|
|
g_signal_new ("parent-set",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, parent_set),
|
|
NULL, NULL,
|
|
clutter_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1,
|
|
CLUTTER_TYPE_ACTOR);
|
|
|
|
/**
|
|
* ClutterActor::event:
|
|
* @actor: the actor which received the event
|
|
* @event: a #ClutterEvent
|
|
*
|
|
* The ::event signal is emitted each time an event is received
|
|
* by the @actor. This signal will be emitted on every actor,
|
|
* following the hierarchy chain, until it reaches the top-level
|
|
* container (the #ClutterStage).
|
|
*
|
|
* Return value: %TRUE if the event has been handled by the actor,
|
|
* or %FALSE to continue the emission.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[EVENT] =
|
|
g_signal_new ("event",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, event),
|
|
_clutter_boolean_handled_accumulator, NULL,
|
|
clutter_marshal_BOOLEAN__BOXED,
|
|
G_TYPE_BOOLEAN, 1,
|
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
/**
|
|
* ClutterActor::button-press-event:
|
|
* @actor: the actor which received the event
|
|
* @event: a #ClutterButtonEvent
|
|
*
|
|
* The ::button-press-event signal is emitted each time a mouse button
|
|
* is pressed on @actor.
|
|
*
|
|
* Return value: %TRUE if the event has been handled by the actor,
|
|
* or %FALSE to continue the emission.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[BUTTON_PRESS_EVENT] =
|
|
g_signal_new ("button-press-event",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
|
|
_clutter_boolean_handled_accumulator, NULL,
|
|
clutter_marshal_BOOLEAN__BOXED,
|
|
G_TYPE_BOOLEAN, 1,
|
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
/**
|
|
* ClutterActor::button-release-event:
|
|
* @actor: the actor which received the event
|
|
* @event: a #ClutterButtonEvent
|
|
*
|
|
* The ::button-release-event signal is emitted each time a mouse button
|
|
* is released on @actor.
|
|
*
|
|
* Return value: %TRUE if the event has been handled by the actor,
|
|
* or %FALSE to continue the emission.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[BUTTON_RELEASE_EVENT] =
|
|
g_signal_new ("button-release-event",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
|
|
_clutter_boolean_handled_accumulator, NULL,
|
|
clutter_marshal_BOOLEAN__BOXED,
|
|
G_TYPE_BOOLEAN, 1,
|
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
/**
|
|
* ClutterActor::scroll-event:
|
|
* @actor: the actor which received the event
|
|
* @event: a #ClutterScrollEvent
|
|
*
|
|
* The ::scroll-event signal is emitted each time the mouse is
|
|
* scrolled on @actor
|
|
*
|
|
* Return value: %TRUE if the event has been handled by the actor,
|
|
* or %FALSE to continue the emission.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[SCROLL_EVENT] =
|
|
g_signal_new ("scroll-event",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
|
|
_clutter_boolean_handled_accumulator, NULL,
|
|
clutter_marshal_BOOLEAN__BOXED,
|
|
G_TYPE_BOOLEAN, 1,
|
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
/**
|
|
* ClutterActor::key-press-event:
|
|
* @actor: the actor which received the event
|
|
* @event: a #ClutterKeyEvent
|
|
*
|
|
* The ::key-press-event signal is emitted each time a keyboard button
|
|
* is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
|
|
*
|
|
* Return value: %TRUE if the event has been handled by the actor,
|
|
* or %FALSE to continue the emission.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[KEY_PRESS_EVENT] =
|
|
g_signal_new ("key-press-event",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
|
|
_clutter_boolean_handled_accumulator, NULL,
|
|
clutter_marshal_BOOLEAN__BOXED,
|
|
G_TYPE_BOOLEAN, 1,
|
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
/**
|
|
* ClutterActor::key-release-event:
|
|
* @actor: the actor which received the event
|
|
* @event: a #ClutterKeyEvent
|
|
*
|
|
* The ::key-release-event signal is emitted each time a keyboard button
|
|
* is released while @actor has key focus (see
|
|
* clutter_stage_set_key_focus()).
|
|
*
|
|
* Return value: %TRUE if the event has been handled by the actor,
|
|
* or %FALSE to continue the emission.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[KEY_RELEASE_EVENT] =
|
|
g_signal_new ("key-release-event",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
|
|
_clutter_boolean_handled_accumulator, NULL,
|
|
clutter_marshal_BOOLEAN__BOXED,
|
|
G_TYPE_BOOLEAN, 1,
|
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
/**
|
|
* ClutterActor::motion-event:
|
|
* @actor: the actor which received the event
|
|
* @event: a #ClutterMotionEvent
|
|
*
|
|
* The ::motion-event signal is emitted each time the mouse pointer is
|
|
* moved over @actor.
|
|
*
|
|
* Return value: %TRUE if the event has been handled by the actor,
|
|
* or %FALSE to continue the emission.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[MOTION_EVENT] =
|
|
g_signal_new ("motion-event",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, motion_event),
|
|
_clutter_boolean_handled_accumulator, NULL,
|
|
clutter_marshal_BOOLEAN__BOXED,
|
|
G_TYPE_BOOLEAN, 1,
|
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
|
|
/**
|
|
* ClutterActor::focus-in:
|
|
* @actor: the actor which now has key focus
|
|
*
|
|
* The ::focus-in signal is emitted when @actor recieves key focus.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[FOCUS_IN] =
|
|
g_signal_new ("focus-in",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, focus_in),
|
|
NULL, NULL,
|
|
clutter_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
/**
|
|
* ClutterActor::focus-out:
|
|
* @actor: the actor which now has key focus
|
|
*
|
|
* The ::focus-out signal is emitted when @actor loses key focus.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[FOCUS_OUT] =
|
|
g_signal_new ("focus-out",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, focus_out),
|
|
NULL, NULL,
|
|
clutter_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
/**
|
|
* ClutterActor::enter-event:
|
|
* @actor: the actor which the pointer has entered.
|
|
* @event: a #ClutterCrossingEvent
|
|
*
|
|
* The ::enter-event signal is emitted when the pointer enters the @actor
|
|
*
|
|
* Return value: %TRUE if the event has been handled by the actor,
|
|
* or %FALSE to continue the emission.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[ENTER_EVENT] =
|
|
g_signal_new ("enter-event",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, enter_event),
|
|
_clutter_boolean_handled_accumulator, NULL,
|
|
clutter_marshal_BOOLEAN__BOXED,
|
|
G_TYPE_BOOLEAN, 1,
|
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
|
|
/**
|
|
* ClutterActor::leave-event:
|
|
* @actor: the actor which the pointer has left
|
|
* @event: a #ClutterCrossingEvent
|
|
*
|
|
* The ::leave-event signal is emitted when the pointer leaves the @actor.
|
|
*
|
|
* Return value: %TRUE if the event has been handled by the actor,
|
|
* or %FALSE to continue the emission.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[LEAVE_EVENT] =
|
|
g_signal_new ("leave-event",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, leave_event),
|
|
_clutter_boolean_handled_accumulator, NULL,
|
|
clutter_marshal_BOOLEAN__BOXED,
|
|
G_TYPE_BOOLEAN, 1,
|
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
|
|
/**
|
|
* ClutterActor::captured-event:
|
|
* @actor: the actor which received the signal
|
|
* @event: a #ClutterEvent
|
|
*
|
|
* The ::captured-event signal is emitted when an event is captured
|
|
* by Clutter. This signal will be emitted starting from the top-level
|
|
* container (the #ClutterStage) to the actor which received the event
|
|
* going down the hierarchy. This signal can be used to intercept every
|
|
* event before the specialized events (like
|
|
* ClutterActor::button-press-event or ::key-released-event) are
|
|
* emitted.
|
|
*
|
|
* Return value: %TRUE if the event has been handled by the actor,
|
|
* or %FALSE to continue the emission.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
actor_signals[CAPTURED_EVENT] =
|
|
g_signal_new ("captured-event",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterActorClass, captured_event),
|
|
_clutter_boolean_handled_accumulator, NULL,
|
|
clutter_marshal_BOOLEAN__BOXED,
|
|
G_TYPE_BOOLEAN, 1,
|
|
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
|
|
|
|
klass->show = clutter_actor_real_show;
|
|
klass->show_all = clutter_actor_show;
|
|
klass->hide = clutter_actor_real_hide;
|
|
klass->hide_all = clutter_actor_hide;
|
|
klass->pick = clutter_actor_real_pick;
|
|
klass->request_coords = clutter_actor_real_request_coords;
|
|
}
|
|
|
|
static void
|
|
clutter_actor_init (ClutterActor *self)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
ClutterActorBox box = { 0, };
|
|
|
|
self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
|
|
|
|
priv->parent_actor = NULL;
|
|
priv->has_clip = FALSE;
|
|
priv->opacity = 0xff;
|
|
priv->id = clutter_id_pool_add (CLUTTER_CONTEXT()->id_pool, self);
|
|
priv->scale_x = CFX_ONE;
|
|
priv->scale_y = CFX_ONE;
|
|
priv->shader_data = NULL;
|
|
priv->show_on_set_parent = TRUE;
|
|
|
|
memset (priv->clip, 0, sizeof (ClutterUnit) * 4);
|
|
|
|
clutter_actor_request_coords (self, &box);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_destroy:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* Destroys an actor. When an actor is destroyed, it will break any
|
|
* references it holds to other objects. If the actor is inside a
|
|
* container, the actor will be removed.
|
|
*
|
|
* When you destroy a container, its children will be destroyed as well.
|
|
*
|
|
* Note: you cannot destroy the #ClutterStage returned by
|
|
* clutter_stage_get_default().
|
|
*/
|
|
void
|
|
clutter_actor_destroy (ClutterActor *self)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
g_object_ref (self);
|
|
|
|
if (priv->parent_actor)
|
|
{
|
|
ClutterActor *parent = priv->parent_actor;
|
|
|
|
if (CLUTTER_IS_CONTAINER (parent))
|
|
clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
|
|
else
|
|
priv->parent_actor = NULL;
|
|
}
|
|
|
|
if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_DESTRUCTION))
|
|
g_object_run_dispose (G_OBJECT (self));
|
|
|
|
g_object_unref (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_queue_redraw:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Queues up a redraw of an actor and any children. The redraw occurs
|
|
* once the main loop becomes idle (after the current batch of events
|
|
* has been processed, roughly).
|
|
*
|
|
* Applications rarely need to call this, as redraws are handled
|
|
* automatically by modification functions.
|
|
*/
|
|
void
|
|
clutter_actor_queue_redraw (ClutterActor *self)
|
|
{
|
|
ClutterActor *stage;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
/* FIXME: should we check we're visible here? */
|
|
if ((stage = clutter_actor_get_stage (self)) != NULL)
|
|
clutter_stage_queue_redraw (CLUTTER_STAGE (stage));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_geometry:
|
|
* @self: A #ClutterActor
|
|
* @geometry: A #ClutterGeometry
|
|
*
|
|
* Sets the actor's untransformed geometry in pixels relative to any
|
|
* parent actor.
|
|
*/
|
|
void
|
|
clutter_actor_set_geometry (ClutterActor *self,
|
|
const ClutterGeometry *geometry)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
box.x1 = CLUTTER_UNITS_FROM_INT (geometry->x);
|
|
box.y1 = CLUTTER_UNITS_FROM_INT (geometry->y);
|
|
box.x2 = CLUTTER_UNITS_FROM_INT (geometry->x + geometry->width);
|
|
box.y2 = CLUTTER_UNITS_FROM_INT (geometry->y + geometry->height);
|
|
|
|
clutter_actor_request_coords (self, &box);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_geometry:
|
|
* @self: A #ClutterActor
|
|
* @geometry: A location to store actors #ClutterGeometry
|
|
*
|
|
* Gets the actor's untransformed geometry in pixels relative to any
|
|
* parent actor.
|
|
*/
|
|
void
|
|
clutter_actor_get_geometry (ClutterActor *self,
|
|
ClutterGeometry *geometry)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
geometry->x = CLUTTER_UNITS_TO_DEVICE (box.x1);
|
|
geometry->y = CLUTTER_UNITS_TO_DEVICE (box.y1);
|
|
geometry->width = CLUTTER_UNITS_TO_DEVICE (box.x2 - box.x1);
|
|
geometry->height = CLUTTER_UNITS_TO_DEVICE (box.y2 - box.y1);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_coords:
|
|
* @self: A #ClutterActor
|
|
* @x_1: A location to store actors left position, or %NULL.
|
|
* @y_1: A location to store actors top position, or %NULL.
|
|
* @x_2: A location to store actors right position, or %NULL.
|
|
* @y_2: A location to store actors bottom position, or %NULL.
|
|
*
|
|
* Gets the actor's untransformed bounding rectangle coordinates in pixels
|
|
* relative to any parent actor.
|
|
*/
|
|
void
|
|
clutter_actor_get_coords (ClutterActor *self,
|
|
gint *x_1,
|
|
gint *y_1,
|
|
gint *x_2,
|
|
gint *y_2)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
if (x_1)
|
|
*x_1 = CLUTTER_UNITS_TO_DEVICE (box.x1);
|
|
|
|
if (y_1)
|
|
*y_1 = CLUTTER_UNITS_TO_DEVICE (box.y1);
|
|
|
|
if (x_2)
|
|
*x_2 = CLUTTER_UNITS_TO_DEVICE (box.x2);
|
|
|
|
if (y_2)
|
|
*y_2 = CLUTTER_UNITS_TO_DEVICE (box.y2);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_position
|
|
* @self: A #ClutterActor
|
|
* @x: New left position of actor in pixels.
|
|
* @y: New top position of actor in pixels.
|
|
*
|
|
* Sets the actor's position in pixels relative to any parent actor.
|
|
*/
|
|
void
|
|
clutter_actor_set_position (ClutterActor *self,
|
|
gint x,
|
|
gint y)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
box.x2 += (CLUTTER_UNITS_FROM_INT (x) - box.x1);
|
|
box.y2 += (CLUTTER_UNITS_FROM_INT (y) - box.y1);
|
|
|
|
box.x1 = CLUTTER_UNITS_FROM_INT (x);
|
|
box.y1 = CLUTTER_UNITS_FROM_INT (y);
|
|
|
|
clutter_actor_request_coords (self, &box);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_positionu
|
|
* @self: A #ClutterActor
|
|
* @x: New left position of actor in #ClutterUnit<!-- -->s
|
|
* @y: New top position of actor in #ClutterUnit<!-- -->s
|
|
*
|
|
* Sets the actor's position in #ClutterUnit<!-- -->s relative to any
|
|
* parent actor.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_positionu (ClutterActor *self,
|
|
ClutterUnit x,
|
|
ClutterUnit y)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
box.x2 += (x - box.x1);
|
|
box.y2 += (y - box.y1);
|
|
|
|
box.x1 = x;
|
|
box.y1 = y;
|
|
|
|
clutter_actor_request_coords (self, &box);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_move_by:
|
|
* @self: A #ClutterActor
|
|
* @dx: Distance to move Actor on X axis.
|
|
* @dy: Distance to move Actor on Y axis.
|
|
*
|
|
* Moves an actor by the specified distance relative to its
|
|
* current position in pixels.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
void
|
|
clutter_actor_move_by (ClutterActor *self,
|
|
gint dx,
|
|
gint dy)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_move_byu (self,
|
|
CLUTTER_UNITS_FROM_DEVICE (dx),
|
|
CLUTTER_UNITS_FROM_DEVICE (dy));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_move_byu:
|
|
* @self: A #ClutterActor
|
|
* @dx: Distance to move Actor on X axis, in #ClutterUnit<!-- -->s.
|
|
* @dy: Distance to move Actor on Y axis, in #ClutterUnit<!-- -->s.
|
|
*
|
|
* Moves an actor by the specified distance relative to its current
|
|
* position.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_move_byu (ClutterActor *self,
|
|
ClutterUnit dx,
|
|
ClutterUnit dy)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
box.x2 += dx;
|
|
box.y2 += dy;
|
|
box.x1 += dx;
|
|
box.y1 += dy;
|
|
|
|
clutter_actor_request_coords (self, &box);
|
|
}
|
|
|
|
/* local inline version, without type checking to be used by
|
|
* set_width() and set_height(). if one of the dimensions is < 0
|
|
* it will not be changed
|
|
*/
|
|
static inline void
|
|
clutter_actor_set_size_internal (ClutterActor *self,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
if (width > 0)
|
|
box.x2 = box.x1 + CLUTTER_UNITS_FROM_INT (width);
|
|
|
|
if (height > 0)
|
|
box.y2 = box.y1 + CLUTTER_UNITS_FROM_INT (height);
|
|
|
|
clutter_actor_request_coords (self, &box);
|
|
}
|
|
|
|
/* local inline unit version, without type checking to be used by
|
|
* set_width() and set_height(). if one of the dimensions is < 0
|
|
* it will not be changed
|
|
*/
|
|
static inline void
|
|
clutter_actor_set_size_internalu (ClutterActor *self,
|
|
ClutterUnit width,
|
|
ClutterUnit height)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
if (width > 0)
|
|
box.x2 = box.x1 + width;
|
|
|
|
if (height > 0)
|
|
box.y2 = box.y1 + height;
|
|
|
|
clutter_actor_request_coords (self, &box);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_size
|
|
* @self: A #ClutterActor
|
|
* @width: New width of actor in pixels, or -1
|
|
* @height: New height of actor in pixels, or -1
|
|
*
|
|
* Sets the actor's size in pixels.
|
|
*
|
|
* If @width and/or @height are -1 the actor will assume the same size
|
|
* of its bounding box.
|
|
*
|
|
* <note>This function is a "request" to the #ClutterActor. Depending
|
|
* on the actual implementation, calling clutter_actor_set_size() might
|
|
* not produce visible results. Calling this function on a #ClutterGroup,
|
|
* for instance, will not resize the group - as its size is dependant
|
|
* on bounding box of actual contents</note>
|
|
*/
|
|
void
|
|
clutter_actor_set_size (ClutterActor *self,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_size_internal (self, width, height);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_sizeu
|
|
* @self: A #ClutterActor
|
|
* @width: New width of actor in #ClutterUnit<!-- -->s, or -1
|
|
* @height: New height of actor in #ClutterUnit<!-- -->s, or -1
|
|
*
|
|
* Sets the actor's size in #ClutterUnit<!-- -->s. If @width and/or @height
|
|
* are -1 the actor will assume the same size as its bounding box.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_sizeu (ClutterActor *self,
|
|
ClutterUnit width,
|
|
ClutterUnit height)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_size_internalu (self, width, height);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_size:
|
|
* @self: A #ClutterActor
|
|
* @width: return location for the width, or %NULL.
|
|
* @height: return location for the height, or %NULL.
|
|
*
|
|
* Gets the size of an actor in pixels, ignoring any scaling factors.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
void
|
|
clutter_actor_get_size (ClutterActor *self,
|
|
guint *width,
|
|
guint *height)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
if (width)
|
|
*width = CLUTTER_UNITS_TO_DEVICE (box.x2 - box.x1);
|
|
|
|
if (height)
|
|
*height = CLUTTER_UNITS_TO_DEVICE (box.y2 - box.y1);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_sizeu:
|
|
* @self: A #ClutterActor
|
|
* @width: return location for the width, or %NULL
|
|
* @height: return location for the height, or %NULL
|
|
*
|
|
* Gets the size of an actor in #ClutterUnit<!-- -->s, ignoring any scaling
|
|
* factors.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_get_sizeu (ClutterActor *self,
|
|
ClutterUnit *width,
|
|
ClutterUnit *height)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
if (width)
|
|
*width = box.x2 - box.x1;
|
|
|
|
if (height)
|
|
*height = box.y2 - box.y1;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_position:
|
|
* @self: a #ClutterActor
|
|
* @x: return location for the X coordinate, or %NULL
|
|
* @y: return location for the Y coordinate, or %NULL
|
|
*
|
|
* Retrieves the position of an actor.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_get_position (ClutterActor *self,
|
|
gint *x,
|
|
gint *y)
|
|
{
|
|
ClutterActorBox box = { 0, };
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
if (x)
|
|
*x = CLUTTER_UNITS_TO_DEVICE (box.x1);
|
|
|
|
if (y)
|
|
*y = CLUTTER_UNITS_TO_DEVICE (box.y1);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_positionu:
|
|
* @self: a #ClutterActor
|
|
* @x: return location for the X coordinate, or %NULL
|
|
* @y: return location for the Y coordinate, or %NULL
|
|
*
|
|
* Retrieves the position of an actor in #ClutterUnit<!-- -->s.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_get_positionu (ClutterActor *self,
|
|
ClutterUnit *x,
|
|
ClutterUnit *y)
|
|
{
|
|
ClutterActorBox box = { 0, };
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
if (x)
|
|
*x = box.x1;
|
|
|
|
if (y)
|
|
*y = box.y1;
|
|
}
|
|
|
|
/*
|
|
* clutter_actor_get_abs_position_units
|
|
* @self: A #ClutterActor
|
|
* @x: return location for the X coordinate, or %NULL
|
|
* @y: return location for the Y coordinate, or %NULL
|
|
*
|
|
* Gets the absolute position of an actor, in #ClutterUnit<!-- -->s,
|
|
* relative to the stage.
|
|
*
|
|
* Since: 0.4
|
|
*/
|
|
static void
|
|
clutter_actor_get_abs_position_units (ClutterActor *self,
|
|
gint32 *x,
|
|
gint32 *y)
|
|
{
|
|
ClutterVertex v1;
|
|
ClutterVertex v2;
|
|
|
|
v1.x = v1.y = v1.z = 0;
|
|
clutter_actor_apply_transform_to_point (self, &v1, &v2);
|
|
|
|
if (x)
|
|
*x = v2.x;
|
|
if (y)
|
|
*y = v2.y;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_abs_position
|
|
* @self: A #ClutterActor
|
|
* @x: return location for the X coordinate, or %NULL
|
|
* @y: return location for the Y coordinate, or %NULL
|
|
*
|
|
* Gets the absolute position of an actor, in pixels, relative
|
|
* to the stage.
|
|
*/
|
|
void
|
|
clutter_actor_get_abs_position (ClutterActor *self,
|
|
gint *x,
|
|
gint *y)
|
|
{
|
|
ClutterUnit xu, yu;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
xu = yu = 0;
|
|
clutter_actor_get_abs_position_units (self, &xu, &yu);
|
|
|
|
if (x)
|
|
*x = CLUTTER_UNITS_TO_DEVICE (xu);
|
|
if (y)
|
|
*y = CLUTTER_UNITS_TO_DEVICE (yu);
|
|
}
|
|
|
|
/*
|
|
* clutter_actor_get_abs_size_units:
|
|
* @self: A #ClutterActor
|
|
* @width: return location for the width, or %NULL
|
|
* @height: return location for the height, or %NULL
|
|
*
|
|
* Gets the absolute size of an actor in #ClutterUnits<!-- -->s, taking
|
|
* into account the scaling factors.
|
|
*
|
|
* <note>When the actor (or one of its ancestors) is rotated around the
|
|
* X or Y axis, it no longer appears as on the stage as a rectangle, but
|
|
* as a generic quadrangle; in that case this function returns the size
|
|
* of the smallest rectangle that encapsulates the entire quad. Please
|
|
* note that in this case no assumptions can be made about the relative
|
|
* position of this envelope to the absolute position of the actor, as
|
|
* returned by clutter_actor_get_abs_position(); if you need this
|
|
* information, you need to use clutter_actor_get_vertices() to get the
|
|
* coords of the actual quadrangle.
|
|
*
|
|
* Since: 0.4
|
|
*/
|
|
static void
|
|
clutter_actor_get_abs_size_units (ClutterActor *self,
|
|
gint32 *width,
|
|
gint32 *height)
|
|
{
|
|
ClutterVertex v[4];
|
|
ClutterFixed x_min, x_max, y_min, y_max;
|
|
gint i;
|
|
|
|
clutter_actor_get_vertices (self, v);
|
|
|
|
x_min = x_max = v[0].x;
|
|
y_min = y_max = v[0].y;
|
|
|
|
for (i = 1; i < sizeof(v)/sizeof(v[0]); ++i)
|
|
{
|
|
if (v[i].x < x_min)
|
|
x_min = v[i].x;
|
|
|
|
if (v[i].x > x_max)
|
|
x_max = v[i].x;
|
|
|
|
if (v[i].y < y_min)
|
|
y_min = v[i].y;
|
|
|
|
if (v[i].y > y_max)
|
|
y_max = v[i].y;
|
|
}
|
|
|
|
*width = x_max - x_min;
|
|
*height = y_max - y_min;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_abs_size:
|
|
* @self: A #ClutterActor
|
|
* @width: return location for the width, or %NULL
|
|
* @height: return location for the height, or %NULL
|
|
*
|
|
* Gets the absolute size of an actor taking into account
|
|
* an scaling factors
|
|
*/
|
|
void
|
|
clutter_actor_get_abs_size (ClutterActor *self,
|
|
guint *width,
|
|
guint *height)
|
|
{
|
|
gint32 wu, hu;
|
|
clutter_actor_get_abs_size_units (self, &wu, &hu);
|
|
|
|
*width = CLUTTER_UNITS_TO_DEVICE (wu);
|
|
*height = CLUTTER_UNITS_TO_DEVICE (hu);
|
|
}
|
|
|
|
|
|
/**
|
|
* clutter_actor_get_width
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the actor's width ignoring any scaling factors.
|
|
*
|
|
* Return value: the width in pixels
|
|
**/
|
|
guint
|
|
clutter_actor_get_width (ClutterActor *self)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
return CLUTTER_UNITS_TO_DEVICE (box.x2 - box.x1);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_widthu
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the actor's width ignoring any scaling factors.
|
|
*
|
|
* Return value: the width in #ClutterUnit<!-- -->s
|
|
*
|
|
* since: 0.6
|
|
**/
|
|
ClutterUnit
|
|
clutter_actor_get_widthu (ClutterActor *self)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
return box.x2 - box.x1;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_height
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the actor's height ignoring any scaling factors.
|
|
*
|
|
* Return value: the height in pixels
|
|
**/
|
|
guint
|
|
clutter_actor_get_height (ClutterActor *self)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
return CLUTTER_UNITS_TO_DEVICE (box.y2 - box.y1);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_heightu
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the actor's height ignoring any scaling factors.
|
|
*
|
|
* Return value: the height in #ClutterUnit<!-- -->s
|
|
*
|
|
* since: 0.6
|
|
**/
|
|
ClutterUnit
|
|
clutter_actor_get_heightu (ClutterActor *self)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
return box.y2 - box.y1;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_width
|
|
* @self: A #ClutterActor
|
|
* @width: Requested new width for the actor, in pixels
|
|
*
|
|
* Requests a new width for the actor
|
|
*
|
|
* since: 0.2
|
|
**/
|
|
void
|
|
clutter_actor_set_width (ClutterActor *self,
|
|
guint width)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_size_internal (self, width, -1);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_widthu
|
|
* @self: A #ClutterActor
|
|
* @width: Requested new width for the actor, in #ClutterUnit<!-- -->s
|
|
*
|
|
* Requests a new width for the actor
|
|
*
|
|
* since: 0.6
|
|
**/
|
|
void
|
|
clutter_actor_set_widthu (ClutterActor *self,
|
|
ClutterUnit width)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_size_internalu (self, width, -1);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_height
|
|
* @self: A #ClutterActor
|
|
* @height: Requested new height for the actor, in pixels
|
|
*
|
|
* Requests a new height for the actor
|
|
*
|
|
* since: 0.2
|
|
**/
|
|
void
|
|
clutter_actor_set_height (ClutterActor *self,
|
|
guint height)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_size_internal (self, -1, height);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_heightu
|
|
* @self: A #ClutterActor
|
|
* @height: Requested new height for the actor, in #ClutterUnit<!-- -->s
|
|
*
|
|
* Requests a new height for the actor
|
|
*
|
|
* since: 0.6
|
|
**/
|
|
void
|
|
clutter_actor_set_heightu (ClutterActor *self,
|
|
ClutterUnit height)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_size_internalu (self, -1, height);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_x:
|
|
* @self: a #ClutterActor
|
|
* @x: the actor's position on the X axis
|
|
*
|
|
* Sets the actor's X coordinate, relative to its parent.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_x (ClutterActor *self,
|
|
gint x)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_position (self,
|
|
x,
|
|
clutter_actor_get_y (self));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_xu:
|
|
* @self: a #ClutterActor
|
|
* @x: the actor's position on the X axis, in #ClutterUnit<!-- -->s
|
|
*
|
|
* Sets the actor's X coordinate, relative to its parent.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_xu (ClutterActor *self,
|
|
ClutterUnit x)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_positionu (self,
|
|
x,
|
|
clutter_actor_get_yu (self));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_y:
|
|
* @self: a #ClutterActor
|
|
* @y: the actor's position on the Y axis
|
|
*
|
|
* Sets the actor's Y coordinate, relative to its parent.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_y (ClutterActor *self,
|
|
gint y)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_position (self,
|
|
clutter_actor_get_x (self),
|
|
y);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_yu:
|
|
* @self: a #ClutterActor
|
|
* @y: the actor's position on the Y axis, in #ClutterUnit<!-- -->s
|
|
*
|
|
* Sets the actor's Y coordinate, relative to its parent.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_yu (ClutterActor *self,
|
|
ClutterUnit y)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_positionu (self,
|
|
clutter_actor_get_xu (self),
|
|
y);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_x
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the actor's X coordinate, relative to any parent.
|
|
*
|
|
* Return value: the X coordinate, in pixels, ignoring any
|
|
* transformation (i.e. scaling, rotation).
|
|
*/
|
|
gint
|
|
clutter_actor_get_x (ClutterActor *self)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
return CLUTTER_UNITS_TO_DEVICE (box.x1);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_xu
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the actor's X coordinate, relative to any parent,
|
|
* in #ClutterUnit<!-- -->s.
|
|
*
|
|
* Return value: the X coordinate, in #ClutterUnit<!-- -->s, ignoring
|
|
* any transformation (i.e. scaling, rotation).
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
ClutterUnit
|
|
clutter_actor_get_xu (ClutterActor *self)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
return box.x1;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_y:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the actor's Y coordinate, relative to any parent.
|
|
*
|
|
* Return value: the Y coordinate, in pixels, ignoring any
|
|
* transformation (i.e. scaling, rotation).
|
|
*/
|
|
gint
|
|
clutter_actor_get_y (ClutterActor *self)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
return CLUTTER_UNITS_TO_DEVICE (box.y1);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_yu:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the actor's Y coordinate, relative to any parent,
|
|
* in #ClutterUnit<!-- -->s.
|
|
*
|
|
* Return value: the Y coordinate, in #ClutterUnit<!-- -->s, ignoring any
|
|
* transformation (i.e. scaling, rotation).
|
|
*/
|
|
ClutterUnit
|
|
clutter_actor_get_yu (ClutterActor *self)
|
|
{
|
|
ClutterActorBox box;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
return box.y1;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_scalex:
|
|
* @self: A #ClutterActor
|
|
* @scale_x: #ClutterFixed factor to scale actor by horizontally.
|
|
* @scale_y: #ClutterFixed factor to scale actor by vertically.
|
|
*
|
|
* Fixed point version of clutter_actor_set_scale().
|
|
*
|
|
* Scales an actor with the given factors. The scaling is always
|
|
* relative to the anchor point.
|
|
*/
|
|
void
|
|
clutter_actor_set_scalex (ClutterActor *self,
|
|
ClutterFixed scale_x,
|
|
ClutterFixed scale_y)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
g_object_ref (self);
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
self->priv->scale_x = scale_x;
|
|
g_object_notify (G_OBJECT (self), "scale-x");
|
|
|
|
self->priv->scale_y = scale_y;
|
|
g_object_notify (G_OBJECT (self), "scale-y");
|
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
g_object_unref (self);
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
clutter_actor_queue_redraw (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_scale:
|
|
* @self: A #ClutterActor
|
|
* @scale_x: double factor to scale actor by horizontally.
|
|
* @scale_y: double factor to scale actor by vertically.
|
|
*
|
|
* Scales an actor with the given factors. The scaling is always
|
|
* relative to the anchor point.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
void
|
|
clutter_actor_set_scale (ClutterActor *self,
|
|
double scale_x,
|
|
double scale_y)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_scalex (self,
|
|
CLUTTER_FLOAT_TO_FIXED (scale_x),
|
|
CLUTTER_FLOAT_TO_FIXED (scale_y));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_scalex:
|
|
* @self: A #ClutterActor
|
|
* @scale_x: Location to store horizonal scale factor, or %NULL.
|
|
* @scale_y: Location to store vertical scale factor, or %NULL.
|
|
*
|
|
* Fixed point version of clutter_actor_get_scale().
|
|
*
|
|
* Retrieves the scale factors of an actor.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
void
|
|
clutter_actor_get_scalex (ClutterActor *self,
|
|
ClutterFixed *scale_x,
|
|
ClutterFixed *scale_y)
|
|
{
|
|
if (scale_x)
|
|
*scale_x = self->priv->scale_x;
|
|
|
|
if (scale_y)
|
|
*scale_y = self->priv->scale_y;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_scale:
|
|
* @self: A #ClutterActor
|
|
* @scale_x: Location to store horizonal float scale factor, or %NULL.
|
|
* @scale_y: Location to store vertical float scale factor, or %NULL.
|
|
*
|
|
* Retrieves an actors scale in floating point.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
void
|
|
clutter_actor_get_scale (ClutterActor *self,
|
|
gdouble *scale_x,
|
|
gdouble *scale_y)
|
|
{
|
|
if (scale_x)
|
|
*scale_x = CLUTTER_FIXED_TO_FLOAT (self->priv->scale_x);
|
|
|
|
if (scale_y)
|
|
*scale_y = CLUTTER_FIXED_TO_FLOAT (self->priv->scale_y);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_opacity:
|
|
* @self: A #ClutterActor
|
|
* @opacity: New opacity value for the actor.
|
|
*
|
|
* Sets the actor's opacity, with zero being completely transparent and
|
|
* 255 (0xff) being fully opaque.
|
|
*/
|
|
void
|
|
clutter_actor_set_opacity (ClutterActor *self,
|
|
guint8 opacity)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
self->priv->opacity = opacity;
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
clutter_actor_queue_redraw (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_abs_opacity:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the absolute opacity of the actor, as it appears on the stage.
|
|
*
|
|
* This function traverses the hierarchy chain and composites the opacity of
|
|
* the actor with that of its parents.
|
|
*
|
|
* This function is intended for subclasses to use in the paint virtual
|
|
* function, to paint themselves with the correct opacity.
|
|
*
|
|
* Return value: The actor opacity value.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
guint8
|
|
clutter_actor_get_abs_opacity (ClutterActor *self)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
ClutterActor *parent;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
priv = self->priv;
|
|
|
|
parent = priv->parent_actor;
|
|
|
|
/* Factor in the actual actors opacity with parents */
|
|
if (G_LIKELY (parent))
|
|
{
|
|
guint8 opacity = clutter_actor_get_abs_opacity (parent);
|
|
|
|
if (opacity != 0xff)
|
|
return (opacity * priv->opacity) / 0xff;
|
|
}
|
|
|
|
return clutter_actor_get_opacity (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_opacity:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* Retrieves the opacity value of an actor, as set by
|
|
* clutter_actor_set_opacity().
|
|
*
|
|
* For retrieving the absolute opacity of the actor inside a paint
|
|
* virtual function, see clutter_actor_get_abs_opacity().
|
|
*
|
|
* Return value: the opacity of the actor
|
|
*/
|
|
guint8
|
|
clutter_actor_get_opacity (ClutterActor *self)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
return self->priv->opacity;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_name:
|
|
* @self: A #ClutterActor
|
|
* @name: Textual tag to apply to actor
|
|
*
|
|
* Sets the given name to @self. The name can be used to identify
|
|
* a #ClutterActor.
|
|
*/
|
|
void
|
|
clutter_actor_set_name (ClutterActor *self,
|
|
const gchar *name)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
g_object_ref (self);
|
|
|
|
g_free (self->priv->name);
|
|
|
|
if (name && name[0] != '\0')
|
|
self->priv->name = g_strdup(name);
|
|
|
|
g_object_notify (G_OBJECT (self), "name");
|
|
g_object_unref (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_name:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the name of @self.
|
|
*
|
|
* Return value: the name of the actor, or %NULL. The returned string is
|
|
* owned by the actor and should not be modified or freed.
|
|
*/
|
|
G_CONST_RETURN gchar *
|
|
clutter_actor_get_name (ClutterActor *self)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
|
|
|
|
return self->priv->name;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_gid:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the unique id for @self.
|
|
*
|
|
* Return value: Globally unique value for this object instance.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
guint32
|
|
clutter_actor_get_gid (ClutterActor *self)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
return self->priv->id;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_depth:
|
|
* @self: a #ClutterActor
|
|
* @depth: Z co-ord
|
|
*
|
|
* Sets the Z co-ordinate of @self to @depth. The Units of which are dependant
|
|
* on the perspective setup.
|
|
*/
|
|
void
|
|
clutter_actor_set_depth (ClutterActor *self,
|
|
gint depth)
|
|
{
|
|
clutter_actor_set_depthu (self, CLUTTER_UNITS_FROM_DEVICE (depth));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_depthu:
|
|
* @self: a #ClutterActor
|
|
* @depth: Z co-ordinate, in #ClutterUnit<!-- -->s
|
|
*
|
|
* Sets the Z co-ordinate of @self to @depth in #ClutterUnit<!-- -->s, the
|
|
* units of which are dependant on the perspective setup.
|
|
*/
|
|
void
|
|
clutter_actor_set_depthu (ClutterActor *self,
|
|
ClutterUnit depth)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
if (priv->z != depth)
|
|
{
|
|
/* Sets Z value. - FIXME: should invert ?*/
|
|
priv->z = depth;
|
|
|
|
if (priv->parent_actor && CLUTTER_IS_CONTAINER (priv->parent_actor))
|
|
{
|
|
ClutterContainer *parent;
|
|
|
|
/* We need to resort the container stacking order as to
|
|
* correctly render alpha values.
|
|
*
|
|
* FIXME: This is sub optimal. maybe queue the the sort
|
|
* before stacking
|
|
*/
|
|
parent = CLUTTER_CONTAINER (priv->parent_actor);
|
|
clutter_container_sort_depth_order (parent);
|
|
}
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
clutter_actor_queue_redraw (self);
|
|
|
|
g_object_notify (G_OBJECT (self), "depth");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_depth:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* Retrieves the depth of @self.
|
|
*
|
|
* Return value: the depth of the actor
|
|
*/
|
|
gint
|
|
clutter_actor_get_depth (ClutterActor *self)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
|
|
|
|
return CLUTTER_UNITS_TO_DEVICE (self->priv->z);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_depthu:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* Retrieves the depth of @self.
|
|
*
|
|
* Return value: the depth of the actor, in #ClutterUnit<!-- -->s
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
ClutterUnit
|
|
clutter_actor_get_depthu (ClutterActor *self)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
|
|
|
|
return self->priv->z;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_rotationu:
|
|
* @self: a #ClutterActor
|
|
* @axis: the axis of rotation
|
|
* @angle: the angle of rotation
|
|
* @x: X coordinate of the rotation center, in #ClutterUnit<!-- -->s
|
|
* @y: Y coordinate of the rotation center, in #ClutterUnit<!-- -->s
|
|
* @z: Z coordinate of the rotation center, in #ClutterUnit<!-- -->s
|
|
*
|
|
* Sets the rotation angle of @self around the given axis.
|
|
*
|
|
* This function is the units based variant of clutter_actor_set_rotation().
|
|
*
|
|
* Since: 0.8
|
|
*/
|
|
void
|
|
clutter_actor_set_rotationu (ClutterActor *self,
|
|
ClutterRotateAxis axis,
|
|
gdouble angle,
|
|
ClutterUnit x,
|
|
ClutterUnit y,
|
|
ClutterUnit z)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_rotation_internal (self, axis,
|
|
CLUTTER_FLOAT_TO_FIXED (angle),
|
|
x, y, z);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_rotationx:
|
|
* @self: a #ClutterActor
|
|
* @axis: the axis of rotation
|
|
* @angle: the angle of rotation
|
|
* @x: X coordinate of the rotation center
|
|
* @y: Y coordinate of the rotation center
|
|
* @z: Z coordinate of the rotation center
|
|
*
|
|
* Sets the rotation angle of @self around the given axis.
|
|
*
|
|
* This function is the fixed point variant of clutter_actor_set_rotation().
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_rotationx (ClutterActor *self,
|
|
ClutterRotateAxis axis,
|
|
ClutterFixed angle,
|
|
gint x,
|
|
gint y,
|
|
gint z)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_rotation_internal (self, axis, angle,
|
|
CLUTTER_UNITS_FROM_DEVICE (x),
|
|
CLUTTER_UNITS_FROM_DEVICE (y),
|
|
CLUTTER_UNITS_FROM_DEVICE (z));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_rotation:
|
|
* @self: a #ClutterActor
|
|
* @axis: the axis of rotation
|
|
* @angle: the angle of rotation
|
|
* @x: X coordinate of the rotation center
|
|
* @y: Y coordinate of the rotation center
|
|
* @z: Z coordinate of the rotation center
|
|
*
|
|
* Sets the rotation angle of @self around the given axis.
|
|
*
|
|
* The rotation center coordinates used depend on the value of @axis:
|
|
* <itemizedlist>
|
|
* <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
|
|
* <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
|
|
* <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
|
|
* </itemizedlist>
|
|
*
|
|
* The rotation coordinates are relative to the anchor point of the
|
|
* actor, set using clutter_actor_set_anchor_point(). If no anchor
|
|
* point is set, the upper left corner is assumed as the origin.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_rotation (ClutterActor *self,
|
|
ClutterRotateAxis axis,
|
|
gdouble angle,
|
|
gint x,
|
|
gint y,
|
|
gint z)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_rotationx (self, axis,
|
|
CLUTTER_FLOAT_TO_FIXED (angle),
|
|
x, y, z);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_rotationu:
|
|
* @self: a #ClutterActor
|
|
* @axis: the axis of rotation
|
|
* @x: return value for the X coordinate of the center of rotation,
|
|
* in #ClutterUnit<!-- -->s
|
|
* @y: return value for the Y coordinate of the center of rotation,
|
|
* in #ClutterUnit<!-- -->s
|
|
* @z: return value for the Z coordinate of the center of rotation,
|
|
* in #ClutterUnit<!-- -->s
|
|
*
|
|
* Retrieves the angle and center of rotation on the given axis,
|
|
* set using clutter_actor_set_rotation().
|
|
*
|
|
* This function is the units based variant of clutter_actor_get_rotation().
|
|
*
|
|
* Return value: the angle of rotation
|
|
*
|
|
* Since: 0.8
|
|
*/
|
|
gdouble
|
|
clutter_actor_get_rotationu (ClutterActor *self,
|
|
ClutterRotateAxis axis,
|
|
ClutterUnit *x,
|
|
ClutterUnit *y,
|
|
ClutterUnit *z)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
gdouble retval = 0;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
priv = self->priv;
|
|
|
|
switch (axis)
|
|
{
|
|
case CLUTTER_X_AXIS:
|
|
retval = CLUTTER_FIXED_TO_DOUBLE (priv->rxang);
|
|
if (y)
|
|
*y = priv->rxy;
|
|
if (z)
|
|
*z = priv->rxz;
|
|
break;
|
|
|
|
case CLUTTER_Y_AXIS:
|
|
retval = CLUTTER_FIXED_TO_DOUBLE (priv->ryang);
|
|
if (x)
|
|
*x = priv->ryx;
|
|
if (z)
|
|
*z = priv->ryz;
|
|
break;
|
|
|
|
case CLUTTER_Z_AXIS:
|
|
retval = CLUTTER_FIXED_TO_DOUBLE (priv->rzang);
|
|
if (x)
|
|
*x = priv->rzx;
|
|
if (y)
|
|
*y = priv->rzy;
|
|
break;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_rotationx:
|
|
* @self: a #ClutterActor
|
|
* @axis: the axis of rotation
|
|
* @x: return value for the X coordinate of the center of rotation
|
|
* @y: return value for the Y coordinate of the center of rotation
|
|
* @z: return value for the Z coordinate of the center of rotation
|
|
*
|
|
* Retrieves the angle and center of rotation on the given axis,
|
|
* set using clutter_actor_set_rotation().
|
|
*
|
|
* This function is the fixed point variant of clutter_actor_get_rotation().
|
|
*
|
|
* Return value: the angle of rotation as a fixed point value.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
ClutterFixed
|
|
clutter_actor_get_rotationx (ClutterActor *self,
|
|
ClutterRotateAxis axis,
|
|
gint *x,
|
|
gint *y,
|
|
gint *z)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
ClutterFixed retval = 0;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
priv = self->priv;
|
|
|
|
switch (axis)
|
|
{
|
|
case CLUTTER_X_AXIS:
|
|
retval = priv->rxang;
|
|
if (y)
|
|
*y = CLUTTER_UNITS_TO_DEVICE (priv->rxy);
|
|
if (z)
|
|
*z = CLUTTER_UNITS_TO_DEVICE (priv->rxz);
|
|
break;
|
|
|
|
case CLUTTER_Y_AXIS:
|
|
retval = priv->ryang;
|
|
if (x)
|
|
*x = CLUTTER_UNITS_TO_DEVICE (priv->ryx);
|
|
if (z)
|
|
*z = CLUTTER_UNITS_TO_DEVICE (priv->ryz);
|
|
break;
|
|
|
|
case CLUTTER_Z_AXIS:
|
|
retval = priv->rzang;
|
|
if (x)
|
|
*x = CLUTTER_UNITS_TO_DEVICE (priv->rzx);
|
|
if (y)
|
|
*y = CLUTTER_UNITS_TO_DEVICE (priv->rzy);
|
|
break;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_rotation:
|
|
* @self: a #ClutterActor
|
|
* @axis: the axis of rotation
|
|
* @x: return value for the X coordinate of the center of rotation
|
|
* @y: return value for the Y coordinate of the center of rotation
|
|
* @z: return value for the Z coordinate of the center of rotation
|
|
*
|
|
* Retrieves the angle and center of rotation on the given axis,
|
|
* set using clutter_actor_set_angle().
|
|
*
|
|
* The coordinates of the center returned by this function depend on
|
|
* the axis passed.
|
|
*
|
|
* Return value: the angle of rotation.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
gdouble
|
|
clutter_actor_get_rotation (ClutterActor *self,
|
|
ClutterRotateAxis axis,
|
|
gint *x,
|
|
gint *y,
|
|
gint *z)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
|
|
|
|
return CLUTTER_FIXED_TO_FLOAT (clutter_actor_get_rotationx (self,
|
|
axis,
|
|
x, y, z));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_clipu:
|
|
* @self: A #ClutterActor
|
|
* @xoff: X offset of the clip rectangle, in #ClutterUnit<!-- -->s
|
|
* @yoff: Y offset of the clip rectangle, in #ClutterUnit<!-- -->s
|
|
* @width: Width of the clip rectangle, in #ClutterUnit<!-- -->s
|
|
* @height: Height of the clip rectangle, in #ClutterUnit<!-- -->s
|
|
*
|
|
* Unit-based variant of clutter_actor_set_clip()
|
|
*
|
|
* Sets clip area for @self. The clip area is always computed from the
|
|
* upper left corner of the actor, even if the anchor point is set
|
|
* otherwise.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_clipu (ClutterActor *self,
|
|
ClutterUnit xoff,
|
|
ClutterUnit yoff,
|
|
ClutterUnit width,
|
|
ClutterUnit height)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
priv->clip[0] = xoff;
|
|
priv->clip[1] = yoff;
|
|
priv->clip[2] = width;
|
|
priv->clip[3] = height;
|
|
|
|
priv->has_clip = TRUE;
|
|
|
|
g_object_notify (G_OBJECT (self), "has-clip");
|
|
g_object_notify (G_OBJECT (self), "clip");
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_clip:
|
|
* @self: A #ClutterActor
|
|
* @xoff: X offset of the clip rectangle, in pixels
|
|
* @yoff: Y offset of the clip rectangle, in pixels
|
|
* @width: Width of the clip rectangle, in pixels
|
|
* @height: Height of the clip rectangle, in pixels
|
|
*
|
|
* Sets clip area in pixels for @self. The clip area is always computed
|
|
* from the upper left corner of the actor, even if the anchor point is
|
|
* set otherwise.
|
|
*/
|
|
void
|
|
clutter_actor_set_clip (ClutterActor *self,
|
|
gint xoff,
|
|
gint yoff,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_clipu (self,
|
|
CLUTTER_UNITS_FROM_DEVICE (xoff),
|
|
CLUTTER_UNITS_FROM_DEVICE (yoff),
|
|
CLUTTER_UNITS_FROM_DEVICE (width),
|
|
CLUTTER_UNITS_FROM_DEVICE (height));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_remove_clip
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Removes clip area from @self.
|
|
*/
|
|
void
|
|
clutter_actor_remove_clip (ClutterActor *self)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
self->priv->has_clip = FALSE;
|
|
|
|
g_object_notify (G_OBJECT (self), "has-clip");
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_has_clip:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* Determines whether the actor has a clip area set or not.
|
|
*
|
|
* Return value: %TRUE if the actor has a clip area set.
|
|
*
|
|
* Since: 0.1.1
|
|
*/
|
|
gboolean
|
|
clutter_actor_has_clip (ClutterActor *self)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
|
|
|
return self->priv->has_clip;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_clipu:
|
|
* @self: a #ClutterActor
|
|
* @xoff: return location for the X offset of the clip rectangle, or %NULL
|
|
* @yoff: return location for the Y offset of the clip rectangle, or %NULL
|
|
* @width: return location for the width of the clip rectangle, or %NULL
|
|
* @height: return location for the height of the clip rectangle, or %NULL
|
|
*
|
|
* Unit-based variant of clutter_actor_get_clip().
|
|
*
|
|
* Gets the clip area for @self, in #ClutterUnit<!-- -->s.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_get_clipu (ClutterActor *self,
|
|
ClutterUnit *xoff,
|
|
ClutterUnit *yoff,
|
|
ClutterUnit *width,
|
|
ClutterUnit *height)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
if (!priv->has_clip)
|
|
return;
|
|
|
|
if (xoff)
|
|
*xoff = priv->clip[0];
|
|
|
|
if (yoff)
|
|
*yoff = priv->clip[1];
|
|
|
|
if (width)
|
|
*width = priv->clip[2];
|
|
|
|
if (height)
|
|
*height = priv->clip[3];
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_clip:
|
|
* @self: a #ClutterActor
|
|
* @xoff: return location for the X offset of the clip rectangle, or %NULL
|
|
* @yoff: return location for the Y offset of the clip rectangle, or %NULL
|
|
* @width: return location for the width of the clip rectangle, or %NULL
|
|
* @height: return location for the height of the clip rectangle, or %NULL
|
|
*
|
|
* Gets the clip area for @self, in pixels.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_get_clip (ClutterActor *self,
|
|
gint *xoff,
|
|
gint *yoff,
|
|
gint *width,
|
|
gint *height)
|
|
{
|
|
struct clipu { ClutterUnit x, y, width, height; } c = { 0, };
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_get_clipu (self, &c.x, &c.y, &c.width, &c.height);
|
|
|
|
if (xoff)
|
|
*xoff = CLUTTER_UNITS_TO_DEVICE (c.x);
|
|
|
|
if (yoff)
|
|
*yoff = CLUTTER_UNITS_TO_DEVICE (c.y);
|
|
|
|
if (width)
|
|
*width = CLUTTER_UNITS_TO_DEVICE (c.width);
|
|
|
|
if (height)
|
|
*height = CLUTTER_UNITS_TO_DEVICE (c.height);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_parent:
|
|
* @self: A #ClutterActor
|
|
* @parent: A new #ClutterActor parent
|
|
*
|
|
* Sets the parent of @self to @parent. The opposite function is
|
|
* clutter_actor_unparent().
|
|
*
|
|
* This function should not be used by applications, but by custom
|
|
* 'composite' actor subclasses.
|
|
*/
|
|
void
|
|
clutter_actor_set_parent (ClutterActor *self,
|
|
ClutterActor *parent)
|
|
{
|
|
ClutterMainContext *clutter_context;
|
|
|
|
clutter_context = clutter_context_get_default ();
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (parent));
|
|
g_return_if_fail (self != parent);
|
|
g_return_if_fail (clutter_context != NULL);
|
|
|
|
if (self->priv->parent_actor != NULL)
|
|
{
|
|
g_warning ("Cannot set a parent on an actor which has a parent.\n"
|
|
"You must use clutter_actor_unparent() first.\n");
|
|
|
|
return;
|
|
}
|
|
|
|
if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)
|
|
{
|
|
g_warning ("Cannot set a parent on a toplevel actor\n");
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
g_object_ref_sink (self);
|
|
self->priv->parent_actor = parent;
|
|
g_signal_emit (self, actor_signals[PARENT_SET], 0, NULL);
|
|
|
|
if (CLUTTER_ACTOR_IS_REALIZED (self->priv->parent_actor))
|
|
clutter_actor_realize (self);
|
|
|
|
if (self->priv->show_on_set_parent)
|
|
clutter_actor_show (self);
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self->priv->parent_actor) &&
|
|
CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
{
|
|
clutter_actor_queue_redraw (self);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_parent:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the parent of @self.
|
|
*
|
|
* Return Value: The #ClutterActor parent, or %NULL if no parent is set
|
|
*/
|
|
ClutterActor *
|
|
clutter_actor_get_parent (ClutterActor *self)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
|
|
|
|
return self->priv->parent_actor;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_unparent:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* This function should not be used in applications. It should be called by
|
|
* implementations of container actors, to dissociate a child from the
|
|
* container.
|
|
*
|
|
* Since: 0.1.1
|
|
*/
|
|
void
|
|
clutter_actor_unparent (ClutterActor *self)
|
|
{
|
|
ClutterActor *old_parent;
|
|
ClutterMainContext *clutter_context;
|
|
|
|
clutter_context = clutter_context_get_default ();
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
g_return_if_fail (clutter_context != NULL);
|
|
|
|
if (self->priv->parent_actor == NULL)
|
|
return;
|
|
|
|
/* just hide the actor if we are reparenting it */
|
|
if (CLUTTER_ACTOR_IS_REALIZED (self))
|
|
{
|
|
if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT)
|
|
clutter_actor_hide (self);
|
|
else
|
|
clutter_actor_unrealize (self);
|
|
}
|
|
|
|
old_parent = self->priv->parent_actor;
|
|
self->priv->parent_actor = NULL;
|
|
g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
|
|
|
|
|
|
g_object_unref (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_reparent:
|
|
* @self: a #ClutterActor
|
|
* @new_parent: the new #ClutterActor parent
|
|
*
|
|
* This function resets the parent actor of @self. It is
|
|
* logically equivalent to calling clutter_actor_unparent()
|
|
* and clutter_actor_set_parent().
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
void
|
|
clutter_actor_reparent (ClutterActor *self,
|
|
ClutterActor *new_parent)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
|
|
g_return_if_fail (self != new_parent);
|
|
|
|
if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)
|
|
{
|
|
g_warning ("Cannot set a parent on a toplevel actor\n");
|
|
return;
|
|
}
|
|
|
|
priv = self->priv;
|
|
|
|
if (priv->parent_actor != new_parent)
|
|
{
|
|
ClutterActor *old_parent;
|
|
|
|
/* if the actor and the parent have already been realized,
|
|
* mark the actor as reparenting, so that clutter_actor_unparent()
|
|
* just hides the actor instead of unrealize it.
|
|
*/
|
|
if (CLUTTER_ACTOR_IS_REALIZED (self) &&
|
|
CLUTTER_ACTOR_IS_REALIZED (new_parent))
|
|
{
|
|
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_REPARENT);
|
|
}
|
|
|
|
old_parent = priv->parent_actor;
|
|
|
|
g_object_ref (self);
|
|
|
|
/* FIXME: below assumes only containers can reparent */
|
|
if (CLUTTER_IS_CONTAINER (priv->parent_actor))
|
|
clutter_container_remove_actor (CLUTTER_CONTAINER (priv->parent_actor),
|
|
self);
|
|
else
|
|
priv->parent_actor = NULL;
|
|
|
|
if (CLUTTER_IS_CONTAINER (new_parent))
|
|
clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
|
|
else
|
|
priv->parent_actor = new_parent;
|
|
|
|
g_object_unref (self);
|
|
|
|
if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IN_REPARENT)
|
|
{
|
|
CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_IN_REPARENT);
|
|
|
|
clutter_actor_queue_redraw (self);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* clutter_actor_raise:
|
|
* @self: A #ClutterActor
|
|
* @below: A #ClutterActor to raise above.
|
|
*
|
|
* Puts @self above @below.
|
|
* Both actors must have the same parent.
|
|
*/
|
|
void
|
|
clutter_actor_raise (ClutterActor *self,
|
|
ClutterActor *below)
|
|
{
|
|
ClutterActor *parent;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
parent = clutter_actor_get_parent (self);
|
|
if (!parent)
|
|
{
|
|
g_warning ("Actor of type %s is not inside a container",
|
|
g_type_name (G_OBJECT_TYPE (self)));
|
|
return;
|
|
}
|
|
|
|
if (below)
|
|
{
|
|
if (parent != clutter_actor_get_parent (below))
|
|
{
|
|
g_warning ("Actor of type %s is not in the same "
|
|
"container of actor of type %s",
|
|
g_type_name (G_OBJECT_TYPE (self)),
|
|
g_type_name (G_OBJECT_TYPE (below)));
|
|
return;
|
|
}
|
|
}
|
|
|
|
clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
clutter_actor_queue_redraw (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_lower:
|
|
* @self: A #ClutterActor
|
|
* @above: A #ClutterActor to lower below
|
|
*
|
|
* Puts @self below @above.
|
|
* Both actors must have the same parent.
|
|
*/
|
|
void
|
|
clutter_actor_lower (ClutterActor *self,
|
|
ClutterActor *above)
|
|
{
|
|
ClutterActor *parent;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR(self));
|
|
|
|
parent = clutter_actor_get_parent (self);
|
|
if (!parent)
|
|
{
|
|
g_warning ("Actor of type %s is not inside a container",
|
|
g_type_name (G_OBJECT_TYPE (self)));
|
|
return;
|
|
}
|
|
|
|
if (above)
|
|
{
|
|
if (parent != clutter_actor_get_parent (above))
|
|
{
|
|
g_warning ("Actor of type %s is not in the same "
|
|
"container of actor of type %s",
|
|
g_type_name (G_OBJECT_TYPE (self)),
|
|
g_type_name (G_OBJECT_TYPE (above)));
|
|
return;
|
|
}
|
|
}
|
|
|
|
clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
clutter_actor_queue_redraw (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_raise_top:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Raises @self to the top.
|
|
*/
|
|
void
|
|
clutter_actor_raise_top (ClutterActor *self)
|
|
{
|
|
clutter_actor_raise (self, NULL);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_lower_bottom:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Lowers @self to the bottom.
|
|
*/
|
|
void
|
|
clutter_actor_lower_bottom (ClutterActor *self)
|
|
{
|
|
clutter_actor_lower (self, NULL);
|
|
}
|
|
|
|
/*
|
|
* Event handling
|
|
*/
|
|
|
|
/**
|
|
* clutter_actor_event:
|
|
* @actor: a #ClutterActor
|
|
* @event: a #ClutterEvent
|
|
* @capture: TRUE if event in in capture phase, FALSE otherwise.
|
|
*
|
|
* This function is used to emit an event on the main stage.
|
|
* You should rarely need to use this function, except for
|
|
* synthetising events.
|
|
*
|
|
* Return value: the return value from the signal emission: %TRUE
|
|
* if the actor handled the event, or %FALSE if the event was
|
|
* not handled
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
gboolean
|
|
clutter_actor_event (ClutterActor *actor,
|
|
ClutterEvent *event,
|
|
gboolean capture)
|
|
{
|
|
gboolean retval = FALSE;
|
|
gint signal_num = -1;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
g_object_ref (actor);
|
|
|
|
if (capture)
|
|
{
|
|
g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
|
|
event,
|
|
&retval);
|
|
goto out;
|
|
}
|
|
|
|
g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
|
|
|
|
if (!retval)
|
|
{
|
|
switch (event->type)
|
|
{
|
|
case CLUTTER_NOTHING:
|
|
break;
|
|
case CLUTTER_BUTTON_PRESS:
|
|
signal_num = BUTTON_PRESS_EVENT;
|
|
break;
|
|
case CLUTTER_BUTTON_RELEASE:
|
|
signal_num = BUTTON_RELEASE_EVENT;
|
|
break;
|
|
case CLUTTER_SCROLL:
|
|
signal_num = SCROLL_EVENT;
|
|
break;
|
|
case CLUTTER_KEY_PRESS:
|
|
signal_num = KEY_PRESS_EVENT;
|
|
break;
|
|
case CLUTTER_KEY_RELEASE:
|
|
signal_num = KEY_RELEASE_EVENT;
|
|
break;
|
|
case CLUTTER_MOTION:
|
|
signal_num = MOTION_EVENT;
|
|
break;
|
|
case CLUTTER_ENTER:
|
|
signal_num = ENTER_EVENT;
|
|
break;
|
|
case CLUTTER_LEAVE:
|
|
signal_num = LEAVE_EVENT;
|
|
break;
|
|
case CLUTTER_DELETE:
|
|
case CLUTTER_DESTROY_NOTIFY:
|
|
case CLUTTER_CLIENT_MESSAGE:
|
|
default:
|
|
signal_num = -1;
|
|
break;
|
|
}
|
|
|
|
if (signal_num != -1)
|
|
g_signal_emit (actor, actor_signals[signal_num], 0,
|
|
event, &retval);
|
|
}
|
|
|
|
out:
|
|
g_object_unref (actor);
|
|
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_reactive:
|
|
* @actor: a #ClutterActor
|
|
* @reactive: whether the actor should be reactive to events
|
|
*
|
|
* Sets @actor as reactive. Reactive actors will receive events.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_reactive (ClutterActor *actor,
|
|
gboolean reactive)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
|
|
|
if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
|
|
return;
|
|
|
|
if (reactive)
|
|
CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
|
|
else
|
|
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
|
|
|
|
g_object_notify (G_OBJECT (actor), "reactive");
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_reactive:
|
|
* @actor: a #ClutterActor
|
|
*
|
|
* Checks whether @actor is marked as reactive.
|
|
*
|
|
* Return value: %TRUE if the actor is reactive
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
gboolean
|
|
clutter_actor_get_reactive (ClutterActor *actor)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
|
|
|
|
return CLUTTER_ACTOR_IS_REACTIVE (actor);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_anchor_point:
|
|
* @self: a #ClutterActor
|
|
* @anchor_x: X coordinate of the anchor point
|
|
* @anchor_y: Y coordinate of the anchor point
|
|
*
|
|
* Sets an anchor point for the @actor. The anchor point is a point in the
|
|
* coordinate space of an actor to which the actor position within its
|
|
* parent is relative; the default is (0, 0), i.e. the top-left corner of
|
|
* the actor.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_anchor_point (ClutterActor *self,
|
|
gint anchor_x,
|
|
gint anchor_y)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_set_anchor_pointu (self,
|
|
CLUTTER_UNITS_FROM_DEVICE (anchor_x),
|
|
CLUTTER_UNITS_FROM_DEVICE (anchor_y));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_move_anchor_point:
|
|
* @self: a #ClutterActor
|
|
* @anchor_x: X coordinate of the anchor point
|
|
* @anchor_y: Y coordinate of the anchor point
|
|
*
|
|
* Sets an anchor point for the @actor, and adjusts the actor postion so
|
|
* that the relative position of the actor toward its parent remains the
|
|
* same.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_move_anchor_point (ClutterActor *self,
|
|
gint anchor_x,
|
|
gint anchor_y)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
ClutterUnit ax = CLUTTER_UNITS_FROM_DEVICE (anchor_x);
|
|
ClutterUnit ay = CLUTTER_UNITS_FROM_DEVICE (anchor_y);
|
|
ClutterUnit dx;
|
|
ClutterUnit dy;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
dx = priv->anchor_x - ax;
|
|
dy = priv->anchor_y - ay;
|
|
|
|
priv->anchor_x = ax;
|
|
priv->anchor_y = ay;
|
|
|
|
priv->coords.x1 -= dx;
|
|
priv->coords.x2 -= dx;
|
|
priv->coords.y1 -= dy;
|
|
priv->coords.y2 -= dy;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_anchor_point:
|
|
* @self: a #ClutterActor
|
|
* @anchor_x: return location for the X coordinate of the anchor point
|
|
* @anchor_y: return location for the y coordinate of the anchor point
|
|
*
|
|
* Gets the current anchor point of the @actor in pixels.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_get_anchor_point (ClutterActor *self,
|
|
gint *anchor_x,
|
|
gint *anchor_y)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
if (anchor_x)
|
|
*anchor_x = CLUTTER_UNITS_TO_DEVICE (priv->anchor_x);
|
|
|
|
if (anchor_y)
|
|
*anchor_y = CLUTTER_UNITS_TO_DEVICE (priv->anchor_y);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_anchor_pointu:
|
|
* @self: a #ClutterActor
|
|
* @anchor_x: X coordinate of the anchor point, in #ClutterUnit<!-- -->s
|
|
* @anchor_y: Y coordinate of the anchor point, in #ClutterUnit<!-- -->s
|
|
*
|
|
* Sets an anchor point for @self. The anchor point is a point in the
|
|
* coordinate space of an actor to which the actor position within its
|
|
* parent is relative; the default is (0, 0), i.e. the top-left corner
|
|
* of the actor.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_anchor_pointu (ClutterActor *self,
|
|
ClutterUnit anchor_x,
|
|
ClutterUnit anchor_y)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
if (priv->anchor_x != anchor_x)
|
|
{
|
|
priv->anchor_x = anchor_x;
|
|
g_object_notify (G_OBJECT (self), "anchor-x");
|
|
}
|
|
|
|
if (priv->anchor_y != anchor_y)
|
|
{
|
|
priv->anchor_y = anchor_y;
|
|
g_object_notify (G_OBJECT (self), "anchor-y");
|
|
}
|
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_move_anchor_pointu:
|
|
* @self: a #ClutterActor
|
|
* @anchor_x: X coordinate of the anchor point
|
|
* @anchor_y: Y coordinate of the anchor point
|
|
*
|
|
* Sets an anchor point for the actor, and adjusts the actor postion so that
|
|
* the relative position of the actor toward its parent remains the same.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_move_anchor_pointu (ClutterActor *self,
|
|
ClutterUnit anchor_x,
|
|
ClutterUnit anchor_y)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
ClutterUnit dx;
|
|
ClutterUnit dy;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
dx = anchor_x - priv->anchor_x;
|
|
dy = anchor_y - priv->anchor_y;
|
|
|
|
priv->anchor_x = anchor_x;
|
|
priv->anchor_y = anchor_y;
|
|
|
|
priv->coords.x1 -= dx;
|
|
priv->coords.x2 -= dx;
|
|
priv->coords.y1 -= dy;
|
|
priv->coords.y2 -= dy;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_anchor_pointu:
|
|
* @self: a #ClutterActor
|
|
* @anchor_x: return location for the X coordinace of the anchor point
|
|
* @anchor_y: return location for the X coordinace of the anchor point
|
|
*
|
|
* Gets the current anchor point of the @actor in #ClutterUnit<!-- -->s.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_get_anchor_pointu (ClutterActor *self,
|
|
ClutterUnit *anchor_x,
|
|
ClutterUnit *anchor_y)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
if (anchor_x)
|
|
*anchor_x = priv->anchor_x;
|
|
|
|
if (anchor_y)
|
|
*anchor_y = priv->anchor_y;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_move_anchor_point_from_gravity:
|
|
* @self: a #ClutterActor
|
|
* @gravity: #ClutterGravity.
|
|
*
|
|
* Sets an anchor point on the actor based on the given gravity, adjusting the
|
|
* actor postion so that its relative position within its parent remains
|
|
* unchanged.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_move_anchor_point_from_gravity (ClutterActor *self,
|
|
ClutterGravity gravity)
|
|
{
|
|
ClutterUnit ax, ay, dx, dy;
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
ax = priv->anchor_x;
|
|
ay = priv->anchor_y;
|
|
|
|
clutter_actor_set_anchor_point_from_gravity (self, gravity);
|
|
|
|
dx = ax - priv->anchor_x;
|
|
dy = ay - priv->anchor_y;
|
|
|
|
priv->coords.x1 -= dx;
|
|
priv->coords.x2 -= dx;
|
|
priv->coords.y1 -= dy;
|
|
priv->coords.y2 -= dy;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_anchor_point_from_gravity:
|
|
* @self: a #ClutterActor
|
|
* @gravity: #ClutterGravity.
|
|
*
|
|
* Sets an anchor point on the actor, based on the given gravity (this is a
|
|
* convenience function wrapping clutter_actor_set_anchor_point()).
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_anchor_point_from_gravity (ClutterActor *self,
|
|
ClutterGravity gravity)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
ClutterActorBox box;
|
|
ClutterUnit w, h, x, y;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
x = 0;
|
|
y = 0;
|
|
w = box.x2 - box.x1;
|
|
h = box.y2 - box.y1;
|
|
|
|
switch (gravity)
|
|
{
|
|
case CLUTTER_GRAVITY_NORTH:
|
|
x = w / 2;
|
|
break;
|
|
case CLUTTER_GRAVITY_SOUTH:
|
|
x = w / 2;
|
|
y = h;
|
|
break;
|
|
case CLUTTER_GRAVITY_EAST:
|
|
x = w;
|
|
y = h / 2;
|
|
break;
|
|
case CLUTTER_GRAVITY_NORTH_EAST:
|
|
x = w;
|
|
break;
|
|
case CLUTTER_GRAVITY_SOUTH_EAST:
|
|
x = w;
|
|
y = h;
|
|
break;
|
|
case CLUTTER_GRAVITY_SOUTH_WEST:
|
|
y = h;
|
|
break;
|
|
case CLUTTER_GRAVITY_WEST:
|
|
y = h / 2;
|
|
break;
|
|
case CLUTTER_GRAVITY_CENTER:
|
|
x = w / 2;
|
|
y = h / 2;
|
|
break;
|
|
case CLUTTER_GRAVITY_NONE:
|
|
case CLUTTER_GRAVITY_NORTH_WEST:
|
|
break;
|
|
}
|
|
|
|
clutter_actor_set_anchor_pointu (self, x, y);
|
|
}
|
|
|
|
typedef enum
|
|
{
|
|
PARSE_X,
|
|
PARSE_Y,
|
|
PARSE_WIDTH,
|
|
PARSE_HEIGHT,
|
|
PARSE_ANCHOR_X,
|
|
PARSE_ANCHOR_Y
|
|
} ParseDimension;
|
|
|
|
static ClutterUnit
|
|
parse_units (ClutterActor *self,
|
|
ParseDimension dimension,
|
|
JsonNode *node)
|
|
{
|
|
GValue value = { 0, };
|
|
ClutterUnit retval = 0;
|
|
|
|
if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
|
|
return 0;
|
|
|
|
json_node_get_value (node, &value);
|
|
|
|
if (G_VALUE_HOLDS (&value, G_TYPE_INT))
|
|
{
|
|
gint pixels = g_value_get_int (&value);
|
|
|
|
retval = CLUTTER_UNITS_FROM_DEVICE (pixels);
|
|
}
|
|
else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
|
|
{
|
|
gint64 val;
|
|
gchar *end;
|
|
|
|
val = g_ascii_strtoll (g_value_get_string (&value), &end, 10);
|
|
|
|
/* skip whitespace */
|
|
while (g_ascii_isspace (*end))
|
|
end++;
|
|
|
|
/* assume pixels */
|
|
if (*end == '\0')
|
|
{
|
|
retval = CLUTTER_UNITS_FROM_DEVICE (val);
|
|
goto out;
|
|
}
|
|
|
|
if (strcmp (end, "px") == 0)
|
|
{
|
|
retval = CLUTTER_UNITS_FROM_DEVICE (val);
|
|
goto out;
|
|
}
|
|
|
|
if (strcmp (end, "mm") == 0)
|
|
{
|
|
retval = CLUTTER_UNITS_FROM_MM (val);
|
|
goto out;
|
|
}
|
|
|
|
if (strcmp (end, "pt") == 0)
|
|
{
|
|
retval = CLUTTER_UNITS_FROM_POINTS (val);
|
|
goto out;
|
|
}
|
|
|
|
if (end[0] == '%' && end[1] == '\0')
|
|
{
|
|
if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)
|
|
{
|
|
g_warning ("Unable to set percentage of %s on a top-level "
|
|
"actor of type `%s'",
|
|
(dimension == PARSE_X ||
|
|
dimension == PARSE_WIDTH ||
|
|
dimension == PARSE_ANCHOR_X) ? "width" : "height",
|
|
g_type_name (G_OBJECT_TYPE (self)));
|
|
retval = 0;
|
|
goto out;
|
|
}
|
|
|
|
if (dimension == PARSE_X ||
|
|
dimension == PARSE_WIDTH ||
|
|
dimension == PARSE_ANCHOR_X)
|
|
retval = CLUTTER_UNITS_FROM_STAGE_WIDTH_PERCENTAGE (val);
|
|
else
|
|
retval = CLUTTER_UNITS_FROM_STAGE_HEIGHT_PERCENTAGE (val);
|
|
|
|
goto out;
|
|
}
|
|
|
|
g_warning ("Invalid value `%s': integers, strings or floating point "
|
|
"values can be used for the x, y, width and height "
|
|
"properties. Valid modifiers for strings are `px', 'mm' "
|
|
"and '%%'.",
|
|
g_value_get_string (&value));
|
|
|
|
retval = 0;
|
|
}
|
|
else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
|
|
{
|
|
gint val;
|
|
|
|
if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)
|
|
{
|
|
g_warning ("Unable to set percentage of %s on a top-level "
|
|
"actor of type `%s'",
|
|
(dimension == PARSE_X || dimension == PARSE_WIDTH) ? "width"
|
|
: "height",
|
|
g_type_name (G_OBJECT_TYPE (self)));
|
|
retval = 0;
|
|
goto out;
|
|
}
|
|
|
|
val = CLAMP (g_value_get_double (&value) * 100, 0, 100);
|
|
|
|
if (dimension == PARSE_X ||
|
|
dimension == PARSE_WIDTH ||
|
|
dimension == PARSE_ANCHOR_X)
|
|
retval = CLUTTER_UNITS_FROM_STAGE_WIDTH_PERCENTAGE (val);
|
|
else
|
|
retval = CLUTTER_UNITS_FROM_STAGE_HEIGHT_PERCENTAGE (val);
|
|
}
|
|
else
|
|
{
|
|
g_warning ("Invalid value of type `%s': integers, strings of floating "
|
|
"point values can be used for the x, y, width, height "
|
|
"anchor-x and anchor-y properties.",
|
|
g_type_name (G_VALUE_TYPE (&value)));
|
|
}
|
|
|
|
out:
|
|
g_value_unset (&value);
|
|
|
|
return retval;
|
|
}
|
|
|
|
typedef struct {
|
|
ClutterRotateAxis axis;
|
|
|
|
ClutterFixed angle;
|
|
|
|
ClutterUnit center_x;
|
|
ClutterUnit center_y;
|
|
ClutterUnit center_z;
|
|
} RotationInfo;
|
|
|
|
static inline gboolean
|
|
parse_rotation_array (ClutterActor *actor,
|
|
JsonArray *array,
|
|
RotationInfo *info)
|
|
{
|
|
JsonNode *element;
|
|
|
|
if (json_array_get_length (array) != 2)
|
|
return FALSE;
|
|
|
|
/* angle */
|
|
element = json_array_get_element (array, 0);
|
|
if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
|
|
info->angle = CLUTTER_FLOAT_TO_FIXED (json_node_get_double (element));
|
|
else
|
|
return FALSE;
|
|
|
|
/* center */
|
|
element = json_array_get_element (array, 1);
|
|
if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
|
|
{
|
|
JsonArray *center = json_node_get_array (element);
|
|
|
|
if (json_array_get_length (center) != 2)
|
|
return FALSE;
|
|
|
|
switch (info->axis)
|
|
{
|
|
case CLUTTER_X_AXIS:
|
|
info->center_y = parse_units (actor, PARSE_Y,
|
|
json_array_get_element (center, 0));
|
|
info->center_z = parse_units (actor, PARSE_Y,
|
|
json_array_get_element (center, 1));
|
|
return TRUE;
|
|
|
|
case CLUTTER_Y_AXIS:
|
|
info->center_x = parse_units (actor, PARSE_X,
|
|
json_array_get_element (center, 0));
|
|
info->center_z = parse_units (actor, PARSE_X,
|
|
json_array_get_element (center, 1));
|
|
return TRUE;
|
|
|
|
case CLUTTER_Z_AXIS:
|
|
info->center_x = parse_units (actor, PARSE_X,
|
|
json_array_get_element (center, 0));
|
|
info->center_y = parse_units (actor, PARSE_Y,
|
|
json_array_get_element (center, 1));
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
parse_rotation (ClutterActor *actor,
|
|
JsonNode *node,
|
|
RotationInfo *info)
|
|
{
|
|
JsonArray *array;
|
|
guint len, i;
|
|
gboolean retval = FALSE;
|
|
|
|
if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
|
|
{
|
|
g_warning ("Invalid node of type `%s' found, expecting an array",
|
|
json_node_type_name (node));
|
|
return FALSE;
|
|
}
|
|
|
|
array = json_node_get_array (node);
|
|
len = json_array_get_length (array);
|
|
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
JsonNode *element = json_array_get_element (array, i);
|
|
JsonObject *object;
|
|
JsonNode *member;
|
|
|
|
if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
|
|
{
|
|
g_warning ("Invalid node of type `%s' found, expecting an object",
|
|
json_node_type_name (element));
|
|
return FALSE;
|
|
}
|
|
|
|
object = json_node_get_object (element);
|
|
|
|
if (json_object_has_member (object, "x-axis"))
|
|
{
|
|
member = json_object_get_member (object, "x-axis");
|
|
|
|
info->axis = CLUTTER_X_AXIS;
|
|
|
|
if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
|
|
{
|
|
info->angle = json_node_get_double (member);
|
|
retval = TRUE;
|
|
}
|
|
else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
|
|
retval = parse_rotation_array (actor,
|
|
json_node_get_array (member),
|
|
info);
|
|
else
|
|
retval = FALSE;
|
|
}
|
|
else if (json_object_has_member (object, "y-axis"))
|
|
{
|
|
member = json_object_get_member (object, "y-axis");
|
|
|
|
info->axis = CLUTTER_Y_AXIS;
|
|
|
|
if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
|
|
{
|
|
info->angle = json_node_get_double (member);
|
|
retval = TRUE;
|
|
}
|
|
else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
|
|
retval = parse_rotation_array (actor,
|
|
json_node_get_array (member),
|
|
info);
|
|
else
|
|
retval = FALSE;
|
|
}
|
|
else if (json_object_has_member (object, "z-axis"))
|
|
{
|
|
member = json_object_get_member (object, "z-axis");
|
|
|
|
info->axis = CLUTTER_Z_AXIS;
|
|
|
|
if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
|
|
{
|
|
info->angle = json_node_get_double (member);
|
|
retval = TRUE;
|
|
}
|
|
else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
|
|
retval = parse_rotation_array (actor,
|
|
json_node_get_array (member),
|
|
info);
|
|
else
|
|
retval = FALSE;
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static gboolean
|
|
clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
|
|
ClutterScript *script,
|
|
GValue *value,
|
|
const gchar *name,
|
|
JsonNode *node)
|
|
{
|
|
ClutterActor *actor = CLUTTER_ACTOR (scriptable);
|
|
gboolean retval = FALSE;
|
|
|
|
if ((name[0] == 'x' && name[1] == '\0') ||
|
|
(name[0] == 'y' && name[1] == '\0') ||
|
|
(strcmp (name, "width") == 0) ||
|
|
(strcmp (name, "height") == 0) ||
|
|
(strcmp (name, "anchor_x") == 0) ||
|
|
(strcmp (name, "anchor_y") == 0))
|
|
{
|
|
ClutterUnit units;
|
|
ParseDimension dimension;
|
|
|
|
if (name[0] == 'x')
|
|
dimension = PARSE_X;
|
|
else if (name[0] == 'y')
|
|
dimension = PARSE_Y;
|
|
else if (name[0] == 'w')
|
|
dimension = PARSE_WIDTH;
|
|
else if (name[0] == 'h')
|
|
dimension = PARSE_HEIGHT;
|
|
else if (name[0] == 'a' && name[7] == 'x')
|
|
dimension = PARSE_ANCHOR_X;
|
|
else if (name[0] == 'a' && name[7] == 'y')
|
|
dimension = PARSE_ANCHOR_Y;
|
|
else
|
|
return FALSE;
|
|
|
|
units = parse_units (actor, dimension, node);
|
|
|
|
/* convert back to pixels: all properties are pixel-based */
|
|
g_value_init (value, G_TYPE_INT);
|
|
g_value_set_int (value, CLUTTER_UNITS_TO_DEVICE (units));
|
|
|
|
retval = TRUE;
|
|
}
|
|
else if (strcmp (name, "rotation") == 0)
|
|
{
|
|
RotationInfo *info;
|
|
|
|
info = g_slice_new0 (RotationInfo);
|
|
retval = parse_rotation (actor, node, info);
|
|
|
|
if (retval)
|
|
{
|
|
g_value_init (value, G_TYPE_POINTER);
|
|
g_value_set_pointer (value, info);
|
|
}
|
|
else
|
|
g_slice_free (RotationInfo, info);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static void
|
|
clutter_actor_set_custom_property (ClutterScriptable *scriptable,
|
|
ClutterScript *script,
|
|
const gchar *name,
|
|
const GValue *value)
|
|
{
|
|
CLUTTER_NOTE (SCRIPT, "in ClutterActor::set_custom_property('%s')", name);
|
|
|
|
if (strcmp (name, "rotation") == 0)
|
|
{
|
|
RotationInfo *info;
|
|
|
|
if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
|
|
return;
|
|
|
|
info = g_value_get_pointer (value);
|
|
|
|
clutter_actor_set_rotation_internal (CLUTTER_ACTOR (scriptable),
|
|
info->axis, info->angle,
|
|
info->center_x,
|
|
info->center_y,
|
|
info->center_z);
|
|
|
|
g_slice_free (RotationInfo, info);
|
|
}
|
|
else
|
|
g_object_set_property (G_OBJECT (scriptable), name, value);
|
|
}
|
|
|
|
static void
|
|
clutter_scriptable_iface_init (ClutterScriptableIface *iface)
|
|
{
|
|
iface->parse_custom_node = clutter_actor_parse_custom_node;
|
|
iface->set_custom_property = clutter_actor_set_custom_property;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_transform_stage_point
|
|
* @self: A #ClutterActor
|
|
* @x: x screen coordinate of the point to unproject, in #ClutterUnit<!-- -->s
|
|
* @y: y screen coordinate of the point to unproject, in #ClutterUnit<!-- -->s
|
|
* @x_out: return location for the unprojected x coordinance, in
|
|
* #ClutterUnit<!-- -->s
|
|
* @y_out: return location for the unprojected y coordinance, in
|
|
* #ClutterUnit<!-- -->s
|
|
*
|
|
* This function translates screen coordinates (@x, @y) to
|
|
* coordinates relative to the actor. For example, it can be used to translate
|
|
* screen events from global screen coordinates into actor-local coordinates.
|
|
*
|
|
* The conversion can fail, notably if the transform stack results in the
|
|
* actor being projected on the screen as a mere line.
|
|
*
|
|
* The conversion should not be expected to be pixel-perfect due to the
|
|
* nature of the operation. In general the error grows when the skewing
|
|
* of the actor rectangle on screen increases.
|
|
*
|
|
* Note: This function is fairly computationally intensive.
|
|
*
|
|
* Return value: %TRUE if conversion was successful.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
gboolean
|
|
clutter_actor_transform_stage_point (ClutterActor *self,
|
|
ClutterUnit x,
|
|
ClutterUnit y,
|
|
ClutterUnit *x_out,
|
|
ClutterUnit *y_out)
|
|
{
|
|
ClutterVertex v[4];
|
|
ClutterFixed ST[3][3];
|
|
ClutterFixed RQ[3][3];
|
|
int du, dv, xi, yi;
|
|
ClutterFixed xf, yf, wf, px, py, det;
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
|
|
|
priv = self->priv;
|
|
|
|
/*
|
|
* This implementation is based on the quad -> quad projection algorithm
|
|
* described by Paul Heckbert in
|
|
*
|
|
* http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
|
|
*
|
|
* and the sample implementaion at http://www.cs.cmu.edu/~ph/src/texfund/.
|
|
*
|
|
* Our texture is a rectangle with origin [0,0], so we are mapping from quad
|
|
* to rectangle only, which significantly simplifies things; the function
|
|
* calls have been unrolled, and most of the math is done in fixed point.
|
|
*/
|
|
|
|
clutter_actor_get_vertices (self, v);
|
|
|
|
/*
|
|
* Keeping these as ints simplifies the multiplication (no significant loss
|
|
* of precission here).
|
|
*/
|
|
du = CLUTTER_UNITS_TO_DEVICE (priv->coords.x2 - priv->coords.x1);
|
|
dv = CLUTTER_UNITS_TO_DEVICE (priv->coords.y2 - priv->coords.y1);
|
|
|
|
if (!du || !dv)
|
|
return FALSE;
|
|
|
|
#define FP2FX CLUTTER_FLOAT_TO_FIXED
|
|
#define FX2FP CLUTTER_FIXED_TO_DOUBLE
|
|
#define FP2INT CLUTTER_FLOAT_TO_INT
|
|
#define DET2X(a,b, c,d) (CFX_QMUL(a,d) - CFX_QMUL(b,c))
|
|
#define DET2FP(a,b, c,d) (a*d - b*c)
|
|
|
|
/*
|
|
* First, find mapping from unit uv square to xy quadrilateral; this
|
|
* equivalent to the pmap_square_quad() functions in the sample
|
|
* implementation, which we can simplify, since our target is always
|
|
* a rectangle.
|
|
*/
|
|
px = v[0].x - v[1].x + v[3].x - v[2].x;
|
|
py = v[0].y - v[1].y + v[3].y - v[2].y;
|
|
|
|
if (!px && !py)
|
|
{ /* affine transform */
|
|
RQ[0][0] = v[1].x - v[0].x;
|
|
RQ[1][0] = v[3].x - v[1].x;
|
|
RQ[2][0] = v[0].x;
|
|
RQ[0][1] = v[1].y - v[0].y;
|
|
RQ[1][1] = v[3].y - v[1].y;
|
|
RQ[2][1] = v[0].y;
|
|
RQ[0][2] = 0;
|
|
RQ[1][2] = 0;
|
|
RQ[2][2] = CFX_ONE;
|
|
}
|
|
else
|
|
{ /*
|
|
* projective transform
|
|
*
|
|
* Must do this in floating point, as the del value can overflow the
|
|
* range of ClutterFixed for large actors.
|
|
*
|
|
* TODO -- see if we could do this with sufficient precision in 26.8
|
|
* fixed.
|
|
*/
|
|
double dx1, dx2, dy1, dy2, del;
|
|
|
|
dx1 = FX2FP (v[1].x - v[3].x);
|
|
dx2 = FX2FP (v[2].x - v[3].x);
|
|
dy1 = FX2FP (v[1].y - v[3].y);
|
|
dy2 = FX2FP (v[2].y - v[3].y);
|
|
|
|
del = DET2FP (dx1,dx2, dy1,dy2);
|
|
|
|
if (!del)
|
|
return FALSE;
|
|
|
|
/*
|
|
* The division here needs to be done in floating point for
|
|
* precisions reasons.
|
|
*/
|
|
RQ[0][2] = FP2FX (DET2FP (FX2FP(px),dx2, FX2FP(py),dy2) / del);
|
|
RQ[1][2] = FP2FX (DET2FP (dx1,FX2FP(px), dy1,FX2FP(py)) / del);
|
|
RQ[1][2] = FP2FX (DET2FP(dx1,FX2FP(px), dy1,FX2FP(py))/del);
|
|
RQ[2][2] = CFX_ONE;
|
|
RQ[0][0] = v[1].x - v[0].x + CFX_QMUL (RQ[0][2], v[1].x);
|
|
RQ[1][0] = v[2].x - v[0].x + CFX_QMUL (RQ[1][2], v[2].x);
|
|
RQ[2][0] = v[0].x;
|
|
RQ[0][1] = v[1].y - v[0].y + CFX_QMUL (RQ[0][2], v[1].y);
|
|
RQ[1][1] = v[2].y - v[0].y + CFX_QMUL (RQ[1][2], v[2].y);
|
|
RQ[2][1] = v[0].y;
|
|
}
|
|
|
|
/*
|
|
* Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
|
|
* square. Since our rectangle is based at 0,0 we only need to scale.
|
|
*/
|
|
RQ[0][0] /= du;
|
|
RQ[1][0] /= dv;
|
|
RQ[0][1] /= du;
|
|
RQ[1][1] /= dv;
|
|
RQ[0][2] /= du;
|
|
RQ[1][2] /= dv;
|
|
|
|
/*
|
|
* Now RQ is transform from uv rectangle to xy quadrilateral; we need an
|
|
* inverse of that.
|
|
*/
|
|
ST[0][0] = DET2X(RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
|
|
ST[1][0] = DET2X(RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
|
|
ST[2][0] = DET2X(RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
|
|
ST[0][1] = DET2X(RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
|
|
ST[1][1] = DET2X(RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
|
|
ST[2][1] = DET2X(RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
|
|
ST[0][2] = DET2X(RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
|
|
ST[1][2] = DET2X(RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
|
|
ST[2][2] = DET2X(RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
|
|
|
|
/*
|
|
* Check the resutling martix is OK.
|
|
*/
|
|
det = CFX_QMUL (RQ[0][0], ST[0][0]) + CFX_QMUL (RQ[0][1], ST[0][1]) +
|
|
CFX_QMUL (RQ[0][2], ST[0][2]);
|
|
|
|
if (!det)
|
|
return FALSE;
|
|
|
|
/*
|
|
* Now transform our point with the ST matrix; the notional w coordiance
|
|
* is 1, hence the last part is simply added.
|
|
*/
|
|
xi = CLUTTER_UNITS_TO_DEVICE (x);
|
|
yi = CLUTTER_UNITS_TO_DEVICE (y);
|
|
|
|
xf = xi*ST[0][0] + yi*ST[1][0] + ST[2][0];
|
|
yf = xi*ST[0][1] + yi*ST[1][1] + ST[2][1];
|
|
wf = xi*ST[0][2] + yi*ST[1][2] + ST[2][2];
|
|
|
|
/*
|
|
* The division needs to be done in floating point for precision reasons.
|
|
*/
|
|
if (x_out)
|
|
*x_out = CLUTTER_UNITS_FROM_FLOAT (FX2FP (xf) / FX2FP (wf));
|
|
if (y_out)
|
|
*y_out = CLUTTER_UNITS_FROM_FLOAT (FX2FP (yf) / FX2FP (wf));
|
|
|
|
#undef FP2FX
|
|
#undef FX2FP
|
|
#undef FP2INT
|
|
#undef DET2X
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* ClutterGeometry
|
|
*/
|
|
|
|
static ClutterGeometry*
|
|
clutter_geometry_copy (const ClutterGeometry *geometry)
|
|
{
|
|
return g_slice_dup (ClutterGeometry, geometry);
|
|
}
|
|
|
|
static void
|
|
clutter_geometry_free (ClutterGeometry *geometry)
|
|
{
|
|
if (G_LIKELY (geometry))
|
|
g_slice_free (ClutterGeometry, geometry);
|
|
}
|
|
|
|
GType
|
|
clutter_geometry_get_type (void)
|
|
{
|
|
static GType our_type = 0;
|
|
|
|
if (G_UNLIKELY (our_type == 0))
|
|
our_type =
|
|
g_boxed_type_register_static (I_("ClutterGeometry"),
|
|
(GBoxedCopyFunc) clutter_geometry_copy,
|
|
(GBoxedFreeFunc) clutter_geometry_free);
|
|
|
|
return our_type;
|
|
}
|
|
|
|
/*
|
|
* ClutterVertices
|
|
*/
|
|
|
|
static ClutterVertex *
|
|
clutter_vertex_copy (const ClutterVertex *vertex)
|
|
{
|
|
return g_slice_dup (ClutterVertex, vertex);
|
|
}
|
|
|
|
static void
|
|
clutter_vertex_free (ClutterVertex *vertex)
|
|
{
|
|
if (G_UNLIKELY (vertex))
|
|
g_slice_free (ClutterVertex, vertex);
|
|
}
|
|
|
|
GType
|
|
clutter_vertex_get_type (void)
|
|
{
|
|
static GType our_type = 0;
|
|
|
|
if (G_UNLIKELY (our_type == 0))
|
|
our_type =
|
|
g_boxed_type_register_static (I_("ClutterVertex"),
|
|
(GBoxedCopyFunc) clutter_vertex_copy,
|
|
(GBoxedFreeFunc) clutter_vertex_free);
|
|
|
|
return our_type;
|
|
}
|
|
|
|
/*
|
|
* ClutterActorBox
|
|
*/
|
|
static ClutterActorBox *
|
|
clutter_actor_box_copy (const ClutterActorBox *box)
|
|
{
|
|
return g_slice_dup (ClutterActorBox, box);
|
|
}
|
|
|
|
static void
|
|
clutter_actor_box_free (ClutterActorBox *box)
|
|
{
|
|
if (G_LIKELY (box))
|
|
g_slice_free (ClutterActorBox, box);
|
|
}
|
|
|
|
GType
|
|
clutter_actor_box_get_type (void)
|
|
{
|
|
static GType our_type = 0;
|
|
|
|
if (G_UNLIKELY (our_type == 0))
|
|
our_type =
|
|
g_boxed_type_register_static (I_("ClutterActorBox"),
|
|
(GBoxedCopyFunc) clutter_actor_box_copy,
|
|
(GBoxedFreeFunc) clutter_actor_box_free);
|
|
return our_type;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
typedef struct _BoxedFloat BoxedFloat;
|
|
|
|
struct _BoxedFloat
|
|
{
|
|
gfloat value;
|
|
};
|
|
|
|
static void
|
|
boxed_float_free (gpointer data)
|
|
{
|
|
if (G_LIKELY (data))
|
|
g_slice_free (BoxedFloat, data);
|
|
}
|
|
|
|
struct _ShaderData
|
|
{
|
|
ClutterShader *shader;
|
|
GHashTable *float1f_hash; /*< list of values that should be set
|
|
* on the shader before each paint cycle
|
|
*/
|
|
};
|
|
|
|
static void
|
|
destroy_shader_data (ClutterActor *self)
|
|
{
|
|
ClutterActorPrivate *actor_priv = self->priv;
|
|
ShaderData *shader_data = actor_priv->shader_data;
|
|
|
|
if (!shader_data)
|
|
return;
|
|
|
|
if (shader_data->shader)
|
|
{
|
|
g_object_unref (shader_data->shader);
|
|
shader_data->shader = NULL;
|
|
}
|
|
|
|
if (shader_data->float1f_hash)
|
|
{
|
|
g_hash_table_destroy (shader_data->float1f_hash);
|
|
shader_data->float1f_hash = NULL;
|
|
}
|
|
|
|
g_free (shader_data);
|
|
actor_priv->shader_data = NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* clutter_actor_get_shader:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* Queries the currently set #ClutterShader on @self.
|
|
*
|
|
* Return value: The currently set #ClutterShader or %NULL if no
|
|
* shader is set.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
ClutterShader *
|
|
clutter_actor_get_shader (ClutterActor *self)
|
|
{
|
|
ClutterActorPrivate *actor_priv;
|
|
ShaderData *shader_data;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
|
|
|
actor_priv = self->priv;
|
|
shader_data = actor_priv->shader_data;
|
|
|
|
if (!shader_data)
|
|
return NULL;
|
|
|
|
return shader_data->shader;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_shader:
|
|
* @self: a #ClutterActor
|
|
* @shader: a #ClutterShader or %NULL to unset the shader.
|
|
*
|
|
* Sets the #ClutterShader to be used when rendering @self.
|
|
* If @shader is %NULL it will unset any currently set shader
|
|
* for the actor.
|
|
*
|
|
* Return value: %TRUE if the shader was successfully applied
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
gboolean
|
|
clutter_actor_set_shader (ClutterActor *self,
|
|
ClutterShader *shader)
|
|
{
|
|
ClutterActorPrivate *actor_priv;
|
|
ShaderData *shader_data;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
|
g_return_val_if_fail (shader == NULL || CLUTTER_IS_SHADER (shader), FALSE);
|
|
|
|
/* if shader passed in is NULL we destroy the shader */
|
|
if (shader == NULL)
|
|
{
|
|
destroy_shader_data (self);
|
|
}
|
|
|
|
actor_priv = self->priv;
|
|
shader_data = actor_priv->shader_data;
|
|
|
|
if (!shader_data)
|
|
{
|
|
actor_priv->shader_data = shader_data = g_new0 (ShaderData, 1);
|
|
shader_data->float1f_hash =
|
|
g_hash_table_new_full (g_str_hash, g_str_equal,
|
|
g_free,
|
|
boxed_float_free);
|
|
}
|
|
if (shader_data->shader)
|
|
{
|
|
g_object_unref (shader_data->shader);
|
|
shader_data->shader = NULL;
|
|
}
|
|
|
|
if (shader)
|
|
{
|
|
shader_data->shader = g_object_ref (shader);
|
|
}
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
clutter_actor_queue_redraw (self);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static void
|
|
set_each_param (gpointer key,
|
|
gpointer value,
|
|
gpointer user_data)
|
|
{
|
|
ClutterShader *shader = CLUTTER_SHADER (user_data);
|
|
BoxedFloat *box = value;
|
|
|
|
clutter_shader_set_uniform_1f (shader, key, box->value);
|
|
}
|
|
|
|
static void
|
|
clutter_actor_shader_pre_paint (ClutterActor *actor,
|
|
gboolean repeat)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
ShaderData *shader_data;
|
|
ClutterShader *shader;
|
|
ClutterMainContext *context;
|
|
|
|
priv = actor->priv;
|
|
shader_data = priv->shader_data;
|
|
|
|
if (!shader_data)
|
|
return;
|
|
|
|
context = clutter_context_get_default ();
|
|
shader = shader_data->shader;
|
|
|
|
if (shader)
|
|
{
|
|
clutter_shader_set_is_enabled (shader, TRUE);
|
|
|
|
g_hash_table_foreach (shader_data->float1f_hash, set_each_param, shader);
|
|
|
|
if (!repeat)
|
|
context->shaders = g_slist_prepend (context->shaders, actor);
|
|
}
|
|
}
|
|
|
|
static void
|
|
clutter_actor_shader_post_paint (ClutterActor *actor)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
ShaderData *shader_data;
|
|
ClutterShader *shader;
|
|
ClutterMainContext *context;
|
|
|
|
priv = actor->priv;
|
|
shader_data = priv->shader_data;
|
|
|
|
if (!shader_data)
|
|
return;
|
|
|
|
context = clutter_context_get_default ();
|
|
shader = shader_data->shader;
|
|
|
|
if (shader)
|
|
{
|
|
clutter_shader_set_is_enabled (shader, FALSE);
|
|
|
|
context->shaders = g_slist_remove (context->shaders, actor);
|
|
if (context->shaders)
|
|
{
|
|
/* call pre-paint again, this time with the second argument being
|
|
* TRUE, indicating that we are reapplying the shader and thus
|
|
* should not be prepended to the stack
|
|
*/
|
|
clutter_actor_shader_pre_paint (context->shaders->data, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_shader_param:
|
|
* @self: a #ClutterActor
|
|
* @param: the name of the parameter
|
|
* @value: the value of the parameter
|
|
*
|
|
* Sets the value for a named parameter of the shader applied
|
|
* to @actor.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_set_shader_param (ClutterActor *self,
|
|
const gchar *param,
|
|
gfloat value)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
ShaderData *shader_data;
|
|
BoxedFloat *box;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
g_return_if_fail (param != NULL);
|
|
|
|
priv = self->priv;
|
|
shader_data = priv->shader_data;
|
|
|
|
if (!shader_data)
|
|
return;
|
|
|
|
box = g_slice_new (BoxedFloat);
|
|
box->value = value;
|
|
g_hash_table_insert (shader_data->float1f_hash, g_strdup (param), box);
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
clutter_actor_queue_redraw (self);
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_is_rotated:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* Checks whether any rotation is applied to the actor.
|
|
*
|
|
* Return value: %TRUE if the actor is rotated.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
gboolean
|
|
clutter_actor_is_rotated (ClutterActor *self)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
|
|
|
priv = self->priv;
|
|
|
|
if (priv->rxang || priv->ryang || priv->rzang)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_is_scaled:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* Checks whether the actor is scaled in either dimension.
|
|
*
|
|
* Return value: %TRUE if the actor is scaled.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
gboolean
|
|
clutter_actor_is_scaled (ClutterActor *self)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
|
|
|
|
priv = self->priv;
|
|
|
|
if (priv->scale_x != CFX_ONE || priv->scale_y != CFX_ONE)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_box_get_from_vertices:
|
|
* @vtx: array of four #ClutterVertex
|
|
* @box: return location for a #ClutterActorBox
|
|
*
|
|
* Calculates the bounding box represented by the four vertices; for details
|
|
* of the vertex array see clutter_actor_get_vertices().
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_actor_get_box_from_vertices (ClutterVertex vtx[4],
|
|
ClutterActorBox *box)
|
|
{
|
|
ClutterUnit x_1, x_2, y_1, y_2;
|
|
|
|
/* 4-way min/max */
|
|
x_1 = vtx[0].x;
|
|
y_1 = vtx[0].y;
|
|
if (vtx[1].x < x_1)
|
|
x_1 = vtx[1].x;
|
|
if (vtx[2].x < x_1)
|
|
x_1 = vtx[2].x;
|
|
if (vtx[3].x < x_1)
|
|
x_1 = vtx[3].x;
|
|
if (vtx[1].y < y_1)
|
|
y_1 = vtx[1].y;
|
|
if (vtx[2].y < y_1)
|
|
y_1 = vtx[2].y;
|
|
if (vtx[3].y < y_1)
|
|
y_1 = vtx[3].y;
|
|
|
|
x_2 = vtx[0].x;
|
|
y_2 = vtx[0].y;
|
|
if (vtx[1].x > x_2)
|
|
x_2 = vtx[1].x;
|
|
if (vtx[2].x > x_2)
|
|
x_2 = vtx[2].x;
|
|
if (vtx[3].x > x_2)
|
|
x_2 = vtx[3].x;
|
|
if (vtx[1].y > y_2)
|
|
y_2 = vtx[1].y;
|
|
if (vtx[2].y > y_2)
|
|
y_2 = vtx[2].y;
|
|
if (vtx[3].y > y_2)
|
|
y_2 = vtx[3].y;
|
|
|
|
box->x1 = x_1;
|
|
box->x2 = x_2;
|
|
box->y1 = y_1;
|
|
box->y2 = y_2;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_get_stage:
|
|
* @actor: a #ClutterActor
|
|
*
|
|
* Retrieves the #ClutterStage where @actor is contained.
|
|
*
|
|
* Return value: the stage containing the actor, or %NULL
|
|
*
|
|
* Since: 0.8
|
|
*/
|
|
ClutterActor *
|
|
clutter_actor_get_stage (ClutterActor *actor)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
|
|
|
|
while (actor && !(CLUTTER_PRIVATE_FLAGS (actor) & CLUTTER_ACTOR_IS_TOPLEVEL))
|
|
actor = clutter_actor_get_parent (actor);
|
|
|
|
return actor;
|
|
}
|