mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 19:42:05 +00:00
98c537365c
* clutter/clutter-actor.c: (clutter_actor_should_pick_paint), (clutter_actor_apply_transform_to_point): Fix the whitespace. (clutter_actor_set_rotation): Clarify that the coordinates of the centre of rotation are relative to the anchor point or, if not set, to the upper left corner of the bounding box.
4920 lines
126 KiB
C
4920 lines
126 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.
|
|
*
|
|
* Actor Transformations
|
|
* 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>
|
|
*
|
|
* Event handling
|
|
* <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. A emitted event starts in the capture
|
|
* phase 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>
|
|
*/
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
|
|
/**
|
|
* CLUTTER_ACTOR_SET_FLAGS:
|
|
* @e: a #ClutterActor
|
|
* @f: the flags to set
|
|
*
|
|
* Sets flags on the given #ClutterActor
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
|
|
/**
|
|
* CLUTTER_ACTOR_UNSET_FLAGS:
|
|
* @e: a #ClutterActor
|
|
* @f: the flags to unset
|
|
*
|
|
* Unsets flags on the given #ClutterActor
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
|
|
#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.h"
|
|
|
|
static guint32 __id = 0;
|
|
|
|
|
|
#define CLUTTER_ACTOR_GET_PRIVATE(obj) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
|
|
|
|
typedef struct _ShaderData ShaderData;
|
|
|
|
struct _ClutterActorPrivate
|
|
{
|
|
ClutterActorBox coords;
|
|
|
|
ClutterGeometry clip; /* FIXME: Should be Units */
|
|
guint has_clip : 1;
|
|
ClutterFixed rxang, ryang, rzang; /* Rotation*/
|
|
ClutterUnit rzx, rzy, rxy, rxz, ryx, ryz;
|
|
ClutterUnit z;
|
|
guint8 opacity;
|
|
ClutterActor *parent_actor;
|
|
gchar *name;
|
|
ClutterFixed scale_x, scale_y;
|
|
guint32 id; /* Unique ID */
|
|
|
|
ShaderData *shader_data;
|
|
ClutterUnit anchor_x, anchor_y;
|
|
};
|
|
|
|
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
|
|
};
|
|
|
|
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);
|
|
|
|
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 gboolean
|
|
redraw_update_idle (gpointer data)
|
|
{
|
|
ClutterMainContext *ctx = CLUTTER_CONTEXT();
|
|
|
|
if (ctx->update_idle)
|
|
{
|
|
g_source_remove (ctx->update_idle);
|
|
ctx->update_idle = 0;
|
|
}
|
|
|
|
clutter_redraw ();
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
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 a clutter actor to be displayed. An actor not shown will not
|
|
* appear on the display.
|
|
**/
|
|
void
|
|
clutter_actor_show (ClutterActor *self)
|
|
{
|
|
if (!CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
{
|
|
g_object_ref (self);
|
|
|
|
g_signal_emit (self, actor_signals[SHOW], 0);
|
|
g_object_notify (G_OBJECT (self), "visible");
|
|
|
|
g_object_unref (self);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_show_all:
|
|
* @self: a #ClutterActor
|
|
*
|
|
* Call show() on all children of a 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 a clutter actor to be hidden. An actor not shown will not
|
|
* appear on the display.
|
|
**/
|
|
void
|
|
clutter_actor_hide (ClutterActor *self)
|
|
{
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
{
|
|
g_object_ref (self);
|
|
|
|
if (CLUTTER_ACTOR_IS_REACTIVE(self))
|
|
; /* FIXME: decrease global reactive count */
|
|
|
|
g_signal_emit (self, actor_signals[HIDE], 0);
|
|
g_object_notify (G_OBJECT (self), "visible");
|
|
|
|
g_object_unref (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;
|
|
|
|
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 in supplied color. Used internally for
|
|
* mapping pointer events to actors.
|
|
*
|
|
* This function should not never be called directly by applications.
|
|
*
|
|
* Subclasses overiding this method should call
|
|
* clutter_actor_should_pick_paint() to decide if to render there
|
|
* silhouette but in any case should still recursively call pick for
|
|
* any children.
|
|
*
|
|
* 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 not 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 (ClutterActor *actor,
|
|
ClutterUnit *x,
|
|
ClutterUnit *y,
|
|
ClutterUnit *z,
|
|
ClutterUnit *w)
|
|
{
|
|
ClutterFixed mtx[16];
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
|
|
|
priv = actor->priv;
|
|
|
|
cogl_push_matrix();
|
|
_clutter_actor_apply_modelview_transform_recursive (actor);
|
|
|
|
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_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 coordiances with the current actor tranform
|
|
* (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 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;
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
cogl_push_matrix();
|
|
_clutter_actor_apply_modelview_transform_recursive (self);
|
|
|
|
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 = priv->coords.x2 - priv->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 = priv->coords.y2 - priv->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 = priv->coords.x2 - priv->coords.x1;
|
|
_y = priv->coords.y2 - priv->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_vertices:
|
|
* @self: A #ClutterActor
|
|
* @verts: Pointer to a location of an array of 4 #ClutterVertex where to
|
|
* store the result.
|
|
*
|
|
* Calculates the tranformed screen coordinates of the four corners of
|
|
* the actor; the returned vertices relate to the ClutterActorBox
|
|
* coordinates as follows:
|
|
*
|
|
* v[0] contains (x1, y1)
|
|
* v[1] contains (x2, y1)
|
|
* v[2] contains (x1, y2)
|
|
* v[3] contains (x2, y2)
|
|
*
|
|
* 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;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
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;
|
|
ClutterActor *parent;
|
|
|
|
parent = clutter_actor_get_parent (self);
|
|
|
|
if (parent != NULL)
|
|
{
|
|
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 (parent && (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);
|
|
|
|
if (priv->has_clip)
|
|
cogl_clip_set (&(priv->clip));
|
|
}
|
|
|
|
/* Recursively applies the transforms associated with this actor and
|
|
* its ancestors 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_recursive (ClutterActor * self)
|
|
{
|
|
ClutterActor * parent;
|
|
|
|
parent = clutter_actor_get_parent (self);
|
|
|
|
if (parent)
|
|
_clutter_actor_apply_modelview_transform_recursive (parent);
|
|
|
|
_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 instead
|
|
* #clutter_actor_queue_redraw should be used to queue paints.
|
|
**/
|
|
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 (G_UNLIKELY(context->pick_mode != CLUTTER_PICK_NONE))
|
|
{
|
|
gint r, g, b;
|
|
ClutterColor col;
|
|
guint32 id;
|
|
|
|
id = clutter_actor_get_gid (self);
|
|
|
|
cogl_get_bitmasks (&r, &g, &b, NULL);
|
|
|
|
/* Encode the actor id into a color, taking into account bpp */
|
|
col.red = ((id >> (g+b)) & (0xff>>(8-r)))<<(8-r);
|
|
col.green = ((id >> b) & (0xff>>(8-g))) << (8-g);
|
|
col.blue = (id & (0xff>>(8-b)))<<(8-b);
|
|
col.alpha = 0xff;
|
|
|
|
/* 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 evental
|
|
* 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 actors #ClutterActorBox co-ordinates
|
|
*
|
|
* Requests the untransformed co-ordinates (in ClutterUnits) for the
|
|
* #ClutterActor relative to any parent.
|
|
*
|
|
* This function should not be called directly by applications instead
|
|
* the various position/geometry methods should be used.
|
|
**/
|
|
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;
|
|
}
|
|
}
|
|
|
|
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:
|
|
clutter_actor_set_rotation (actor,
|
|
CLUTTER_X_AXIS,
|
|
g_value_get_double (value),
|
|
0, priv->rxy, priv->rxz);
|
|
break;
|
|
case PROP_ROTATION_ANGLE_Y:
|
|
clutter_actor_set_rotation (actor,
|
|
CLUTTER_Y_AXIS,
|
|
g_value_get_double (value),
|
|
priv->ryx, 0, priv->ryz);
|
|
break;
|
|
case PROP_ROTATION_ANGLE_Z:
|
|
clutter_actor_set_rotation (actor,
|
|
CLUTTER_Z_AXIS,
|
|
g_value_get_double (value),
|
|
priv->rzx, priv->rzy, 0);
|
|
break;
|
|
case PROP_ROTATION_CENTER_X:
|
|
{
|
|
ClutterVertex *center;
|
|
|
|
center = g_value_get_boxed (value);
|
|
clutter_actor_set_rotationx (actor,
|
|
CLUTTER_X_AXIS,
|
|
priv->rxang,
|
|
0,
|
|
CLUTTER_UNITS_TO_DEVICE (center->y),
|
|
CLUTTER_UNITS_TO_DEVICE (center->z));
|
|
}
|
|
break;
|
|
case PROP_ROTATION_CENTER_Y:
|
|
{
|
|
ClutterVertex *center;
|
|
|
|
center = g_value_get_boxed (value);
|
|
clutter_actor_set_rotationx (actor,
|
|
CLUTTER_X_AXIS,
|
|
priv->ryang,
|
|
CLUTTER_UNITS_TO_DEVICE (center->x),
|
|
0,
|
|
CLUTTER_UNITS_TO_DEVICE (center->z));
|
|
}
|
|
break;
|
|
case PROP_ROTATION_CENTER_Z:
|
|
{
|
|
ClutterVertex *center;
|
|
|
|
center = g_value_get_boxed (value);
|
|
clutter_actor_set_rotationx (actor,
|
|
CLUTTER_X_AXIS,
|
|
priv->rzang,
|
|
CLUTTER_UNITS_TO_DEVICE (center->x),
|
|
CLUTTER_UNITS_TO_DEVICE (center->y),
|
|
0);
|
|
}
|
|
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:
|
|
g_value_set_boxed (value, &(priv->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_IS_REACTIVE (actor) != FALSE));
|
|
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;
|
|
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);
|
|
|
|
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 X",
|
|
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 Y",
|
|
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::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 becomes visible.
|
|
*
|
|
* 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 visible.
|
|
*
|
|
* 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 and 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 a 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 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[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 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[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 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[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 = __id++;
|
|
priv->scale_x = CFX_ONE;
|
|
priv->scale_y = CFX_ONE;
|
|
priv->shader_data = NULL;
|
|
|
|
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));
|
|
|
|
if (CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL)
|
|
{
|
|
g_warning ("Calling clutter_actor_destroy() on an actor of type `%s' "
|
|
"is not possible. This is usually an application bug.",
|
|
g_type_name (G_OBJECT_TYPE (self)));
|
|
return;
|
|
}
|
|
|
|
priv = self->priv;
|
|
|
|
if (priv->parent_actor)
|
|
{
|
|
ClutterActor *parent = priv->parent_actor;
|
|
|
|
if (CLUTTER_IS_CONTAINER (parent))
|
|
{
|
|
g_object_ref (self);
|
|
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)
|
|
{
|
|
ClutterMainContext *ctx = CLUTTER_CONTEXT();
|
|
|
|
if (!ctx->update_idle)
|
|
{
|
|
CLUTTER_TIMESTAMP (SCHEDULER, "Adding idle source for actor: %p", self);
|
|
|
|
ctx->update_idle =
|
|
clutter_threads_add_idle_full (G_PRIORITY_DEFAULT + 10,
|
|
redraw_update_idle,
|
|
NULL, NULL);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_geometry:
|
|
* @self: A #ClutterActor
|
|
* @geometry: A #ClutterGeometry
|
|
*
|
|
* Sets the actors 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 actors 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 actors untransformed bounding rectangle co-ordinates 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 actors 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
|
|
* @y: New top position of actor in #ClutterUnit
|
|
*
|
|
* Sets the actors position in #ClutterUnit 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 specified distance relative to
|
|
* current position in pixels.
|
|
*
|
|
* Since: 0.2
|
|
*/
|
|
void
|
|
clutter_actor_move_by (ClutterActor *self,
|
|
gint dx,
|
|
gint dy)
|
|
{
|
|
ClutterActorBox box;
|
|
gint32 dxu = CLUTTER_UNITS_FROM_INT (dx);
|
|
gint32 dyu = CLUTTER_UNITS_FROM_INT (dy);
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clutter_actor_query_coords (self, &box);
|
|
|
|
box.x2 += dxu;
|
|
box.y2 += dyu;
|
|
box.x1 += dxu;
|
|
box.y1 += dyu;
|
|
|
|
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 actors size in pixels. If @width and/or @height are -1 the
|
|
* actor will assume the same size of its bounding box.
|
|
*/
|
|
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, or -1
|
|
* @height: New height of actor in #ClutterUnit, or -1
|
|
*
|
|
* Sets the actors size in #ClutterUnit. If @width and/or @height are -1 the
|
|
* actor will assume the same size of 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: Location to store width if non NULL.
|
|
* @height: Location to store height if non 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: Location to store width if non NULL.
|
|
* @height: Location to store height if non 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: Location to store x position if non NULL.
|
|
* @y: Location to store y position if non NULL.
|
|
*
|
|
* Gets the absolute position of an actor in clutter units 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;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
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: Location to store x position if non NULL.
|
|
* @y: Location to store y position if non 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: Location to store width if non NULL.
|
|
* @height: Location to store height if non NULL.
|
|
*
|
|
* Gets the absolute size of an actor in clutter units taking into account
|
|
* an 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: Location to store width if non NULL.
|
|
* @height: Location to store height if non 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 actors width ignoring any scaling factors.
|
|
*
|
|
* Return value: The actor 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 actors width ignoring any scaling factors.
|
|
*
|
|
* Return value: The actor width in #ClutterUnit
|
|
*
|
|
* 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 actors height ignoring any scaling factors.
|
|
*
|
|
* Return value: The actor 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 actors height ignoring any scaling factors.
|
|
*
|
|
* Return value: The actor height in #ClutterUnit
|
|
*
|
|
* 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 actor
|
|
*
|
|
* Requests a new width for 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 actor in #ClutterUnit
|
|
*
|
|
* Requests a new width for 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 actor
|
|
*
|
|
* Requests a new height for 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 actor in #ClutterUnit
|
|
*
|
|
* Requests a new height for 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 actors position on the X axis
|
|
*
|
|
* Sets the actor's x position 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 actors position on the X axis in #ClutterUnit
|
|
*
|
|
* Sets the actor's x position 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 actors position on the Y axis
|
|
*
|
|
* Sets the actor's y position 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 actors position on the Y axis in #ClutterUnit
|
|
*
|
|
* Sets the actor's y position 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 actors x position relative to any parent.
|
|
*
|
|
* Return value: The actor x position in pixels ignoring any tranforms
|
|
* (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 actors x position relative to any parent, in #ClutterUnit
|
|
*
|
|
* Return value: The actor x position in #ClutterUnit ignoring any tranforms
|
|
* (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 actors y position relative to any parent.
|
|
*
|
|
* Return value: The actor y position in pixels ignoring any tranforms
|
|
* (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 actors y position relative to any parent, in #ClutterUnit
|
|
*
|
|
* Return value: The actor y position in #ClutterUnit ignoring any tranforms
|
|
* (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.
|
|
*
|
|
* Scales an actor with fixed point parameters.
|
|
*/
|
|
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 floating point parameters.
|
|
*
|
|
* 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 fixed scale factor if non NULL.
|
|
* @scale_y: Location to store vertical fixed scale factor if non NULL.
|
|
*
|
|
* Retrieves an actors scale in fixed point.
|
|
*
|
|
* 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 if non NULL.
|
|
* @scale_y: Location to store vertical float scale factor if non 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 actor.
|
|
*
|
|
* Sets the actors opacity, with zero being completely transparent and
|
|
* 255 (0xff) as 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_opacity:
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Retrieves the actors opacity.
|
|
*
|
|
* Return value: The actor opacity value.
|
|
*/
|
|
guint8
|
|
clutter_actor_get_opacity (ClutterActor *self)
|
|
{
|
|
ClutterActor *parent;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
|
|
|
|
parent = self->priv->parent_actor;
|
|
|
|
/* Factor in the actual actors opacity with parents */
|
|
if (parent && clutter_actor_get_opacity (parent) != 0xff)
|
|
return (clutter_actor_get_opacity(parent) * self->priv->opacity) / 0xff;
|
|
|
|
return self->priv->opacity;
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_set_name:
|
|
* @self: A #ClutterActor
|
|
* @name: Textual tag to apply to actor
|
|
*
|
|
* Sets a textual tag to the actor.
|
|
*/
|
|
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: pointer to textual tag for the actor. 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 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-ord in #ClutterUnit
|
|
*
|
|
* Sets the Z co-ordinate of @self to @depth in #ClutterUnit, 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 a #ClutterActor
|
|
*/
|
|
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 a #ClutterActor in #ClutterUnit
|
|
*
|
|
* 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_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)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
switch (axis)
|
|
{
|
|
case CLUTTER_X_AXIS:
|
|
priv->rxang = angle;
|
|
priv->rxy = CLUTTER_UNITS_FROM_DEVICE (y);
|
|
priv->rxz = CLUTTER_UNITS_FROM_DEVICE (z);
|
|
break;
|
|
|
|
case CLUTTER_Y_AXIS:
|
|
priv->ryang = angle;
|
|
priv->ryx = CLUTTER_UNITS_FROM_DEVICE (x);
|
|
priv->ryz = CLUTTER_UNITS_FROM_DEVICE (z);
|
|
break;
|
|
|
|
case CLUTTER_Z_AXIS:
|
|
priv->rzang = angle;
|
|
priv->rzx = CLUTTER_UNITS_FROM_DEVICE (x);
|
|
priv->rzy = CLUTTER_UNITS_FROM_DEVICE (y);
|
|
break;
|
|
}
|
|
|
|
if (CLUTTER_ACTOR_IS_VISIBLE (self))
|
|
clutter_actor_queue_redraw (self);
|
|
}
|
|
|
|
/**
|
|
* 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_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_clip:
|
|
* @self: A #ClutterActor
|
|
* @xoff: X offset of the clip rectangle
|
|
* @yoff: Y offset of the clip rectangle
|
|
* @width: Width of the clip rectangle
|
|
* @height: Height of the clip rectangle
|
|
*
|
|
* 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)
|
|
{
|
|
ClutterGeometry *clip;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
clip = &(self->priv->clip);
|
|
|
|
clip->x = xoff;
|
|
clip->y = yoff;
|
|
clip->width = width;
|
|
clip->height = height;
|
|
|
|
self->priv->has_clip = TRUE;
|
|
|
|
g_object_notify (G_OBJECT (self), "has-clip");
|
|
g_object_notify (G_OBJECT (self), "clip");
|
|
}
|
|
|
|
/**
|
|
* clutter_actor_remove_clip
|
|
* @self: A #ClutterActor
|
|
*
|
|
* Removes clip area in pixels 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
|
|
*
|
|
* Gets whether the actor has a clip set or not.
|
|
*
|
|
* Return value: %TRUE if the actor has a clip 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_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)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
ClutterGeometry clip = { 0, };
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
if (!priv->has_clip)
|
|
return;
|
|
|
|
clip = priv->clip;
|
|
|
|
if (xoff)
|
|
*xoff = clip.x;
|
|
if (yoff)
|
|
*yoff = clip.y;
|
|
if (width)
|
|
*width = clip.width;
|
|
if (height)
|
|
*height = clip.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 sub classes.
|
|
*/
|
|
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_hash_table_insert (clutter_context->actor_hash,
|
|
GUINT_TO_POINTER (clutter_actor_get_gid (self)),
|
|
(gpointer)self);
|
|
|
|
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 (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
|
|
*/
|
|
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_hash_table_remove (clutter_context->actor_hash,
|
|
GUINT_TO_POINTER (clutter_actor_get_gid (self)));
|
|
|
|
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_actory_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);
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
ClutterActorPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (self));
|
|
|
|
priv = self->priv;
|
|
|
|
priv->anchor_x = CLUTTER_UNITS_FROM_DEVICE (anchor_x);
|
|
priv->anchor_y = CLUTTER_UNITS_FROM_DEVICE (anchor_y);
|
|
}
|
|
|
|
/**
|
|
* 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 the @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;
|
|
|
|
priv->anchor_x = anchor_x;
|
|
priv->anchor_y = anchor_y;
|
|
}
|
|
|
|
/**
|
|
* 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_set_anchor_point_from_gravity:
|
|
* @self: a #ClutterActor
|
|
* @gravity: #ClutterGravity.
|
|
*
|
|
* Sets an anchor point 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:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
priv->anchor_x = x;
|
|
priv->anchor_y = y;
|
|
}
|
|
|
|
typedef enum
|
|
{
|
|
PARSE_X,
|
|
PARSE_Y,
|
|
PARSE_WIDTH,
|
|
PARSE_HEIGHT
|
|
} 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);
|
|
|
|
/* 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) ? "width"
|
|
: "height",
|
|
g_type_name (G_OBJECT_TYPE (self)));
|
|
retval = 0;
|
|
goto out;
|
|
}
|
|
|
|
if (dimension == PARSE_X || dimension == PARSE_WIDTH)
|
|
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)
|
|
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 and height "
|
|
"properties.",
|
|
g_type_name (G_VALUE_TYPE (&value)));
|
|
}
|
|
|
|
out:
|
|
g_value_unset (&value);
|
|
|
|
return retval;
|
|
}
|
|
|
|
typedef struct {
|
|
ClutterRotateAxis axis;
|
|
|
|
gdouble angle;
|
|
|
|
ClutterUnit center_x;
|
|
ClutterUnit center_y;
|
|
ClutterUnit center_z;
|
|
} RotationInfo;
|
|
|
|
static gboolean
|
|
parse_rotation_array (ClutterActor *actor,
|
|
JsonNode *node,
|
|
RotationInfo *info)
|
|
{
|
|
JsonArray *array = json_node_get_array (node);
|
|
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 = 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 *array = json_node_get_array (element);
|
|
|
|
if (json_array_get_length (array) != 2)
|
|
return FALSE;
|
|
|
|
switch (info->axis)
|
|
{
|
|
case CLUTTER_X_AXIS:
|
|
info->center_y = parse_units (actor, PARSE_Y,
|
|
json_array_get_element (array, 0));
|
|
info->center_z = parse_units (actor, PARSE_Y,
|
|
json_array_get_element (array, 1));
|
|
return TRUE;
|
|
|
|
case CLUTTER_Y_AXIS:
|
|
info->center_x = parse_units (actor, PARSE_X,
|
|
json_array_get_element (array, 0));
|
|
info->center_z = parse_units (actor, PARSE_X,
|
|
json_array_get_element (array, 1));
|
|
return TRUE;
|
|
|
|
case CLUTTER_Z_AXIS:
|
|
info->center_x = parse_units (actor, PARSE_X,
|
|
json_array_get_element (array, 0));
|
|
info->center_y = parse_units (actor, PARSE_Y,
|
|
json_array_get_element (array, 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, 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, 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, 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))
|
|
{
|
|
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
|
|
dimension = PARSE_HEIGHT;
|
|
|
|
units = parse_units (actor, dimension, node);
|
|
|
|
/* convert back to pixels */
|
|
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)
|
|
{
|
|
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 (CLUTTER_ACTOR (scriptable),
|
|
info->axis, info->angle,
|
|
CLUTTER_UNITS_TO_DEVICE (info->center_x),
|
|
CLUTTER_UNITS_TO_DEVICE (info->center_y),
|
|
CLUTTER_UNITS_TO_DEVICE (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
|
|
*
|
|
* The function translates point with screen coordinates (@x, @y) to
|
|
* coordinates relative to the actor, i.e. it can be used to translate
|
|
* screen events from global screen coordinates into 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))
|
|
|
|
/*
|
|
* 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 */
|
|
ClutterFixed dx1, dx2, dy1, dy2, del;
|
|
|
|
dx1 = v[1].x - v[3].x;
|
|
dx2 = v[2].x - v[3].x;
|
|
dy1 = v[1].y - v[3].y;
|
|
dy2 = v[2].y - v[3].y;
|
|
|
|
del = DET2X (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 (FX2FP (DET2X (px,dx2, py,dy2) / FX2FP (del)));
|
|
RQ[1][2] = FP2FX (FX2FP (DET2X (dx1,px, dy1,py) / FX2FP (del)));
|
|
RQ[1][2] = CFX_DIV (DET2X(dx1,px, dy1,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 precission reasons.
|
|
*/
|
|
*x_out = CLUTTER_UNITS_FROM_FLOAT (FX2FP (xf) / FX2FP (wf));
|
|
*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)
|
|
{
|
|
ClutterGeometry *result = g_slice_new (ClutterGeometry);
|
|
|
|
*result = *geometry;
|
|
|
|
return result;
|
|
}
|
|
|
|
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)
|
|
{
|
|
ClutterVertex *result = g_slice_new (ClutterVertex);
|
|
|
|
*result = *vertex;
|
|
|
|
return result;
|
|
}
|
|
|
|
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)
|
|
{
|
|
ClutterActorBox *result = g_slice_new (ClutterActorBox);
|
|
|
|
*result = *box;
|
|
|
|
return result;
|
|
}
|
|
|
|
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_apply_shader:
|
|
* @self: a #ClutterActor
|
|
* @shader: a #ClutterShader or %NULL
|
|
*
|
|
* Sets the #ClutterShader to be applied on @self.
|
|
*
|
|
* Return value: %TRUE if the shader was successfully applied
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
gboolean
|
|
clutter_actor_apply_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);
|
|
|
|
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);
|
|
|
|
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;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
|
|
|
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;
|
|
|
|
g_return_if_fail (CLUTTER_IS_ACTOR (actor));
|
|
|
|
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);
|
|
}
|