diff --git a/.gitignore b/.gitignore
index 0ff441116..c3d05ec40 100644
--- a/.gitignore
+++ b/.gitignore
@@ -111,6 +111,7 @@ stamp-h1
/tests/interactive/test-easing
/tests/interactive/test-interactive
/tests/interactive/test-binding-pool
+/tests/interactive/test-text-field
/tests/interactive/redhand.png
/tests/interactive/test-script.json
/tests/conform/test-conformance
@@ -158,6 +159,7 @@ stamp-h1
/clutter/x11/stamp-clutter-x11-enum-types.h
/po/Makefile.in.in
/po/POTFILES
+/po/*.pot
*.swn
*.swo
*.swp
diff --git a/clutter/Makefile.am b/clutter/Makefile.am
index 4db7c9fe2..faa9480cc 100644
--- a/clutter/Makefile.am
+++ b/clutter/Makefile.am
@@ -64,7 +64,6 @@ source_h = \
$(srcdir)/clutter-container.h \
$(srcdir)/clutter-deprecated.h \
$(srcdir)/clutter-effect.h \
- $(srcdir)/clutter-entry.h \
$(srcdir)/clutter-event.h \
$(srcdir)/clutter-feature.h \
$(srcdir)/clutter-fixed.h \
@@ -72,7 +71,6 @@ source_h = \
$(srcdir)/clutter-group.h \
$(srcdir)/clutter-interval.h \
$(srcdir)/clutter-keysyms.h \
- $(srcdir)/clutter-label.h \
$(srcdir)/clutter-list-model.h \
$(srcdir)/clutter-main.h \
$(srcdir)/clutter-media.h \
@@ -87,6 +85,7 @@ source_h = \
$(srcdir)/clutter-stage.h \
$(srcdir)/clutter-stage-manager.h \
$(srcdir)/clutter-texture.h \
+ $(srcdir)/clutter-text.h \
$(srcdir)/clutter-timeline.h \
$(srcdir)/clutter-timeout-pool.h \
$(srcdir)/clutter-types.h \
@@ -155,7 +154,6 @@ source_c = \
clutter-color.c \
clutter-container.c \
clutter-effect.c \
- clutter-entry.c \
clutter-enum-types.c \
clutter-event.c \
clutter-feature.c \
@@ -164,7 +162,6 @@ source_c = \
clutter-group.c \
clutter-id-pool.c \
clutter-interval.c \
- clutter-label.c \
clutter-list-model.c \
clutter-main.c \
clutter-marshal.c \
@@ -182,6 +179,7 @@ source_c = \
clutter-stage-manager.c \
clutter-stage-window.c \
clutter-texture.c \
+ clutter-text.c \
clutter-timeline.c \
clutter-timeout-pool.c \
clutter-units.c \
diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c
index d804e41d2..7d616266e 100644
--- a/clutter/clutter-actor.c
+++ b/clutter/clutter-actor.c
@@ -221,7 +221,9 @@ struct _ClutterActorPrivate
/* cached allocation is invalid (request has changed, probably) */
guint needs_allocation : 1;
- guint has_clip : 1;
+ guint show_on_set_parent : 1;
+ guint has_clip : 1;
+
ClutterUnit clip[4];
/* Rotation angles */
@@ -260,7 +262,7 @@ struct _ClutterActorPrivate
ShaderData *shader_data;
- gboolean show_on_set_parent;
+ PangoContext *pango_context;
};
enum
@@ -772,6 +774,24 @@ clutter_actor_real_allocate (ClutterActor *self,
g_object_thaw_notify (G_OBJECT (self));
}
+/* like ClutterVertex, but using CoglFixed and with a w component */
+typedef struct {
+ CoglFixed x;
+ CoglFixed y;
+ CoglFixed z;
+ CoglFixed w;
+} fixed_vertex_t;
+
+/* copies a fixed vertex into a ClutterVertex */
+static inline void
+fixed_vertex_to_units (const fixed_vertex_t *f,
+ ClutterVertex *u)
+{
+ u->x = CLUTTER_UNITS_FROM_FIXED (f->x);
+ u->y = CLUTTER_UNITS_FROM_FIXED (f->y);
+ u->z = CLUTTER_UNITS_FROM_FIXED (f->z);
+}
+
/*
* Utility functions for manipulating transformation matrix
*
@@ -779,49 +799,114 @@ clutter_actor_real_allocate (ClutterActor *self,
*/
#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)
+/* Transforms a vertex using the passed matrix; vertex is
+ * an in-out parameter
+ */
+static inline void
+mtx_transform (const ClutterFixed m[],
+ fixed_vertex_t *vertex)
{
- ClutterFixed _x, _y, _z, _w;
- _x = *x;
- _y = *y;
- _z = *z;
- _w = *w;
+ ClutterFixed _x, _y, _z, _w;
- /* We care lot about precision here, so have to use QMUL */
- *x = COGL_FIXED_MUL (M (m, 0, 0), _x)
- + COGL_FIXED_MUL (M (m, 0, 1), _y)
- + COGL_FIXED_MUL (M (m, 0, 2), _z)
- + COGL_FIXED_MUL (M (m, 0, 3), _w);
+ _x = vertex->x;
+ _y = vertex->y;
+ _z = vertex->z;
+ _w = vertex->w;
- *y = COGL_FIXED_MUL (M (m, 1, 0), _x)
- + COGL_FIXED_MUL (M (m, 1, 1), _y)
- + COGL_FIXED_MUL (M (m, 1, 2), _z)
- + COGL_FIXED_MUL (M (m, 1, 3), _w);
+ /* We care lot about precision here, so have to use MUL instead
+ * of FAST_MUL
+ */
+ vertex->x = COGL_FIXED_MUL (M (m, 0, 0), _x)
+ + COGL_FIXED_MUL (M (m, 0, 1), _y)
+ + COGL_FIXED_MUL (M (m, 0, 2), _z)
+ + COGL_FIXED_MUL (M (m, 0, 3), _w);
- *z = COGL_FIXED_MUL (M (m, 2, 0), _x)
- + COGL_FIXED_MUL (M (m, 2, 1), _y)
- + COGL_FIXED_MUL (M (m, 2, 2), _z)
- + COGL_FIXED_MUL (M (m, 2, 3), _w);
+ vertex->y = COGL_FIXED_MUL (M (m, 1, 0), _x)
+ + COGL_FIXED_MUL (M (m, 1, 1), _y)
+ + COGL_FIXED_MUL (M (m, 1, 2), _z)
+ + COGL_FIXED_MUL (M (m, 1, 3), _w);
- *w = COGL_FIXED_MUL (M (m, 3, 0), _x)
- + COGL_FIXED_MUL (M (m, 3, 1), _y)
- + COGL_FIXED_MUL (M (m, 3, 2), _z)
- + COGL_FIXED_MUL (M (m, 3, 3), _w);
+ vertex->z = COGL_FIXED_MUL (M (m, 2, 0), _x)
+ + COGL_FIXED_MUL (M (m, 2, 1), _y)
+ + COGL_FIXED_MUL (M (m, 2, 2), _z)
+ + COGL_FIXED_MUL (M (m, 2, 3), _w);
- /* Specially for Matthew: was going to put a comment here, but could not
- * think of anything at all to say ;)
- */
+ vertex->w = COGL_FIXED_MUL (M (m, 3, 0), _x)
+ + COGL_FIXED_MUL (M (m, 3, 1), _y)
+ + COGL_FIXED_MUL (M (m, 3, 2), _z)
+ + COGL_FIXED_MUL (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
+/* 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) (COGL_FIXED_MUL (((COGL_FIXED_DIV ((x), (w)) + COGL_FIXED_1) >> 1), (v1)) + (v2))
+#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - COGL_FIXED_MUL (((COGL_FIXED_DIV ((y), (w)) + COGL_FIXED_1) >> 1), (v1)) + (v2))
+#define MTX_GL_SCALE_Z(z,w,v1,v2) (MTX_GL_SCALE_X ((z), (w), (v1), (v2)))
+
+/* transforms a 4-tuple of coordinates using @matrix and
+ * places the result into a fixed @vertex
+ */
+static inline void
+fixed_vertex_transform (const ClutterFixed matrix[],
+ ClutterFixed x,
+ ClutterFixed y,
+ ClutterFixed z,
+ ClutterFixed w,
+ fixed_vertex_t *vertex)
+{
+ fixed_vertex_t tmp = { 0, };
+
+ tmp.x = x;
+ tmp.y = y;
+ tmp.z = z;
+ tmp.w = w;
+
+ mtx_transform (matrix, &tmp);
+
+ *vertex = tmp;
+}
+
+/* scales a fixed @vertex using @matrix and @viewport, and
+ * transforms the result into ClutterUnits, filling @vertex_p
+ */
+static inline void
+fixed_vertex_scale (const ClutterFixed matrix[],
+ const fixed_vertex_t *vertex,
+ const ClutterFixed viewport[],
+ ClutterVertex *vertex_p)
+{
+ ClutterFixed v_x, v_y, v_width, v_height;
+ fixed_vertex_t tmp = { 0, };
+
+ tmp = *vertex;
+
+ mtx_transform (matrix, &tmp);
+
+ v_x = viewport[0];
+ v_y = viewport[1];
+ v_width = viewport[2];
+ v_height = viewport[3];
+
+ tmp.x = MTX_GL_SCALE_X (tmp.x, tmp.w, v_width, v_x);
+ tmp.y = MTX_GL_SCALE_Y (tmp.y, tmp.w, v_height, v_y);
+ tmp.z = MTX_GL_SCALE_Z (tmp.z, tmp.w, v_width, v_x);
+ tmp.w = 0;
+
+ fixed_vertex_to_units (&tmp, vertex_p);
+}
+
/* 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
+ *
+ * The point coordinates are in-out parameters
*/
static void
clutter_actor_transform_point_relative (ClutterActor *actor,
@@ -832,14 +917,33 @@ clutter_actor_transform_point_relative (ClutterActor *actor,
ClutterUnit *w)
{
ClutterFixed mtx[16];
+ fixed_vertex_t vertex = { 0, };
+
+ vertex.x = (x != NULL) ? CLUTTER_UNITS_TO_FIXED (*x) : 0;
+ vertex.y = (y != NULL) ? CLUTTER_UNITS_TO_FIXED (*y) : 0;
+ vertex.z = (z != NULL) ? CLUTTER_UNITS_TO_FIXED (*z) : 0;
+ vertex.w = (w != NULL) ? CLUTTER_UNITS_TO_FIXED (*w) : 0;
cogl_push_matrix();
_clutter_actor_apply_modelview_transform_recursive (actor, ancestor);
+
cogl_get_modelview_matrix (mtx);
- mtx_transform (mtx, x, y, z, w);
+ mtx_transform (mtx, &vertex);
cogl_pop_matrix();
+
+ if (x)
+ *x = CLUTTER_UNITS_FROM_FIXED (vertex.x);
+
+ if (y)
+ *y = CLUTTER_UNITS_FROM_FIXED (vertex.y);
+
+ if (z)
+ *z = CLUTTER_UNITS_FROM_FIXED (vertex.z);
+
+ if (w)
+ *w = CLUTTER_UNITS_FROM_FIXED (vertex.w);
}
/* Applies the transforms associated with this actor and its ancestors,
@@ -854,22 +958,34 @@ clutter_actor_transform_point (ClutterActor *actor,
ClutterUnit *w)
{
ClutterFixed mtx[16];
+ fixed_vertex_t vertex = { 0, };
+
+ vertex.x = (x != NULL) ? CLUTTER_UNITS_TO_FIXED (*x) : 0;
+ vertex.y = (y != NULL) ? CLUTTER_UNITS_TO_FIXED (*y) : 0;
+ vertex.z = (z != NULL) ? CLUTTER_UNITS_TO_FIXED (*z) : 0;
+ vertex.w = (w != NULL) ? CLUTTER_UNITS_TO_FIXED (*w) : 0;
cogl_push_matrix();
_clutter_actor_apply_modelview_transform_recursive (actor, NULL);
+
cogl_get_modelview_matrix (mtx);
- mtx_transform (mtx, x, y, z, w);
+ mtx_transform (mtx, &vertex);
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) (COGL_FIXED_MUL (((COGL_FIXED_DIV ((x), (w)) + COGL_FIXED_1) >> 1), (v1)) + (v2))
-#define MTX_GL_SCALE_Y(y,w,v1,v2) ((v1) - COGL_FIXED_MUL (((COGL_FIXED_DIV ((y), (w)) + COGL_FIXED_1) >> 1), (v1)) + (v2))
-#define MTX_GL_SCALE_Z(z,w,v1,v2) (MTX_GL_SCALE_X ((z), (w), (v1), (v2)))
+ if (x)
+ *x = CLUTTER_UNITS_FROM_FIXED (vertex.x);
+
+ if (y)
+ *y = CLUTTER_UNITS_FROM_FIXED (vertex.y);
+
+ if (z)
+ *z = CLUTTER_UNITS_FROM_FIXED (vertex.z);
+
+ if (w)
+ *w = CLUTTER_UNITS_FROM_FIXED (vertex.w);
+}
/**
* clutter_actor_apply_relative_transform_to_point:
@@ -896,21 +1012,22 @@ clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
const ClutterVertex *point,
ClutterVertex *vertex)
{
- ClutterVertex tmp = { 0, };
ClutterFixed v[4];
- ClutterFixed w = COGL_FIXED_1;
+ ClutterFixed x, y, z, w;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
g_return_if_fail (point != NULL);
g_return_if_fail (vertex != NULL);
- tmp = *point;
+ x = CLUTTER_UNITS_TO_FIXED (vertex->x);
+ y = CLUTTER_UNITS_TO_FIXED (vertex->y);
+ z = CLUTTER_UNITS_TO_FIXED (vertex->z);
+ w = COGL_FIXED_1;
/* First we tranform the point using the OpenGL modelview matrix */
clutter_actor_transform_point_relative (self, ancestor,
- &tmp.x, &tmp.y, &tmp.z,
- &w);
+ &x, &y, &z, &w);
cogl_get_viewport (v);
@@ -918,9 +1035,12 @@ clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
* The w[3] parameter should always be 1.0 here, so we ignore it; otherwise
* we would have to divide the original verts with it.
*/
- vertex->x = COGL_FIXED_MUL ((tmp.x + COGL_FIXED_0_5), v[2]);
- vertex->y = COGL_FIXED_MUL ((COGL_FIXED_0_5 - tmp.y), v[3]);
- vertex->z = COGL_FIXED_MUL ((tmp.z + COGL_FIXED_0_5), v[2]);
+ vertex->x =
+ CLUTTER_UNITS_FROM_FIXED (COGL_FIXED_MUL ((x + COGL_FIXED_0_5), v[2]));
+ vertex->y =
+ CLUTTER_UNITS_FROM_FIXED (COGL_FIXED_MUL ((COGL_FIXED_0_5 - y), v[3]));
+ vertex->z =
+ CLUTTER_UNITS_FROM_FIXED (COGL_FIXED_MUL ((z + COGL_FIXED_0_5), v[2]));
}
/**
@@ -940,30 +1060,35 @@ clutter_actor_apply_transform_to_point (ClutterActor *self,
const ClutterVertex *point,
ClutterVertex *vertex)
{
- ClutterVertex tmp = { 0, };
ClutterFixed mtx_p[16];
ClutterFixed v[4];
- ClutterFixed w = COGL_FIXED_1;
+ fixed_vertex_t tmp = { 0, };
g_return_if_fail (CLUTTER_IS_ACTOR (self));
g_return_if_fail (point != NULL);
g_return_if_fail (vertex != NULL);
- tmp = *point;
+ tmp.x = CLUTTER_UNITS_TO_FIXED (vertex->x);
+ tmp.y = CLUTTER_UNITS_TO_FIXED (vertex->y);
+ tmp.z = CLUTTER_UNITS_TO_FIXED (vertex->z);
+ tmp.w = COGL_FIXED_1;
/* First we tranform the point using the OpenGL modelview matrix */
- clutter_actor_transform_point (self, &tmp.x, &tmp.y, &tmp.z, &w);
+ clutter_actor_transform_point (self, &tmp.x, &tmp.y, &tmp.z, &tmp.w);
cogl_get_projection_matrix (mtx_p);
cogl_get_viewport (v);
/* Now, transform it again with the projection matrix */
- mtx_transform (mtx_p, &tmp.x, &tmp.y, &tmp.z, &w);
+ mtx_transform (mtx_p, &tmp);
/* Finaly translate from OpenGL coords to window coords */
- vertex->x = MTX_GL_SCALE_X (tmp.x, w, v[2], v[0]);
- vertex->y = MTX_GL_SCALE_Y (tmp.y, w, v[3], v[1]);
- vertex->z = MTX_GL_SCALE_Z (tmp.z, w, v[2], v[0]);
+ vertex->x =
+ CLUTTER_UNITS_FROM_FIXED (MTX_GL_SCALE_X (tmp.x, tmp.w, v[2], v[0]));
+ vertex->y =
+ CLUTTER_UNITS_FROM_FIXED (MTX_GL_SCALE_Y (tmp.y, tmp.w, v[3], v[1]));
+ vertex->z =
+ CLUTTER_UNITS_FROM_FIXED (MTX_GL_SCALE_Z (tmp.z, tmp.w, v[2], v[0]));
}
/* Recursively tranform supplied vertices with the tranform for the current
@@ -971,66 +1096,27 @@ clutter_actor_apply_transform_to_point (ClutterActor *self,
* for all the vertices in one go).
*/
static void
-clutter_actor_transform_vertices_relative (ClutterActor *self,
- ClutterActor *ancestor,
- ClutterVertex verts[4],
- ClutterFixed w[4])
+clutter_actor_transform_vertices_relative (ClutterActor *self,
+ ClutterActor *ancestor,
+ fixed_vertex_t vertices[])
{
- ClutterFixed mtx[16];
- ClutterFixed _x, _y, _z, _w;
+ ClutterActorPrivate *priv = self->priv;
+ ClutterFixed mtx[16];
+ ClutterFixed width, height;
+
+ width = CLUTTER_UNITS_TO_FIXED (priv->allocation.x2 - priv->allocation.x1);
+ height = CLUTTER_UNITS_TO_FIXED (priv->allocation.y2 - priv->allocation.y1);
cogl_push_matrix();
_clutter_actor_apply_modelview_transform_recursive (self, ancestor);
+
cogl_get_modelview_matrix (mtx);
- _x = 0;
- _y = 0;
- _z = 0;
- _w = COGL_FIXED_1;
-
- mtx_transform (mtx, &_x, &_y, &_z, &_w);
-
- verts[0].x = _x;
- verts[0].y = _y;
- verts[0].z = _z;
- w[0] = _w;
-
- _x = self->priv->allocation.x2 - self->priv->allocation.x1;
- _y = 0;
- _z = 0;
- _w = COGL_FIXED_1;
-
- 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 = self->priv->allocation.y2 - self->priv->allocation.y1;
- _z = 0;
- _w = COGL_FIXED_1;
-
- mtx_transform (mtx, &_x, &_y, &_z, &_w);
-
- verts[2].x = _x;
- verts[2].y = _y;
- verts[2].z = _z;
- w[2] = _w;
-
- _x = self->priv->allocation.x2 - self->priv->allocation.x1;
- _y = self->priv->allocation.y2 - self->priv->allocation.y1;
- _z = 0;
- _w = COGL_FIXED_1;
-
- mtx_transform (mtx, &_x, &_y, &_z, &_w);
-
- verts[3].x = _x;
- verts[3].y = _y;
- verts[3].z = _z;
- w[3] = _w;
+ fixed_vertex_transform (mtx, 0, 0, 0, COGL_FIXED_1, &vertices[0]);
+ fixed_vertex_transform (mtx, width, 0, 0, COGL_FIXED_1, &vertices[1]);
+ fixed_vertex_transform (mtx, 0, height, 0, COGL_FIXED_1, &vertices[2]);
+ fixed_vertex_transform (mtx, width, height, 0, COGL_FIXED_1, &vertices[3]);
cogl_pop_matrix();
}
@@ -1045,12 +1131,15 @@ clutter_actor_transform_and_project_box (ClutterActor *self,
const ClutterActorBox *box,
ClutterVertex verts[4])
{
- ClutterActor *stage;
- ClutterFixed mtx[16];
- ClutterFixed mtx_p[16];
- ClutterFixed _x, _y, _z, _w;
- ClutterFixed w[4];
- ClutterFixed v[4];
+ ClutterActor *stage;
+ ClutterFixed mtx[16];
+ ClutterFixed mtx_p[16];
+ ClutterFixed v[4];
+ ClutterFixed width, height;
+ fixed_vertex_t vertices[4];
+
+ width = CLUTTER_UNITS_TO_FIXED (box->x2 - box->x1);
+ height = CLUTTER_UNITS_TO_FIXED (box->y2 - box->y1);
/* We essentially have to dupe some code from clutter_redraw() here
* to make sure GL Matrices etc are initialised if we're called and we
@@ -1071,102 +1160,25 @@ clutter_actor_transform_and_project_box (ClutterActor *self,
_clutter_stage_maybe_setup_viewport (CLUTTER_STAGE (stage));
cogl_push_matrix();
+
_clutter_actor_apply_modelview_transform_recursive (self, NULL);
cogl_get_modelview_matrix (mtx);
- _x = 0;
- _y = 0;
- _z = 0;
- _w = COGL_FIXED_1;
-
- mtx_transform (mtx, &_x, &_y, &_z, &_w);
-
- verts[0].x = _x;
- verts[0].y = _y;
- verts[0].z = _z;
- w[0] = _w;
-
- _x = box->x2 - box->x1;
- _y = 0;
- _z = 0;
- _w = COGL_FIXED_1;
-
- 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 = box->y2 - box->y1;
- _z = 0;
- _w = COGL_FIXED_1;
-
- mtx_transform (mtx, &_x, &_y, &_z, &_w);
-
- verts[2].x = _x;
- verts[2].y = _y;
- verts[2].z = _z;
- w[2] = _w;
-
- _x = box->x2 - box->x1;
- _y = box->y2 - box->y1;
- _z = 0;
- _w = COGL_FIXED_1;
-
- mtx_transform (mtx, &_x, &_y, &_z, &_w);
-
- verts[3].x = _x;
- verts[3].y = _y;
- verts[3].z = _z;
- w[3] = _w;
+ fixed_vertex_transform (mtx, 0, 0, 0, COGL_FIXED_1, &vertices[0]);
+ fixed_vertex_transform (mtx, width, 0, 0, COGL_FIXED_1, &vertices[1]);
+ fixed_vertex_transform (mtx, 0, height, 0, COGL_FIXED_1, &vertices[2]);
+ fixed_vertex_transform (mtx, width, height, 0, COGL_FIXED_1, &vertices[3]);
cogl_pop_matrix();
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]);
+ fixed_vertex_scale (mtx_p, &vertices[0], v, &verts[0]);
+ fixed_vertex_scale (mtx_p, &vertices[1], v, &verts[1]);
+ fixed_vertex_scale (mtx_p, &vertices[2], v, &verts[2]);
+ fixed_vertex_scale (mtx_p, &vertices[3], v, &verts[3]);
}
/**
@@ -1181,10 +1193,10 @@ clutter_actor_transform_and_project_box (ClutterActor *self,
* actor in the plane of @ancestor. 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)
+ * @verts[0] contains (x1, y1)
+ * @verts[1] contains (x2, y1)
+ * @verts[2] contains (x1, y2)
+ * @verts[3] contains (x2, y2)
*
*
* If @ancestor is %NULL the ancestor will be the #ClutterStage. In
@@ -1197,12 +1209,13 @@ clutter_actor_transform_and_project_box (ClutterActor *self,
void
clutter_actor_get_allocation_vertices (ClutterActor *self,
ClutterActor *ancestor,
- ClutterVertex verts[4])
+ ClutterVertex verts[])
{
- ClutterFixed v[4];
- ClutterFixed w[4];
- ClutterActorPrivate *priv;
- ClutterActor *stage;
+ ClutterActorPrivate *priv;
+ ClutterActor *stage;
+ ClutterFixed v[4];
+ fixed_vertex_t vertices[4];
+ fixed_vertex_t tmp = { 0, };
g_return_if_fail (CLUTTER_IS_ACTOR (self));
g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
@@ -1234,28 +1247,33 @@ clutter_actor_get_allocation_vertices (ClutterActor *self,
if (priv->needs_allocation)
_clutter_stage_maybe_relayout (stage);
- clutter_actor_transform_vertices_relative (self, ancestor, verts, w);
+ clutter_actor_transform_vertices_relative (self, ancestor, vertices);
+
cogl_get_viewport (v);
/*
- * The w[3] parameter should always be 1.0 here, so we ignore it; otherwise
- * we would have to devide the original verts with it.
+ * The w[3] parameter should always be 1.0 here, so we ignore it;
+ * otherwise we would have to divide the original verts with it.
*/
- verts[0].x = COGL_FIXED_MUL ((verts[0].x + COGL_FIXED_0_5), v[2]);
- verts[0].y = COGL_FIXED_MUL ((COGL_FIXED_0_5 - verts[0].y), v[3]);
- verts[0].z = COGL_FIXED_MUL ((verts[0].z + COGL_FIXED_0_5), v[2]);
+ tmp.x = COGL_FIXED_MUL ((vertices[0].x + COGL_FIXED_0_5), v[2]);
+ tmp.y = COGL_FIXED_MUL ((COGL_FIXED_0_5 - vertices[0].y), v[3]);
+ tmp.z = COGL_FIXED_MUL ((vertices[0].z + COGL_FIXED_0_5), v[2]);
+ fixed_vertex_to_units (&tmp, &verts[0]);
- verts[1].x = COGL_FIXED_MUL ((verts[1].x + COGL_FIXED_0_5), v[2]);
- verts[1].y = COGL_FIXED_MUL ((COGL_FIXED_0_5 - verts[1].y), v[3]);
- verts[1].z = COGL_FIXED_MUL ((verts[1].z + COGL_FIXED_0_5), v[2]);
+ tmp.x = COGL_FIXED_MUL ((vertices[1].x + COGL_FIXED_0_5), v[2]);
+ tmp.y = COGL_FIXED_MUL ((COGL_FIXED_0_5 - vertices[1].y), v[3]);
+ tmp.z = COGL_FIXED_MUL ((vertices[1].z + COGL_FIXED_0_5), v[2]);
+ fixed_vertex_to_units (&tmp, &verts[1]);
- verts[2].x = COGL_FIXED_MUL ((verts[2].x + COGL_FIXED_0_5), v[2]);
- verts[2].y = COGL_FIXED_MUL ((COGL_FIXED_0_5 - verts[2].y), v[3]);
- verts[2].z = COGL_FIXED_MUL ((verts[2].z + COGL_FIXED_0_5), v[2]);
+ tmp.x = COGL_FIXED_MUL ((vertices[2].x + COGL_FIXED_0_5), v[2]);
+ tmp.y = COGL_FIXED_MUL ((COGL_FIXED_0_5 - vertices[2].y), v[3]);
+ tmp.z = COGL_FIXED_MUL ((vertices[2].z + COGL_FIXED_0_5), v[2]);
+ fixed_vertex_to_units (&tmp, &verts[2]);
- verts[3].x = COGL_FIXED_MUL ((verts[3].x + COGL_FIXED_0_5), v[2]);
- verts[3].y = COGL_FIXED_MUL ((COGL_FIXED_0_5 - verts[3].y), v[3]);
- verts[3].z = COGL_FIXED_MUL ((verts[3].z + COGL_FIXED_0_5), v[2]);
+ tmp.x = COGL_FIXED_MUL ((vertices[3].x + COGL_FIXED_0_5), v[2]);
+ tmp.y = COGL_FIXED_MUL ((COGL_FIXED_0_5 - vertices[3].y), v[3]);
+ tmp.z = COGL_FIXED_MUL ((vertices[3].z + COGL_FIXED_0_5), v[2]);
+ fixed_vertex_to_units (&tmp, &verts[3]);
}
/**
@@ -1941,6 +1959,12 @@ clutter_actor_dispose (GObject *object)
destroy_shader_data (self);
+ if (priv->pango_context)
+ {
+ g_object_unref (priv->pango_context);
+ priv->pango_context = NULL;
+ }
+
g_signal_emit (self, actor_signals[DESTROY], 0);
G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
@@ -6842,17 +6866,18 @@ clutter_scriptable_iface_init (ClutterScriptableIface *iface)
* Since: 0.6
*/
gboolean
-clutter_actor_transform_stage_point (ClutterActor *self,
- ClutterUnit x,
- ClutterUnit y,
- ClutterUnit *x_out,
- ClutterUnit *y_out)
+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;
+ ClutterUnit px, py;
+ ClutterFixed xf, yf, wf, det;
ClutterActorPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
@@ -6865,11 +6890,12 @@ clutter_actor_transform_stage_point (ClutterActor *self,
*
* http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
*
- * and the sample implementaion at http://www.cs.cmu.edu/~ph/src/texfund/.
+ * and the sample implementation 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.
+ * 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_abs_allocation_vertices (self, v);
@@ -6886,9 +6912,11 @@ clutter_actor_transform_stage_point (ClutterActor *self,
#define FP2FX COGL_FIXED_FROM_FLOAT
#define FX2FP COGL_FIXED_TO_DOUBLE
+#define UX2FP CLUTTER_UNITS_TO_FLOAT
+#define UX2FX CLUTTER_UNITS_TO_FIXED
#define FP2INT CLUTTER_FLOAT_TO_INT
-#define DET2X(a,b,c,d) (COGL_FIXED_MUL (a, d) - COGL_FIXED_MUL (b, c))
-#define DET2FP(a,b,c,d) (a*d - b*c)
+#define DET2X(a,b,c,d) (COGL_FIXED_MUL ((a), (d)) - COGL_FIXED_MUL ((b), (c)))
+#define DET2FP(a,b,c,d) ((a) * (d) - (b) * (c))
/*
* First, find mapping from unit uv square to xy quadrilateral; this
@@ -6900,20 +6928,21 @@ clutter_actor_transform_stage_point (ClutterActor *self,
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;
+ {
+ /* affine transform */
+ RQ[0][0] = UX2FX (v[1].x - v[0].x);
+ RQ[1][0] = UX2FX (v[3].x - v[1].x);
+ RQ[2][0] = UX2FX (v[0].x);
+ RQ[0][1] = UX2FX (v[1].y - v[0].y);
+ RQ[1][1] = UX2FX (v[3].y - v[1].y);
+ RQ[2][1] = UX2FX (v[0].y);
RQ[0][2] = 0;
RQ[1][2] = 0;
RQ[2][2] = COGL_FIXED_1;
}
else
- { /*
- * projective transform
+ {
+ /* projective transform
*
* Must do this in floating point, as the del value can overflow the
* range of ClutterFixed for large actors.
@@ -6923,13 +6952,12 @@ clutter_actor_transform_stage_point (ClutterActor *self,
*/
double dx1, dx2, dy1, dy2, del;
- dx1 = FX2FP (v[1].x - v[3].x);
- dx2 = FX2FP (v[2].x - v[3].x);
- dy1 = FX2FP (v[1].y - v[3].y);
- dy2 = FX2FP (v[2].y - v[3].y);
-
- del = DET2FP (dx1,dx2, dy1,dy2);
+ dx1 = UX2FP (v[1].x - v[3].x);
+ dx2 = UX2FP (v[2].x - v[3].x);
+ dy1 = UX2FP (v[1].y - v[3].y);
+ dy2 = UX2FP (v[2].y - v[3].y);
+ del = DET2FP (dx1, dx2, dy1, dy2);
if (!del)
return FALSE;
@@ -6937,16 +6965,20 @@ clutter_actor_transform_stage_point (ClutterActor *self,
* The division here needs to be done in floating point for
* precisions reasons.
*/
- RQ[0][2] = FP2FX (DET2FP (FX2FP(px),dx2, FX2FP(py),dy2) / del);
- RQ[1][2] = FP2FX (DET2FP (dx1,FX2FP(px), dy1,FX2FP(py)) / del);
- RQ[1][2] = FP2FX (DET2FP(dx1,FX2FP(px), dy1,FX2FP(py))/del);
+ RQ[0][2] = FP2FX (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
+ RQ[1][2] = FP2FX (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
+ RQ[1][2] = FP2FX (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
RQ[2][2] = COGL_FIXED_1;
- RQ[0][0] = v[1].x - v[0].x + COGL_FIXED_MUL (RQ[0][2], v[1].x);
- RQ[1][0] = v[2].x - v[0].x + COGL_FIXED_MUL (RQ[1][2], v[2].x);
- RQ[2][0] = v[0].x;
- RQ[0][1] = v[1].y - v[0].y + COGL_FIXED_MUL (RQ[0][2], v[1].y);
- RQ[1][1] = v[2].y - v[0].y + COGL_FIXED_MUL (RQ[1][2], v[2].y);
- RQ[2][1] = v[0].y;
+ RQ[0][0] = UX2FX (v[1].x - v[0].x)
+ + COGL_FIXED_MUL (RQ[0][2], UX2FX (v[1].x));
+ RQ[1][0] = UX2FX (v[2].x - v[0].x)
+ + COGL_FIXED_MUL (RQ[1][2], UX2FX (v[2].x));
+ RQ[2][0] = UX2FX (v[0].x);
+ RQ[0][1] = UX2FX (v[1].y - v[0].y)
+ + COGL_FIXED_MUL (RQ[0][2], UX2FX (v[1].y));
+ RQ[1][1] = UX2FX (v[2].y - v[0].y)
+ + COGL_FIXED_MUL (RQ[1][2], UX2FX (v[2].y));
+ RQ[2][1] = UX2FX (v[0].y);
}
/*
@@ -6985,24 +7017,27 @@ clutter_actor_transform_stage_point (ClutterActor *self,
return FALSE;
/*
- * Now transform our point with the ST matrix; the notional w coordiance
- * is 1, hence the last part is simply added.
+ * Now transform our point with the ST matrix; the notional w
+ * coordinate 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];
+ xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
+ yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
+ wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
/*
* The division needs to be done in floating point for precision reasons.
*/
if (x_out)
*x_out = CLUTTER_UNITS_FROM_FLOAT (FX2FP (xf) / FX2FP (wf));
+
if (y_out)
*y_out = CLUTTER_UNITS_FROM_FLOAT (FX2FP (yf) / FX2FP (wf));
+#undef UX2FX
+#undef UX2FP
#undef FP2FX
#undef FX2FP
#undef FP2INT
@@ -7197,11 +7232,11 @@ clutter_actor_set_shader (ClutterActor *self,
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
g_return_val_if_fail (shader == NULL || CLUTTER_IS_SHADER (shader), FALSE);
- /* if shader passed in is NULL we destroy the shader */
- if (shader == NULL)
- {
- destroy_shader_data (self);
- }
+ if (shader)
+ g_object_ref (shader);
+ else
+ /* if shader passed in is NULL we destroy the shader */
+ destroy_shader_data (self);
actor_priv = self->priv;
shader_data = actor_priv->shader_data;
@@ -7215,15 +7250,9 @@ clutter_actor_set_shader (ClutterActor *self,
shader_value_free);
}
if (shader_data->shader)
- {
- g_object_unref (shader_data->shader);
- shader_data->shader = NULL;
- }
+ g_object_unref (shader_data->shader);
- if (shader)
- {
- shader_data->shader = g_object_ref (shader);
- }
+ shader_data->shader = shader;
if (CLUTTER_ACTOR_IS_VISIBLE (self))
clutter_actor_queue_redraw (self);
@@ -7570,3 +7599,99 @@ clutter_actor_allocate_preferred_size (ClutterActor *self,
clutter_actor_allocate (self, &actor_box, absolute_origin_changed);
}
+
+/**
+ * clutter_actor_grab_key_focus:
+ * @self: a #ClutterActor
+ *
+ * Sets the key focus of the #ClutterStage including @self
+ * to this #ClutterActor.
+ *
+ * Since: 1.0
+ */
+void
+clutter_actor_grab_key_focus (ClutterActor *self)
+{
+ ClutterActor *parent;
+
+ g_return_if_fail (CLUTTER_IS_ACTOR (self));
+
+ parent = clutter_actor_get_parent (self);
+ if (!parent)
+ return;
+
+ parent = clutter_actor_get_stage (self);
+ if (parent && CLUTTER_IS_STAGE (parent))
+ clutter_stage_set_key_focus (CLUTTER_STAGE (parent), self);
+}
+
+/**
+ * clutter_actor_get_pango_context:
+ * @self: a #ClutterActor
+ *
+ * Retrieves the #PangoContext for @self. The actor's #PangoContext
+ * is already configured using the appropriate font map, resolution
+ * and font options.
+ *
+ * Unlike clutter_actor_create_pango_context(), this context is owend
+ * by the #ClutterActor and it will be updated each time the options
+ * stored by the #ClutterBackend change.
+ *
+ * You can use the returned #PangoContext to create a #PangoLayout
+ * and render text using cogl_pango_render_layout() to reuse the
+ * glyphs cache also used by Clutter.
+ *
+ * Return value: the #PangoContext for a #ClutterActor. The returned
+ * #PangoContext is owned by the actor and should not be unreferenced
+ * by the application code
+ *
+ * Since: 1.0
+ */
+PangoContext *
+clutter_actor_get_pango_context (ClutterActor *self)
+{
+ ClutterActorPrivate *priv;
+ ClutterMainContext *ctx;
+
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
+
+ priv = self->priv;
+
+ if (priv->pango_context)
+ return priv->pango_context;
+
+ ctx = CLUTTER_CONTEXT ();
+ priv->pango_context = _clutter_context_get_pango_context (ctx);
+ g_object_ref (priv->pango_context);
+
+ return priv->pango_context;
+}
+
+/**
+ * clutter_actor_create_pango_context:
+ * @self: a #ClutterActor
+ *
+ * Creates a #PangoContext for the given actor. The #PangoContext
+ * is already configured using the appropriate font map, resolution
+ * and font options.
+ *
+ * See also clutter_actor_get_pango_context().
+ *
+ * Return value: the newly created #PangoContext. Use g_object_ref()
+ * on the returned value to deallocate its resources
+ *
+ * Since: 1.0
+ */
+PangoContext *
+clutter_actor_create_pango_context (ClutterActor *self)
+{
+ ClutterMainContext *ctx;
+ PangoContext *retval;
+
+ g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
+
+ ctx = CLUTTER_CONTEXT ();
+ retval = _clutter_context_create_pango_context (ctx);
+
+ return retval;
+}
diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h
index e964a9ef0..af962caf1 100644
--- a/clutter/clutter-actor.h
+++ b/clutter/clutter-actor.h
@@ -31,6 +31,8 @@
/* clutter-actor.h */
#include
+#include
+
#include
#include
#include
@@ -420,6 +422,8 @@ void clutter_actor_set_opacity (ClutterActor
guint8 opacity);
guint8 clutter_actor_get_opacity (ClutterActor *self);
guint8 clutter_actor_get_paint_opacity (ClutterActor *self);
+gboolean clutter_actor_get_paint_visibility (ClutterActor *self);
+
void clutter_actor_set_name (ClutterActor *self,
const gchar *name);
@@ -545,21 +549,24 @@ gboolean clutter_actor_is_rotated (ClutterActor *self);
gboolean clutter_actor_is_scaled (ClutterActor *self);
gboolean clutter_actor_should_pick_paint (ClutterActor *self);
-void clutter_actor_box_get_from_vertices (ClutterVertex vtx[4],
- ClutterActorBox *box);
+void clutter_actor_box_get_from_vertices (ClutterVertex vtx[4],
+ ClutterActorBox *box);
-void clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
- ClutterVertex verts[4]);
+void clutter_actor_get_abs_allocation_vertices (ClutterActor *self,
+ ClutterVertex verts[4]);
-void clutter_actor_apply_transform_to_point (ClutterActor *self,
- const ClutterVertex *point,
- ClutterVertex *vertex);
-void clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
- ClutterActor *ancestor,
- const ClutterVertex *point,
- ClutterVertex *vertex);
+void clutter_actor_apply_transform_to_point (ClutterActor *self,
+ const ClutterVertex *point,
+ ClutterVertex *vertex);
+void clutter_actor_apply_relative_transform_to_point (ClutterActor *self,
+ ClutterActor *ancestor,
+ const ClutterVertex *point,
+ ClutterVertex *vertex);
-gboolean clutter_actor_get_paint_visibility (ClutterActor *self);
+void clutter_actor_grab_key_focus (ClutterActor *self);
+
+PangoContext *clutter_actor_get_pango_context (ClutterActor *self);
+PangoContext *clutter_actor_create_pango_context (ClutterActor *self);
G_END_DECLS
diff --git a/clutter/clutter-alpha.c b/clutter/clutter-alpha.c
index 2114fe38e..dc1dddeba 100644
--- a/clutter/clutter-alpha.c
+++ b/clutter/clutter-alpha.c
@@ -395,6 +395,9 @@ clutter_alpha_set_timeline (ClutterAlpha *alpha,
priv = alpha->priv;
+ if (priv->timeline == timeline)
+ return;
+
if (priv->timeline)
{
g_signal_handlers_disconnect_by_func (priv->timeline,
@@ -565,13 +568,13 @@ clutter_alpha_set_mode (ClutterAlpha *alpha,
priv = alpha->priv;
- priv->mode = mode;
-
/* sanity check to avoid getting an out of sync enum/function mapping */
g_assert (animation_modes[mode].mode == mode);
if (G_LIKELY (animation_modes[mode].func != NULL))
clutter_alpha_set_func (alpha, animation_modes[mode].func, NULL, NULL);
+ priv->mode = mode;
+
g_object_notify (G_OBJECT (alpha), "mode");
}
diff --git a/clutter/clutter-animation.c b/clutter/clutter-animation.c
index 83845057b..eae81250d 100644
--- a/clutter/clutter-animation.c
+++ b/clutter/clutter-animation.c
@@ -739,6 +739,8 @@ clutter_animation_set_actor (ClutterAnimation *animation,
priv = animation->priv;
+ g_object_ref (actor);
+
if (priv->actor)
{
g_object_weak_unref (G_OBJECT (animation),
@@ -750,7 +752,7 @@ clutter_animation_set_actor (ClutterAnimation *animation,
g_object_unref (priv->actor);
}
- priv->actor = g_object_ref (actor);
+ priv->actor = actor;
g_object_weak_ref (G_OBJECT (animation),
on_animation_weak_notify,
priv->actor);
@@ -780,12 +782,11 @@ clutter_animation_get_actor (ClutterAnimation *animation)
}
static inline void
-clutter_animation_set_mode_internal (ClutterAnimation *animation)
+clutter_animation_set_mode_internal (ClutterAnimation *animation,
+ ClutterAlpha *alpha)
{
ClutterAnimationPrivate *priv = animation->priv;
- ClutterAlpha *alpha;
- alpha = clutter_animation_get_alpha (animation);
if (alpha)
clutter_alpha_set_mode (alpha, priv->mode);
}
@@ -810,7 +811,7 @@ clutter_animation_set_mode (ClutterAnimation *animation,
priv = animation->priv;
priv->mode = mode;
- clutter_animation_set_mode_internal (animation);
+ clutter_animation_set_mode_internal (animation, priv->alpha);
g_object_notify (G_OBJECT (animation), "mode");
}
@@ -968,6 +969,9 @@ clutter_animation_set_timeline (ClutterAnimation *animation,
priv = animation->priv;
+ if (timeline && priv->timeline == timeline)
+ return;
+
g_object_freeze_notify (G_OBJECT (animation));
if (priv->timeline)
@@ -1048,6 +1052,19 @@ clutter_animation_set_alpha (ClutterAnimation *animation,
priv = animation->priv;
+ if (!alpha)
+ {
+ ClutterTimeline *timeline;
+
+ timeline = clutter_animation_get_timeline (animation);
+
+ alpha = clutter_alpha_new ();
+ clutter_alpha_set_timeline (alpha, timeline);
+ clutter_animation_set_mode_internal (animation, alpha);
+ }
+
+ g_object_ref_sink (alpha);
+
if (priv->alpha)
{
if (priv->alpha_notify_id)
@@ -1058,18 +1075,7 @@ clutter_animation_set_alpha (ClutterAnimation *animation,
priv->alpha = NULL;
}
- if (!alpha)
- {
- ClutterTimeline *timeline;
-
- timeline = clutter_animation_get_timeline (animation);
-
- alpha = clutter_alpha_new ();
- clutter_alpha_set_timeline (alpha, timeline);
- clutter_animation_set_mode_internal (animation);
- }
-
- priv->alpha = g_object_ref_sink (alpha);
+ priv->alpha = alpha;
priv->alpha_notify_id =
g_signal_connect (alpha, "notify::alpha",
diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c
index 9a599c16b..4c60d40ff 100644
--- a/clutter/clutter-backend.c
+++ b/clutter/clutter-backend.c
@@ -44,10 +44,13 @@
#include "clutter-backend.h"
#include "clutter-debug.h"
#include "clutter-fixed.h"
+#include "clutter-marshal.h"
#include "clutter-private.h"
G_DEFINE_ABSTRACT_TYPE (ClutterBackend, clutter_backend, G_TYPE_OBJECT);
+#define DEFAULT_FONT_NAME "Sans 10"
+
#define CLUTTER_BACKEND_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_BACKEND, ClutterBackendPrivate))
@@ -60,11 +63,24 @@ struct _ClutterBackendPrivate
ClutterFixed resolution;
cairo_font_options_t *font_options;
+
+ gchar *font_name;
};
+enum
+{
+ RESOLUTION_CHANGED,
+ FONT_CHANGED,
+
+ LAST_SIGNAL
+};
+
+static guint backend_signals[LAST_SIGNAL] = { 0, };
+
static void
clutter_backend_dispose (GObject *gobject)
{
+ ClutterBackendPrivate *priv = CLUTTER_BACKEND (gobject)->priv;
ClutterMainContext *clutter_context;
clutter_context = clutter_context_get_default ();
@@ -76,6 +92,8 @@ clutter_backend_dispose (GObject *gobject)
clutter_context->events_queue = NULL;
}
+ g_free (priv->font_name);
+
clutter_backend_set_font_options (CLUTTER_BACKEND (gobject), NULL);
G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject);
@@ -89,6 +107,24 @@ clutter_backend_class_init (ClutterBackendClass *klass)
gobject_class->dispose = clutter_backend_dispose;
g_type_class_add_private (gobject_class, sizeof (ClutterBackendPrivate));
+
+ backend_signals[RESOLUTION_CHANGED] =
+ g_signal_new (I_("resolution-changed"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterBackendClass, resolution_changed),
+ NULL, NULL,
+ clutter_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ backend_signals[FONT_CHANGED] =
+ g_signal_new (I_("font-changed"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterBackendClass, font_changed),
+ NULL, NULL,
+ clutter_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
static void
@@ -388,8 +424,9 @@ clutter_backend_set_resolution (ClutterBackend *backend,
priv->resolution = fixed_dpi;
if (CLUTTER_CONTEXT ()->font_map)
- cogl_pango_font_map_set_resolution (CLUTTER_CONTEXT ()->font_map,
- COGL_FIXED_TO_FLOAT (fixed_dpi));
+ cogl_pango_font_map_set_resolution (CLUTTER_CONTEXT ()->font_map, dpi);
+
+ g_signal_emit (backend, backend_signals[RESOLUTION_CHANGED], 0);
}
/**
@@ -445,6 +482,8 @@ clutter_backend_set_font_options (ClutterBackend *backend,
priv->font_options = cairo_font_options_copy (options);
else
priv->font_options = NULL;
+
+ g_signal_emit (backend, backend_signals[FONT_CHANGED], 0);
}
}
@@ -482,3 +521,63 @@ clutter_backend_get_font_options (ClutterBackend *backend)
return priv->font_options;
}
+/**
+ * clutter_backend_set_font_name:
+ * @backend: a #ClutterBackend
+ * @font_name: the name of the font
+ *
+ * Sets the default font to be used by Clutter. The @font_name string
+ * must either be %NULL, which means that the font name from the
+ * default #ClutterBackend will be used; or be something that can
+ * be parsed by the pango_font_description_from_string() function.
+ *
+ * Since: 1.0
+ */
+void
+clutter_backend_set_font_name (ClutterBackend *backend,
+ const gchar *font_name)
+{
+ ClutterBackendPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_BACKEND (backend));
+
+ priv = backend->priv;
+
+ g_free (priv->font_name);
+
+ if (font_name == NULL || *font_name == '\0')
+ priv->font_name = g_strdup (DEFAULT_FONT_NAME);
+ else
+ priv->font_name = g_strdup (font_name);
+
+ g_signal_emit (backend, backend_signals[FONT_CHANGED], 0);
+}
+
+/**
+ * clutter_backend_get_font_name:
+ * @backend: a #ClutterBackend
+ *
+ * Retrieves the default font name as set by
+ * clutter_backend_set_font_name().
+ *
+ * Return value: the font name for the backend. The returned string is
+ * owned by the #ClutterBackend and should never be modified or freed
+ *
+ * Since: 1.0
+ */
+G_CONST_RETURN gchar *
+clutter_backend_get_font_name (ClutterBackend *backend)
+{
+ ClutterBackendPrivate *priv;
+
+ g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), NULL);
+
+ priv = backend->priv;
+
+ if (G_LIKELY (priv->font_name))
+ return priv->font_name;
+
+ priv->font_name = g_strdup (DEFAULT_FONT_NAME);
+
+ return priv->font_name;
+}
diff --git a/clutter/clutter-backend.h b/clutter/clutter-backend.h
index 27f49c46f..fda1d3413 100644
--- a/clutter/clutter-backend.h
+++ b/clutter/clutter-backend.h
@@ -30,6 +30,8 @@
#include
#include
+#include
+
#include
#include
#include
@@ -77,6 +79,10 @@ struct _ClutterBackendClass
ClutterStage *stage);
void (* ensure_context) (ClutterBackend *backend,
ClutterStage *stage);
+
+ /* signals */
+ void (* resolution_changed) (ClutterBackend *backend);
+ void (* font_changed) (ClutterBackend *backend);
};
GType clutter_backend_get_type (void) G_GNUC_CONST;
@@ -95,6 +101,9 @@ guint clutter_backend_get_double_click_distance (ClutterBackend
void clutter_backend_set_font_options (ClutterBackend *backend,
cairo_font_options_t *options);
cairo_font_options_t *clutter_backend_get_font_options (ClutterBackend *backend);
+void clutter_backend_set_font_name (ClutterBackend *backend,
+ const gchar *font_name);
+G_CONST_RETURN gchar *clutter_backend_get_font_name (ClutterBackend *backend);
G_END_DECLS
diff --git a/clutter/clutter-behaviour-rotate.c b/clutter/clutter-behaviour-rotate.c
index 1a62fee56..3e13c6dab 100644
--- a/clutter/clutter-behaviour-rotate.c
+++ b/clutter/clutter-behaviour-rotate.c
@@ -619,7 +619,7 @@ clutter_behaviour_rotate_get_boundsx (ClutterBehaviourRotate *rotate,
priv = rotate->priv;
- if (angle_start);
+ if (angle_start)
*angle_start = priv->angle_start;
if (angle_end)
diff --git a/clutter/clutter-behaviour.c b/clutter/clutter-behaviour.c
index 11da23d35..006be1bda 100644
--- a/clutter/clutter-behaviour.c
+++ b/clutter/clutter-behaviour.c
@@ -570,6 +570,9 @@ clutter_behaviour_set_alpha (ClutterBehaviour *behave,
priv = behave->priv;
+ if (alpha)
+ g_object_ref_sink (alpha);
+
if (priv->notify_id)
{
CLUTTER_NOTE (BEHAVIOUR, "removing previous notify-id (%d)",
@@ -590,7 +593,6 @@ clutter_behaviour_set_alpha (ClutterBehaviour *behave,
if (alpha)
{
priv->alpha = alpha;
- g_object_ref_sink (priv->alpha);
priv->notify_id = g_signal_connect (priv->alpha, "notify::alpha",
G_CALLBACK(notify_cb),
diff --git a/clutter/clutter-binding-pool.c b/clutter/clutter-binding-pool.c
index 8b567b28d..78a483f72 100644
--- a/clutter/clutter-binding-pool.c
+++ b/clutter/clutter-binding-pool.c
@@ -476,10 +476,129 @@ clutter_binding_pool_install_closure (ClutterBindingPool *pool,
g_hash_table_insert (pool->entries_hash, entry, entry);
}
-gchar **
-clutter_binding_pool_list_actions (ClutterBindingPool *pool)
+/**
+ * clutter_binding_pool_override_action:
+ * @pool: a #ClutterBindingPool
+ * @key_val: key symbol
+ * @modifiers: bitmask of modifiers
+ * @callback: function to be called when the action is activated
+ * @data: data to be passed to @callback
+ * @notify: function to be called when the action is removed
+ * from the pool
+ *
+ * Allows overriding the action for @key_val and @modifiers inside a
+ * #ClutterBindingPool. See clutter_binding_pool_install_action().
+ *
+ * When an action has been activated using clutter_binding_pool_activate()
+ * the passed @callback will be invoked (with @data).
+ *
+ * Actions can be blocked with clutter_binding_pool_block_action()
+ * and then unblocked using clutter_binding_pool_unblock_action().
+ *
+ * Since: 1.0
+ */
+void
+clutter_binding_pool_override_action (ClutterBindingPool *pool,
+ guint key_val,
+ ClutterModifierType modifiers,
+ GCallback callback,
+ gpointer data,
+ GDestroyNotify notify)
{
- return NULL;
+ ClutterBindingEntry *entry;
+ GClosure *closure;
+
+ g_return_if_fail (pool != NULL);
+ g_return_if_fail (key_val != 0);
+ g_return_if_fail (callback != NULL);
+
+ entry = binding_pool_lookup_entry (pool, key_val, modifiers);
+ if (G_UNLIKELY (entry == NULL))
+ {
+ g_warning ("There is no action for the given key symbol "
+ "of %d (modifiers: %d) installed inside the "
+ "binding pool.",
+ key_val, modifiers);
+ return;
+ }
+
+ if (entry->closure)
+ {
+ g_closure_unref (entry->closure);
+ entry->closure = NULL;
+ }
+
+ closure = g_cclosure_new (callback, data, (GClosureNotify) notify);
+ entry->closure = g_closure_ref (closure);
+ g_closure_sink (closure);
+
+ if (G_CLOSURE_NEEDS_MARSHAL (closure))
+ {
+ GClosureMarshal marshal;
+
+ marshal = clutter_marshal_BOOLEAN__STRING_UINT_ENUM;
+ g_closure_set_marshal (closure, marshal);
+ }
+}
+
+/**
+ * clutter_binding_pool_override_closure:
+ * @pool: a #ClutterBindingPool
+ * @key_val: key symbol
+ * @modifiers: bitmask of modifiers
+ * @closure: a #GClosure
+ *
+ * A #GClosure variant of clutter_binding_pool_override_action().
+ *
+ * Allows overriding the action for @key_val and @modifiers inside a
+ * #ClutterBindingPool. See clutter_binding_pool_install_closure().
+ *
+ * When an action has been activated using clutter_binding_pool_activate()
+ * the passed @callback will be invoked (with @data).
+ *
+ * Actions can be blocked with clutter_binding_pool_block_action()
+ * and then unblocked using clutter_binding_pool_unblock_action().
+ *
+ * Since: 1.0
+ */
+void
+clutter_binding_pool_override_closure (ClutterBindingPool *pool,
+ guint key_val,
+ ClutterModifierType modifiers,
+ GClosure *closure)
+{
+ ClutterBindingEntry *entry;
+
+ g_return_if_fail (pool != NULL);
+ g_return_if_fail (key_val != 0);
+ g_return_if_fail (closure != NULL);
+
+ entry = binding_pool_lookup_entry (pool, key_val, modifiers);
+ if (G_UNLIKELY (entry == NULL))
+ {
+ g_warning ("There is no action for the given key symbol "
+ "of %d (modifiers: %d) installed inside the "
+ "binding pool.",
+ key_val, modifiers);
+ return;
+ }
+
+ if (entry->closure)
+ {
+ g_closure_unref (entry->closure);
+ entry->closure = NULL;
+ }
+
+ entry->closure = g_closure_ref (closure);
+ g_closure_sink (closure);
+
+ if (G_CLOSURE_NEEDS_MARSHAL (closure))
+ {
+ GClosureMarshal marshal;
+
+ marshal = clutter_marshal_BOOLEAN__STRING_UINT_ENUM;
+ g_closure_set_marshal (closure, marshal);
+ }
}
/**
@@ -531,6 +650,7 @@ clutter_binding_pool_remove_action (ClutterBindingPool *pool,
ClutterModifierType modifiers)
{
ClutterBindingEntry remove_entry = { 0, };
+ GSList *l;
g_return_if_fail (pool != NULL);
g_return_if_fail (key_val != 0);
@@ -540,6 +660,18 @@ clutter_binding_pool_remove_action (ClutterBindingPool *pool,
remove_entry.key_val = key_val;
remove_entry.modifiers = modifiers;
+ for (l = pool->entries; l != NULL; l = l->data)
+ {
+ ClutterBindingEntry *e = l->data;
+
+ if (e->key_val == remove_entry.key_val &&
+ e->modifiers == remove_entry.modifiers)
+ {
+ pool->entries = g_slist_remove_link (pool->entries, l);
+ break;
+ }
+ }
+
g_hash_table_remove (pool->entries_hash, &remove_entry);
}
diff --git a/clutter/clutter-binding-pool.h b/clutter/clutter-binding-pool.h
index 47692403e..55b5273c8 100644
--- a/clutter/clutter-binding-pool.h
+++ b/clutter/clutter-binding-pool.h
@@ -56,40 +56,49 @@ typedef gboolean (* ClutterBindingActionFunc) (GObject *gobject,
guint key_val,
ClutterModifierType modifiers);
-ClutterBindingPool * clutter_binding_pool_new (const gchar *name);
-ClutterBindingPool * clutter_binding_pool_get_for_class (gpointer klass);
-ClutterBindingPool * clutter_binding_pool_find (const gchar *name);
+ClutterBindingPool * clutter_binding_pool_new (const gchar *name);
+ClutterBindingPool * clutter_binding_pool_get_for_class (gpointer klass);
+ClutterBindingPool * clutter_binding_pool_find (const gchar *name);
-void clutter_binding_pool_install_action (ClutterBindingPool *pool,
- const gchar *action_name,
- guint key_val,
- ClutterModifierType modifiers,
- GCallback callback,
- gpointer data,
- GDestroyNotify notify);
-void clutter_binding_pool_install_closure (ClutterBindingPool *pool,
- const gchar *action_name,
- guint key_val,
- ClutterModifierType modifiers,
- GClosure *closure);
+void clutter_binding_pool_install_action (ClutterBindingPool *pool,
+ const gchar *action_name,
+ guint key_val,
+ ClutterModifierType modifiers,
+ GCallback callback,
+ gpointer data,
+ GDestroyNotify notify);
+void clutter_binding_pool_install_closure (ClutterBindingPool *pool,
+ const gchar *action_name,
+ guint key_val,
+ ClutterModifierType modifiers,
+ GClosure *closure);
+void clutter_binding_pool_override_action (ClutterBindingPool *pool,
+ guint key_val,
+ ClutterModifierType modifiers,
+ GCallback callback,
+ gpointer data,
+ GDestroyNotify notify);
+void clutter_binding_pool_override_closure (ClutterBindingPool *pool,
+ guint key_val,
+ ClutterModifierType modifiers,
+ GClosure *closure);
-gchar ** clutter_binding_pool_list_actions (ClutterBindingPool *pool);
-G_CONST_RETURN gchar *clutter_binding_pool_find_action (ClutterBindingPool *pool,
- guint key_val,
- ClutterModifierType modifiers);
-void clutter_binding_pool_remove_action (ClutterBindingPool *pool,
- guint key_val,
- ClutterModifierType modifiers);
+G_CONST_RETURN gchar *clutter_binding_pool_find_action (ClutterBindingPool *pool,
+ guint key_val,
+ ClutterModifierType modifiers);
+void clutter_binding_pool_remove_action (ClutterBindingPool *pool,
+ guint key_val,
+ ClutterModifierType modifiers);
-gboolean clutter_binding_pool_activate (ClutterBindingPool *pool,
- guint key_val,
- ClutterModifierType modifiers,
- GObject *gobject);
+gboolean clutter_binding_pool_activate (ClutterBindingPool *pool,
+ guint key_val,
+ ClutterModifierType modifiers,
+ GObject *gobject);
-void clutter_binding_pool_block_action (ClutterBindingPool *pool,
- const gchar *action_name);
-void clutter_binding_pool_unblock_action (ClutterBindingPool *pool,
- const gchar *action_name);
+void clutter_binding_pool_block_action (ClutterBindingPool *pool,
+ const gchar *action_name);
+void clutter_binding_pool_unblock_action (ClutterBindingPool *pool,
+ const gchar *action_name);
G_END_DECLS
diff --git a/clutter/clutter-clone-texture.c b/clutter/clutter-clone-texture.c
index 5ea21b7ee..a2350cbab 100644
--- a/clutter/clutter-clone-texture.c
+++ b/clutter/clutter-clone-texture.c
@@ -25,7 +25,7 @@
/**
* SECTION:clutter-clone-texture
- * @short_description: Actor for cloning existing textures in an
+ * @short_description: Actor for cloning existing textures in an
* efficient way.
*
* #ClutterCloneTexture allows the cloning of existing #ClutterTexture based
@@ -39,7 +39,7 @@
#include "clutter-main.h"
#include "clutter-feature.h"
#include "clutter-actor.h"
-#include "clutter-util.h"
+#include "clutter-util.h"
#include "clutter-enum-types.h"
#include "clutter-private.h"
#include "clutter-debug.h"
@@ -157,16 +157,16 @@ clutter_clone_texture_paint (ClutterActor *self)
clutter_actor_get_name (self) ? clutter_actor_get_name (self)
: "unknown");
- /* parent texture may have been hidden, there for need to make sure its
- * realised with resources available.
+ /* parent texture may have been hidden, there for need to make sure its
+ * realised with resources available.
*/
parent_texture = CLUTTER_ACTOR (priv->parent_texture);
if (!CLUTTER_ACTOR_IS_REALIZED (parent_texture))
clutter_actor_realize (parent_texture);
- /* If 'parent' texture isn't visible we run its paint to be sure it
- * updates. Needed for TFP and likely FBOs.
- * Potentially could cause issues
+ /* If 'parent' texture isn't visible we run its paint to be sure it
+ * updates. Needed for TFP and likely FBOs.
+ * Potentially could cause issues
*/
if (!clutter_actor_get_paint_visibility(parent_texture))
{
@@ -221,6 +221,9 @@ set_parent_texture (ClutterCloneTexture *ctexture,
ClutterActor *actor = CLUTTER_ACTOR (ctexture);
gboolean was_visible = CLUTTER_ACTOR_IS_VISIBLE (ctexture);
+ if (priv->parent_texture == texture)
+ return;
+
if (priv->parent_texture)
{
g_object_unref (priv->parent_texture);
@@ -230,7 +233,7 @@ set_parent_texture (ClutterCloneTexture *ctexture,
clutter_actor_hide (actor);
}
- if (texture)
+ if (texture)
{
priv->parent_texture = g_object_ref (texture);
@@ -244,14 +247,14 @@ set_parent_texture (ClutterCloneTexture *ctexture,
clutter_actor_queue_relayout (actor);
}
-
+
}
-static void
+static void
clutter_clone_texture_dispose (GObject *object)
{
ClutterCloneTexture *self = CLUTTER_CLONE_TEXTURE(object);
- ClutterCloneTexturePrivate *priv = self->priv;
+ ClutterCloneTexturePrivate *priv = self->priv;
if (priv->parent_texture)
g_object_unref (priv->parent_texture);
@@ -261,7 +264,7 @@ clutter_clone_texture_dispose (GObject *object)
G_OBJECT_CLASS (clutter_clone_texture_parent_class)->dispose (object);
}
-static void
+static void
clutter_clone_texture_finalize (GObject *object)
{
G_OBJECT_CLASS (clutter_clone_texture_parent_class)->finalize (object);
@@ -391,7 +394,7 @@ clutter_clone_texture_init (ClutterCloneTexture *self)
* clutter_clone_texture_new:
* @texture: a #ClutterTexture, or %NULL
*
- * Creates an efficient 'clone' of a pre-existing texture with which it
+ * Creates an efficient 'clone' of a pre-existing texture with which it
* shares the underlying pixbuf data.
*
* You can use clutter_clone_texture_set_parent_texture() to change the
@@ -412,7 +415,7 @@ clutter_clone_texture_new (ClutterTexture *texture)
/**
* clutter_clone_texture_get_parent_texture:
* @clone: a #ClutterCloneTexture
- *
+ *
* Retrieves the parent #ClutterTexture used by @clone.
*
* Return value: a #ClutterTexture actor, or %NULL
diff --git a/clutter/clutter-entry.c b/clutter/clutter-entry.c
deleted file mode 100644
index 1ae661eda..000000000
--- a/clutter/clutter-entry.c
+++ /dev/null
@@ -1,1795 +0,0 @@
-/*
- * Clutter.
- *
- * An OpenGL based 'interactive canvas' library.
- *
- * Authored By Matthew Allum
- * Neil Jagdish Patel
- *
- * 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-entry
- * @short_description: A single line text entry actor
- *
- * #ClutterEntry is a #ClutterTexture that allows single line text entry.
- *
- * #ClutterEntry is available since Clutter 0.4.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include
-
-#include "clutter-entry.h"
-
-#include "clutter-debug.h"
-#include "clutter-enum-types.h"
-#include "clutter-keysyms.h"
-#include "clutter-main.h"
-#include "clutter-marshal.h"
-#include "clutter-private.h"
-#include "clutter-rectangle.h"
-#include "clutter-units.h"
-
-#include "cogl-pango.h"
-
-#define DEFAULT_FONT_NAME "Sans 10"
-#define ENTRY_CURSOR_WIDTH 1
-#define ENTRY_PADDING 5
-
-G_DEFINE_TYPE (ClutterEntry, clutter_entry, CLUTTER_TYPE_ACTOR);
-
-/* Probably move into main */
-static PangoContext *_context = NULL;
-
-static const ClutterColor default_text_color = { 0, 0, 0, 255 };
-
-enum
-{
- PROP_0,
-
- PROP_FONT_NAME,
- PROP_TEXT,
- PROP_COLOR,
- PROP_ALIGNMENT, /* FIXME */
- PROP_POSITION,
- PROP_CURSOR,
- PROP_TEXT_VISIBLE,
- PROP_MAX_LENGTH,
- PROP_ENTRY_PADDING,
- PROP_X_ALIGN
-};
-
-enum
-{
- TEXT_CHANGED,
- CURSOR_EVENT,
- ACTIVATE,
-
- LAST_SIGNAL
-};
-
-static guint entry_signals[LAST_SIGNAL] = { 0, };
-
-#define CLUTTER_ENTRY_GET_PRIVATE(obj) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ENTRY, ClutterEntryPrivate))
-
-struct _ClutterEntryPrivate
-{
- PangoContext *context;
- PangoFontDescription *desc;
-
- ClutterColor fgcol;
-
- gchar *text;
- gchar *font_name;
- gboolean text_visible;
- gunichar priv_char;
-
- gint extents_width;
- gint extents_height;
-
- gint width;
- gint n_chars; /* number of chars */
- gint n_bytes; /* number of bytes */
-
- guint alignment : 2;
- guint wrap : 1;
- guint use_underline : 1;
- guint use_markup : 1;
- guint ellipsize : 3;
- guint single_line_mode : 1;
- guint wrap_mode : 3;
- gint position;
- gint text_x;
- gint max_length;
- gint entry_padding;
- gdouble x_align;
-
- PangoAttrList *attrs;
- PangoAttrList *effective_attrs;
- PangoLayout *layout;
- gint width_chars;
-
- ClutterGeometry cursor_pos;
- gboolean show_cursor;
-};
-
-static void
-clutter_entry_set_entry_padding (ClutterEntry *entry,
- guint padding)
-{
- ClutterEntryPrivate *priv = entry->priv;
-
- if (priv->entry_padding != padding)
- {
- priv->entry_padding = padding;
-
- if (CLUTTER_ACTOR_IS_VISIBLE (entry))
- clutter_actor_queue_redraw (CLUTTER_ACTOR (entry));
-
- g_object_notify (G_OBJECT (entry), "entry-padding");
- }
-}
-
-static void
-clutter_entry_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ClutterEntry *entry;
- ClutterEntryPrivate *priv;
-
- entry = CLUTTER_ENTRY (object);
- priv = entry->priv;
-
- switch (prop_id)
- {
- case PROP_FONT_NAME:
- clutter_entry_set_font_name (entry, g_value_get_string (value));
- break;
- case PROP_TEXT:
- clutter_entry_set_text (entry, g_value_get_string (value));
- break;
- case PROP_COLOR:
- clutter_entry_set_color (entry, clutter_value_get_color (value));
- break;
- case PROP_ALIGNMENT:
- clutter_entry_set_alignment (entry, g_value_get_enum (value));
- break;
- case PROP_POSITION:
- clutter_entry_set_cursor_position (entry, g_value_get_int (value));
- break;
- case PROP_CURSOR:
- clutter_entry_set_visible_cursor (entry, g_value_get_boolean (value));
- break;
- case PROP_TEXT_VISIBLE:
- clutter_entry_set_visibility (entry, g_value_get_boolean (value));
- break;
- case PROP_MAX_LENGTH:
- clutter_entry_set_max_length (entry, g_value_get_int (value));
- break;
- case PROP_ENTRY_PADDING:
- clutter_entry_set_entry_padding (entry, g_value_get_uint (value));
- break;
- case PROP_X_ALIGN:
- entry->priv->x_align = g_value_get_double (value);
- clutter_actor_queue_redraw (CLUTTER_ACTOR (object));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-clutter_entry_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ClutterEntry *entry;
- ClutterEntryPrivate *priv;
-
- entry = CLUTTER_ENTRY(object);
- priv = entry->priv;
-
- switch (prop_id)
- {
- case PROP_FONT_NAME:
- g_value_set_string (value, priv->font_name);
- break;
- case PROP_TEXT:
- g_value_set_string (value, priv->text);
- break;
- case PROP_COLOR:
- clutter_value_set_color (value, &priv->fgcol);
- break;
- case PROP_ALIGNMENT:
- g_value_set_enum (value, priv->alignment);
- break;
- case PROP_POSITION:
- g_value_set_int (value, priv->position);
- break;
- case PROP_CURSOR:
- g_value_set_boolean (value, priv->show_cursor);
- break;
- case PROP_TEXT_VISIBLE:
- g_value_set_boolean (value, priv->text_visible);
- break;
- case PROP_MAX_LENGTH:
- g_value_set_int (value, priv->max_length);
- break;
- case PROP_ENTRY_PADDING:
- g_value_set_uint (value, priv->entry_padding);
- break;
- case PROP_X_ALIGN:
- g_value_set_double (value, priv->x_align);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-clutter_entry_ensure_layout (ClutterEntry *entry, gint width)
-{
- ClutterEntryPrivate *priv;
-
- priv = entry->priv;
-
- if (!priv->layout)
- {
- priv->layout = pango_layout_new (_context);
-
- if (priv->effective_attrs)
- pango_layout_set_attributes (priv->layout, priv->effective_attrs);
-
- pango_layout_set_alignment (priv->layout, priv->alignment);
- pango_layout_set_ellipsize (priv->layout, priv->ellipsize);
- pango_layout_set_single_paragraph_mode (priv->layout,
- priv->single_line_mode);
-
- pango_layout_set_font_description (priv->layout, priv->desc);
-
- if (priv->text_visible)
- pango_layout_set_text (priv->layout, priv->text, priv->n_bytes);
- else
- {
- GString *str = g_string_sized_new (priv->n_bytes);
- gunichar invisible_char;
- gchar buf[7];
- gint char_len, i;
-
- if (priv->priv_char != 0)
- invisible_char = priv->priv_char;
- else
- invisible_char = '*';
-
- /* we need to convert the string built of invisible characters
- * into UTF-8 for it to be fed to the Pango layout
- */
- memset (buf, 0, sizeof (buf));
- char_len = g_unichar_to_utf8 (invisible_char, buf);
-
- for (i = 0; i < priv->n_chars; i++)
- g_string_append_len (str, buf, char_len);
-
- pango_layout_set_text (priv->layout, str->str, str->len);
-
- g_string_free (str, TRUE);
- }
-
- if (priv->wrap)
- pango_layout_set_wrap (priv->layout, priv->wrap_mode);
-
- if (priv->wrap && width > 0)
- pango_layout_set_width (priv->layout, width * PANGO_SCALE);
- else
- pango_layout_set_width (priv->layout, -1);
-
- /* Prime the cache for the layout */
- cogl_pango_ensure_glyph_cache_for_layout (priv->layout);
- }
-}
-
-static void
-clutter_entry_clear_layout (ClutterEntry *entry)
-{
- if (entry->priv->layout)
- {
- g_object_unref (entry->priv->layout);
- entry->priv->layout = NULL;
- }
-}
-
-static gint
-offset_to_bytes (const gchar *text, gint pos)
-{
- gchar *c = NULL;
- gint i, j, len;
-
- if (pos < 1)
- return pos;
-
- c = g_utf8_next_char (text);
- j = 1;
- len = strlen (text);
-
- for (i = 0; i < len; i++)
- {
- if (&text[i] == c)
- {
- if (j == pos)
- break;
- else
- {
- c = g_utf8_next_char (c);
- j++;
- }
- }
- }
- return i;
-}
-
-
-static void
-clutter_entry_ensure_cursor_position (ClutterEntry *entry)
-{
- ClutterEntryPrivate *priv;
- gint index_;
- PangoRectangle rect;
- gint priv_char_bytes;
-
- priv = entry->priv;
-
- /* If characters are invisible, get the byte-length of the invisible
- * character. If priv_char is 0, we use '*', which is ASCII (1 byte).
- */
- if (!priv->text_visible && priv->priv_char)
- priv_char_bytes = g_unichar_to_utf8 (priv->priv_char, NULL);
- else
- priv_char_bytes = 1;
-
- if (priv->position == -1)
- {
- if (priv->text_visible)
- index_ = strlen (priv->text);
- else
- index_ = priv->n_chars * priv_char_bytes;
- }
- else
- {
- if (priv->text_visible)
- index_ = offset_to_bytes (priv->text, priv->position);
- else
- index_ = priv->position * priv_char_bytes;
- }
-
- pango_layout_get_cursor_pos (priv->layout, index_, &rect, NULL);
- priv->cursor_pos.x = rect.x / PANGO_SCALE;
- priv->cursor_pos.y = rect.y / PANGO_SCALE;
- priv->cursor_pos.width = ENTRY_CURSOR_WIDTH;
- priv->cursor_pos.height = rect.height / PANGO_SCALE;
-
- g_signal_emit (entry, entry_signals[CURSOR_EVENT], 0, &priv->cursor_pos);
-}
-
-static void
-clutter_entry_clear_cursor_position (ClutterEntry *entry)
-{
- entry->priv->cursor_pos.width = 0;
-}
-
-void
-clutter_entry_paint_cursor (ClutterEntry *entry)
-{
- ClutterEntryPrivate *priv;
-
- priv = entry->priv;
-
- if (priv->show_cursor)
- {
- cogl_set_source_color4ub (priv->fgcol.red,
- priv->fgcol.green,
- priv->fgcol.blue,
- priv->fgcol.alpha);
-
- cogl_rectangle (priv->cursor_pos.x,
- priv->cursor_pos.y,
- priv->cursor_pos.width,
- priv->cursor_pos.height);
- }
-}
-
-static void
-clutter_entry_paint (ClutterActor *self)
-{
- ClutterEntry *entry;
- ClutterEntryPrivate *priv;
- PangoRectangle logical;
- gint width, actor_width;
- gint text_width;
- gint cursor_x;
- CoglColor color = { 0, };
-
- entry = CLUTTER_ENTRY(self);
- priv = entry->priv;
-
- if (priv->desc == NULL || priv->text == NULL)
- {
- CLUTTER_NOTE (ACTOR, "layout: %p , desc: %p, text %p",
- priv->layout,
- priv->desc,
- priv->text);
- return;
- }
-
- if (priv->width < 0)
- width = clutter_actor_get_width (self);
- else
- width = priv->width;
-
- cogl_clip_set (0, 0,
- COGL_FIXED_FROM_INT (width),
- COGL_FIXED_FROM_INT (clutter_actor_get_height (self)));
-
- actor_width = width - (2 * priv->entry_padding);
- clutter_entry_ensure_layout (entry, actor_width);
- clutter_entry_ensure_cursor_position (entry);
-
- pango_layout_get_extents (priv->layout, NULL, &logical);
- text_width = logical.width / PANGO_SCALE;
-
- if (actor_width < text_width)
- {
- /* We need to do some scrolling */
- cursor_x = priv->cursor_pos.x;
-
- /* If the cursor is at the begining or the end of the text, the placement
- * is easy, however, if the cursor is in the middle somewhere, we need to
- * make sure the text doesn't move until the cursor is either in the
- * far left or far right
- */
-
- if (priv->position == 0)
- priv->text_x = 0;
- else if (priv->position == -1)
- {
- priv->text_x = actor_width - text_width;
- priv->cursor_pos.x += priv->text_x + priv->entry_padding;
- }
- else
- {
- if (priv->text_x <= 0)
- {
- gint diff = -1 * priv->text_x;
-
- if (cursor_x < diff)
- priv->text_x += diff - cursor_x;
- else if (cursor_x > (diff + actor_width))
- priv->text_x -= cursor_x - (diff+actor_width);
- }
-
- priv->cursor_pos.x += priv->text_x + priv->entry_padding;
- }
-
- }
- else
- {
- priv->text_x = (actor_width - text_width) * priv->x_align;
- priv->cursor_pos.x += priv->text_x + priv->entry_padding;
- }
-
- cogl_color_set_from_4ub (&color,
- priv->fgcol.red,
- priv->fgcol.green,
- priv->fgcol.blue,
- clutter_actor_get_paint_opacity (self));
-
- cogl_pango_render_layout (priv->layout,
- priv->text_x + priv->entry_padding, 0,
- &color, 0);
-
- if (CLUTTER_ENTRY_GET_CLASS (entry)->paint_cursor)
- CLUTTER_ENTRY_GET_CLASS (entry)->paint_cursor (entry);
-
- cogl_clip_unset ();
-}
-
-static void
-clutter_entry_allocate (ClutterActor *self,
- const ClutterActorBox *box,
- gboolean absolute_origin_changed)
-{
- ClutterEntry *entry = CLUTTER_ENTRY (self);
- ClutterEntryPrivate *priv = entry->priv;
- gint width;
-
- width = CLUTTER_UNITS_TO_DEVICE (box->x2 - box->x1);
-
- if (priv->width != width)
- {
- clutter_entry_clear_layout (entry);
- clutter_entry_ensure_layout (entry, width);
-
- priv->width = width;
- }
-
- CLUTTER_ACTOR_CLASS (clutter_entry_parent_class)->allocate (self, box, absolute_origin_changed);
-}
-
-static inline void
-clutter_entry_handle_key_event_internal (ClutterEntry *entry,
- ClutterKeyEvent *event)
-{
- gunichar key_unichar;
- ClutterEntryPrivate *priv = entry->priv;
- gint pos = priv->position;
- gint len = 0;
- gint keyval = clutter_key_event_symbol (event);
-
- if (priv->text)
- len = g_utf8_strlen (priv->text, -1);
-
- switch (keyval)
- {
- case CLUTTER_Return:
- case CLUTTER_KP_Enter:
- case CLUTTER_ISO_Enter:
- g_signal_emit (entry, entry_signals[ACTIVATE], 0);
- break;
-
- case CLUTTER_Escape:
- case CLUTTER_Up:
- case CLUTTER_KP_Up:
- case CLUTTER_Down:
- case CLUTTER_KP_Down:
- case CLUTTER_Shift_L:
- case CLUTTER_Shift_R:
- break;
-
- case CLUTTER_BackSpace:
- if (pos != 0 && len != 0)
- clutter_entry_delete_chars (entry, 1);
- break;
-
- case CLUTTER_Delete:
- case CLUTTER_KP_Delete:
- if (len && pos != -1)
- clutter_entry_delete_text (entry, pos, pos+1);;
- break;
-
- case CLUTTER_Left:
- case CLUTTER_KP_Left:
- if (pos != 0 && len != 0)
- {
- if (pos == -1)
- clutter_entry_set_cursor_position (entry, len - 1);
- else
- clutter_entry_set_cursor_position (entry, pos - 1);
- }
- break;
-
- case CLUTTER_Right:
- case CLUTTER_KP_Right:
- if (pos != -1 && len != 0)
- {
- if (pos != len)
- clutter_entry_set_cursor_position (entry, pos + 1);
- }
- break;
-
- case CLUTTER_End:
- case CLUTTER_KP_End:
- clutter_entry_set_cursor_position (entry, -1);
- break;
-
- case CLUTTER_Begin:
- case CLUTTER_Home:
- case CLUTTER_KP_Home:
- clutter_entry_set_cursor_position (entry, 0);
- break;
-
- default:
- key_unichar = clutter_key_event_unicode (event);
- if (g_unichar_validate (key_unichar))
- clutter_entry_insert_unichar (entry, key_unichar);
- break;
- }
-}
-
-static gboolean
-clutter_entry_key_press (ClutterActor *actor,
- ClutterKeyEvent *event)
-{
- clutter_entry_handle_key_event_internal (CLUTTER_ENTRY (actor), event);
-
- return TRUE;
-}
-
-static void
-clutter_entry_dispose (GObject *object)
-{
- ClutterEntry *self = CLUTTER_ENTRY(object);
- ClutterEntryPrivate *priv;
-
- priv = self->priv;
-
- if (priv->layout)
- {
- g_object_unref (priv->layout);
- priv->layout = NULL;
- }
-
- if (priv->context)
- {
- g_object_unref (priv->context);
- priv->context = NULL;
- }
-
- G_OBJECT_CLASS (clutter_entry_parent_class)->dispose (object);
-}
-
-static void
-clutter_entry_finalize (GObject *object)
-{
- ClutterEntryPrivate *priv = CLUTTER_ENTRY (object)->priv;
-
- if (priv->desc)
- pango_font_description_free (priv->desc);
-
- g_free (priv->text);
- g_free (priv->font_name);
-
- G_OBJECT_CLASS (clutter_entry_parent_class)->finalize (object);
-}
-
-static void
-clutter_entry_class_init (ClutterEntryClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
- GParamSpec *pspec;
-
- klass->paint_cursor = clutter_entry_paint_cursor;
-
- actor_class->paint = clutter_entry_paint;
- actor_class->allocate = clutter_entry_allocate;
- actor_class->key_press_event = clutter_entry_key_press;
-
- gobject_class->finalize = clutter_entry_finalize;
- gobject_class->dispose = clutter_entry_dispose;
- gobject_class->set_property = clutter_entry_set_property;
- gobject_class->get_property = clutter_entry_get_property;
-
- /**
- * ClutterEntry:font-name:
- *
- * The font to be used by the entry, expressed in a string that
- * can be parsed by pango_font_description_from_string().
- *
- * Since: 0.4
- */
- g_object_class_install_property
- (gobject_class, PROP_FONT_NAME,
- g_param_spec_string ("font-name",
- "Font Name",
- "Pango font description",
- NULL,
- CLUTTER_PARAM_READWRITE));
- /**
- * ClutterEntry:text:
- *
- * The text inside the entry.
- *
- * Since: 0.4
- */
- g_object_class_install_property
- (gobject_class, PROP_TEXT,
- g_param_spec_string ("text",
- "Text",
- "Text to render",
- NULL,
- CLUTTER_PARAM_READWRITE));
- /**
- * ClutterEntry:color:
- *
- * The color of the text inside the entry.
- *
- * Since: 0.4
- */
- pspec = clutter_param_spec_color ("color",
- "Color",
- "The color of the text",
- &default_text_color,
- CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_COLOR, pspec);
- /**
- * ClutterEntry:alignment:
- *
- * The preferred alignment for the string.
- *
- * Since: 0.4
- */
- g_object_class_install_property
- (gobject_class, PROP_ALIGNMENT,
- g_param_spec_enum ("alignment",
- "Alignment",
- "The preferred alignment for the string,",
- PANGO_TYPE_ALIGNMENT,
- PANGO_ALIGN_LEFT,
- CLUTTER_PARAM_READWRITE));
- /**
- * ClutterEntry:position:
- *
- * The current input cursor position. -1 is taken to be the end of the text
- *
- * Since: 0.4
- */
- g_object_class_install_property
- (gobject_class, PROP_POSITION,
- g_param_spec_int ("position",
- "Position",
- "The cursor position",
- -1, G_MAXINT,
- -1,
- CLUTTER_PARAM_READWRITE));
-
- /**
- * ClutterEntry:cursor-visible:
- *
- * Whether the input cursor is visible or not.
- *
- * Since: 0.4
- */
- g_object_class_install_property
- (gobject_class, PROP_CURSOR,
- g_param_spec_boolean ( "cursor-visible",
- "Cursor Visible",
- "Whether the input cursor is visible",
- TRUE,
- CLUTTER_PARAM_READWRITE));
-
- /**
- * ClutterEntry:text-visible:
- *
- * Whether the text is visible in plain form, or replaced by the
- * character set by clutter_entry_set_invisible_char().
- *
- * Since: 0.4
- */
- g_object_class_install_property
- (gobject_class, PROP_TEXT_VISIBLE,
- g_param_spec_boolean ("text-visible",
- "Text Visible",
- "Whether the text is visible in plain form",
- TRUE,
- CLUTTER_PARAM_READWRITE));
-
- /**
- * ClutterEntry:max-length:
- *
- * The maximum length of the entry text.
- *
- * Since: 0.4
- */
- g_object_class_install_property
- (gobject_class, PROP_MAX_LENGTH,
- g_param_spec_int ("max-length",
- "Max Length",
- "The maximum length of the entry text",
- 0, G_MAXINT,
- 0,
- CLUTTER_PARAM_READWRITE));
- /**
- * ClutterEntry:entry-padding:
- *
- * The padding space between the text and the entry right and left borders.
- *
- * Since: 0.4
- */
- g_object_class_install_property
- (gobject_class, PROP_ENTRY_PADDING,
- g_param_spec_uint ("entry-padding",
- "Entry Padding",
- "The padding space between the text and the left and "
- "right borders",
- 0, G_MAXUINT,
- ENTRY_PADDING,
- CLUTTER_PARAM_READWRITE));
- /**
- * ClutterEntry:x-align:
- *
- * Horizontal alignment to be used for the text (0.0 for left alignment,
- * 1.0 for right alignment).
- *
- * Since: 0.6
- */
- g_object_class_install_property (gobject_class,
- PROP_X_ALIGN,
- g_param_spec_double ("x-align",
- "Horizontal Alignment",
- "The horizontal alignment to be used for the text",
- 0.0, 1.0, 0.0,
- CLUTTER_PARAM_READWRITE));
- /**
- * ClutterEntry::text-changed:
- * @entry: the actor which received the event
- *
- * The ::text-changed signal is emitted after @entry's text changes
- */
- entry_signals[TEXT_CHANGED] =
- g_signal_new ("text-changed",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterEntryClass, text_changed),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- /**
- * ClutterEntry::cursor-event:
- * @entry: the actor which received the event
- * @geometry: a #ClutterGeometry
- *
- * The ::cursor-event signal is emitted each time the input cursor's geometry
- * changes, this could be a positional or size change. If you would like to
- * implement your own input cursor, set the cursor-visible property to %FALSE,
- * and connect to this signal to position and size your own cursor.
- *
- * Since: 0.4
- */
- entry_signals[CURSOR_EVENT] =
- g_signal_new ("cursor-event",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterEntryClass, cursor_event),
- NULL, NULL,
- clutter_marshal_VOID__BOXED,
- G_TYPE_NONE, 1,
- CLUTTER_TYPE_GEOMETRY | G_SIGNAL_TYPE_STATIC_SCOPE);
-
- /**
- * ClutterEntry::activate:
- * @entry: the actor which received the event
- *
- * The ::activate signal is emitted each time the entry is 'activated'
- * by the user, normally by pressing the 'Enter' key.
- *
- * Since: 0.4
- */
- entry_signals[ACTIVATE] =
- g_signal_new ("activate",
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (ClutterEntryClass, activate),
- NULL, NULL,
- clutter_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- g_type_class_add_private (gobject_class, sizeof (ClutterEntryPrivate));
-}
-
-static void
-clutter_entry_init (ClutterEntry *self)
-{
- ClutterEntryPrivate *priv;
- gdouble resolution;
- gint font_size;
-
- self->priv = priv = CLUTTER_ENTRY_GET_PRIVATE (self);
-
- if (G_UNLIKELY (_context == NULL))
- _context = _clutter_context_create_pango_context (CLUTTER_CONTEXT ());
-
- resolution = pango_cairo_context_get_resolution (_context);
-
- priv->alignment = PANGO_ALIGN_LEFT;
- priv->wrap = FALSE;
- priv->wrap_mode = PANGO_WRAP_WORD;
- priv->ellipsize = PANGO_ELLIPSIZE_NONE;
- priv->use_underline = FALSE;
- priv->use_markup = FALSE;
- priv->layout = NULL;
- priv->text = NULL;
- priv->attrs = NULL;
- priv->position = -1;
- priv->priv_char = '*';
- priv->text_visible = TRUE;
- priv->text_x = 0;
- priv->max_length = 0;
- priv->entry_padding = ENTRY_PADDING;
- priv->x_align = 0.0;
-
- priv->fgcol = default_text_color;
-
- priv->font_name = g_strdup (DEFAULT_FONT_NAME);
- priv->desc = pango_font_description_from_string (priv->font_name);
-
- /* we use the font size to set the default width and height, in case
- * the user doesn't call clutter_actor_set_size().
- */
- font_size = PANGO_PIXELS (pango_font_description_get_size (priv->desc))
- * resolution
- / 72.0;
- clutter_actor_set_size (CLUTTER_ACTOR (self), font_size * 20, 50);
-
- priv->show_cursor = TRUE;
-}
-
-/**
- * clutter_entry_new_with_text:
- * @font_name: the name (and size) of the font to be used
- * @text: the text to be displayed
- *
- * Creates a new #ClutterEntry displaying @text using @font_name.
- *
- * Return value: the newly created #ClutterEntry
- *
- * Since: 0.4
- */
-ClutterActor *
-clutter_entry_new_with_text (const gchar *font_name,
- const gchar *text)
-{
- ClutterActor *entry = clutter_entry_new ();
-
- g_object_set (entry,
- "font-name", font_name,
- "text", text,
- NULL);
- return entry;
-}
-
-/**
- * clutter_entry_new_full:
- * @font_name: the name (and size) of the font to be used
- * @text: the text to be displayed
- * @color: #ClutterColor for text
- *
- * Creates a new #ClutterEntry displaying @text with @color
- * using @font_name.
- *
- * Return value: the newly created #ClutterEntry
- *
- * Since: 0.4
- */
-ClutterActor *
-clutter_entry_new_full (const gchar *font_name,
- const gchar *text,
- const ClutterColor *color)
-{
- ClutterActor *entry;
-
- entry = clutter_entry_new_with_text (font_name, text);
- clutter_entry_set_color (CLUTTER_ENTRY(entry), color);
-
- return entry;
-}
-
-/**
- * clutter_entry_new:
- *
- * Creates a new, empty #ClutterEntry.
- *
- * Returns: the newly created #ClutterEntry
- */
-ClutterActor *
-clutter_entry_new (void)
-{
- ClutterActor *entry = g_object_new (CLUTTER_TYPE_ENTRY,
- NULL);
- clutter_actor_set_size (entry, 50, 50);
-
- return entry;
-}
-
-/**
- * clutter_entry_get_text:
- * @entry: a #ClutterEntry
- *
- * Retrieves the text displayed by @entry.
- *
- * Return value: the text of the entry. The returned string is
- * owned by #ClutterEntry and should not be modified or freed.
- *
- * Since: 0.4
- */
-G_CONST_RETURN gchar *
-clutter_entry_get_text (ClutterEntry *entry)
-{
- g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), NULL);
-
- return entry->priv->text;
-}
-
-/**
- * clutter_entry_set_text:
- * @entry: a #ClutterEntry
- * @text: the text to be displayed
- *
- * Sets @text as the text to be displayed by @entry. The
- * ClutterEntry::text-changed signal is emitted.
- *
- * Since: 0.4
- */
-void
-clutter_entry_set_text (ClutterEntry *entry,
- const gchar *text)
-{
- ClutterEntryPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
- g_return_if_fail (text != NULL);
-
- priv = entry->priv;
-
- g_object_ref (entry);
-
- if (priv->max_length > 0)
- {
- gint len = g_utf8_strlen (text, -1);
-
- if (len < priv->max_length)
- {
- g_free (priv->text);
-
- priv->text = g_strdup (text);
- priv->n_bytes = strlen (text);
- priv->n_chars = len;
- }
- else
- {
- gchar * n = g_malloc0 (priv->max_length + 1);
-
- g_utf8_strncpy (n, text, priv->max_length);
- g_free (priv->text);
-
- priv->text = n;
- priv->n_bytes = strlen (n);
- priv->n_chars = priv->max_length;
- }
- }
- else
- {
- g_free (priv->text);
-
- priv->text = g_strdup (text);
- priv->n_bytes = strlen (text);
- priv->n_chars = g_utf8_strlen (priv->text, -1);
- }
-
- clutter_entry_clear_layout (entry);
- clutter_entry_clear_cursor_position (entry);
- /* Recreate the layout so the glyph cache will be primed */
- clutter_entry_ensure_layout (entry, -1);
-
- if (CLUTTER_ACTOR_IS_VISIBLE (entry))
- clutter_actor_queue_redraw (CLUTTER_ACTOR (entry));
-
- g_signal_emit (G_OBJECT (entry), entry_signals[TEXT_CHANGED], 0);
-
- g_object_notify (G_OBJECT (entry), "text");
- g_object_unref (entry);
-}
-
-/**
- * clutter_entry_get_font_name:
- * @entry: a #ClutterEntry
- *
- * Retrieves the font used by @entry.
- *
- * Return value: a string containing the font name, in a format
- * understandable by pango_font_description_from_string(). The
- * string is owned by #ClutterEntry and should not be modified
- * or freed.
- *
- * Since: 0.4
- */
-G_CONST_RETURN gchar *
-clutter_entry_get_font_name (ClutterEntry *entry)
-{
- g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), NULL);
-
- return entry->priv->font_name;
-}
-
-/**
- * clutter_entry_set_font_name:
- * @entry: a #ClutterEntry
- * @font_name: a font name and size, or %NULL for the default font
- *
- * Sets @font_name as the font used by @entry.
- *
- * @font_name must be a string containing the font name and its
- * size, similarly to what you would feed to the
- * pango_font_description_from_string() function.
- *
- * Since: 0.4
- */
-void
-clutter_entry_set_font_name (ClutterEntry *entry,
- const gchar *font_name)
-{
- ClutterEntryPrivate *priv;
- PangoFontDescription *desc;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
-
- if (!font_name || font_name[0] == '\0')
- font_name = DEFAULT_FONT_NAME;
-
- priv = entry->priv;
-
- if (strcmp (priv->font_name, font_name) == 0)
- return;
-
- desc = pango_font_description_from_string (font_name);
- if (!desc)
- {
- g_warning ("Attempting to create a PangoFontDescription for "
- "font name `%s', but failed.",
- font_name);
- return;
- }
-
- g_object_ref (entry);
-
- g_free (priv->font_name);
- priv->font_name = g_strdup (font_name);
-
- if (priv->desc)
- pango_font_description_free (priv->desc);
-
- priv->desc = desc;
-
- if (entry->priv->text && entry->priv->text[0] != '\0')
- {
- clutter_entry_clear_layout (entry);
- /* Recreate the layout so the glyph cache will be primed */
- clutter_entry_ensure_layout (entry, -1);
-
- if (CLUTTER_ACTOR_IS_VISIBLE (entry))
- clutter_actor_queue_redraw (CLUTTER_ACTOR (entry));
- }
-
- g_object_notify (G_OBJECT (entry), "font-name");
- g_object_unref (entry);
-}
-
-
-/**
- * clutter_entry_set_color:
- * @entry: a #ClutterEntry
- * @color: a #ClutterColor
- *
- * Sets the color of @entry.
- *
- * Since: 0.4
- */
-void
-clutter_entry_set_color (ClutterEntry *entry,
- const ClutterColor *color)
-{
- ClutterActor *actor;
- ClutterEntryPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
- g_return_if_fail (color != NULL);
-
- priv = entry->priv;
-
- g_object_ref (entry);
-
- priv->fgcol.red = color->red;
- priv->fgcol.green = color->green;
- priv->fgcol.blue = color->blue;
- priv->fgcol.alpha = color->alpha;
-
- actor = CLUTTER_ACTOR (entry);
-
- clutter_actor_set_opacity (actor, priv->fgcol.alpha);
-
- if (CLUTTER_ACTOR_IS_VISIBLE (actor))
- clutter_actor_queue_redraw (actor);
-
- g_object_notify (G_OBJECT (entry), "color");
- g_object_unref (entry);
-}
-
-/**
- * clutter_entry_get_color:
- * @entry: a #ClutterEntry
- * @color: return location for a #ClutterColor
- *
- * Retrieves the color of @entry.
- *
- * Since: 0.4
- */
-void
-clutter_entry_get_color (ClutterEntry *entry,
- ClutterColor *color)
-{
- ClutterEntryPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
- g_return_if_fail (color != NULL);
-
- priv = entry->priv;
-
- color->red = priv->fgcol.red;
- color->green = priv->fgcol.green;
- color->blue = priv->fgcol.blue;
- color->alpha = priv->fgcol.alpha;
-}
-
-/**
- * clutter_entry_get_layout:
- * @entry: a #ClutterEntry
- *
- * Gets the #PangoLayout used to display the entry.
- * The layout is useful to e.g. convert text positions to
- * pixel positions.
- * The returned layout is owned by the entry so need not be
- * freed by the caller.
- *
- * Return value: the #PangoLayout for this entry
- *
- * Since: 0.4
- **/
-PangoLayout *
-clutter_entry_get_layout (ClutterEntry *entry)
-{
- g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), NULL);
-
- clutter_entry_ensure_layout (entry, -1);
-
- return entry->priv->layout;
-}
-
-/**
- * clutter_entry_set_alignment:
- * @entry: a #ClutterEntry
- * @alignment: A #PangoAlignment
- *
- * Sets text alignment of the entry.
- *
- * Since: 0.4
- */
-void
-clutter_entry_set_alignment (ClutterEntry *entry,
- PangoAlignment alignment)
-{
- ClutterEntryPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
-
- priv = entry->priv;
-
- if (priv->alignment != alignment)
- {
- g_object_ref (entry);
-
- priv->alignment = alignment;
-
- clutter_entry_clear_layout (entry);
-
- if (CLUTTER_ACTOR_IS_VISIBLE (entry))
- clutter_actor_queue_redraw (CLUTTER_ACTOR (entry));
-
- g_object_notify (G_OBJECT (entry), "alignment");
- g_object_unref (entry);
- }
-}
-
-/**
- * clutter_entry_get_alignment:
- * @entry: a #ClutterEntry
- *
- * Returns the entry's text alignment
- *
- * Return value: The entry's #PangoAlignment
- *
- * Since: 0.4
- */
-PangoAlignment
-clutter_entry_get_alignment (ClutterEntry *entry)
-{
- g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), FALSE);
-
- return entry->priv->alignment;
-}
-
-/**
- * clutter_entry_set_cursor_position:
- * @entry: a #ClutterEntry
- * @position: the position of the cursor.
- *
- * Sets the position of the cursor. The @position must be less than or
- * equal to the number of characters in the entry. A value of -1 indicates
- * that the position should be set after the last character in the entry.
- * Note that this position is in characters, not in bytes.
- *
- * Since: 0.6
- */
-void
-clutter_entry_set_cursor_position (ClutterEntry *entry,
- gint position)
-{
- ClutterEntryPrivate *priv;
- gint len;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
-
- priv = entry->priv;
-
- if (priv->text == NULL)
- return;
-
- len = g_utf8_strlen (priv->text, -1);
-
- if (position < 0 || position >= len)
- priv->position = -1;
- else
- priv->position = position;
-
- clutter_entry_clear_cursor_position (entry);
-
- if (CLUTTER_ACTOR_IS_VISIBLE (entry))
- clutter_actor_queue_redraw (CLUTTER_ACTOR (entry));
-}
-
-/**
- * clutter_entry_get_cursor_position:
- * @entry: a #ClutterEntry
- *
- * Gets the position, in characters, of the cursor in @entry.
- *
- * Return value: the position of the cursor.
- *
- * Since: 0.6
- */
-gint
-clutter_entry_get_cursor_position (ClutterEntry *entry)
-{
- ClutterEntryPrivate *priv;
-
- g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), 0);
-
- priv = entry->priv;
-
- return priv->position;
-}
-
-/**
- * clutter_entry_handle_key_event:
- * @entry: a #ClutterEntry
- * @kev: a #ClutterKeyEvent
- *
- * This function will handle a #ClutterKeyEvent, like those returned in a
- * key-press/release-event, and will translate it for the @entry. This includes
- * non-alphanumeric keys, such as the arrows keys, which will move the
- * input cursor. You should use this function inside a handler for the
- * ClutterStage::key-press-event or ClutterStage::key-release-event.
- *
- * Since: 0.4
- *
- * Deprecated: 0.8: The key events will automatically be handled when
- * giving the key focus to an entry using clutter_stage_set_key_focus().
- */
-void
-clutter_entry_handle_key_event (ClutterEntry *entry,
- ClutterKeyEvent *kev)
-{
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
-
- clutter_entry_handle_key_event_internal (entry, kev);
-}
-
-/**
- * clutter_entry_insert_unichar:
- * @entry: a #ClutterEntry
- * @wc: a Unicode character
- *
- * Insert a character to the right of the current position of the cursor,
- * and updates the position of the cursor.
- *
- * Since: 0.4
- */
-void
-clutter_entry_insert_unichar (ClutterEntry *entry,
- gunichar wc)
-{
- ClutterEntryPrivate *priv;
- GString *new = NULL;
- glong pos;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
- g_return_if_fail (g_unichar_validate (wc));
-
- if (wc == 0)
- return;
-
- priv = entry->priv;
-
- g_object_ref (entry);
-
- new = g_string_new (priv->text);
- pos = offset_to_bytes (priv->text, priv->position);
- new = g_string_insert_unichar (new, pos, wc);
-
- clutter_entry_set_text (entry, new->str);
-
- if (priv->position >= 0)
- clutter_entry_set_cursor_position (entry, priv->position + 1);
-
- g_string_free (new, TRUE);
-
- g_object_notify (G_OBJECT (entry), "text");
- g_object_unref (entry);
-}
-
-/**
- * clutter_entry_delete_chars:
- * @entry: a #ClutterEntry
- * @len: the number of characters to remove.
- *
- * Characters are removed from before the current postion of the cursor.
- *
- * Since: 0.4
- */
-void
-clutter_entry_delete_chars (ClutterEntry *entry,
- guint num)
-{
- ClutterEntryPrivate *priv;
- GString *new = NULL;
- gint len;
- gint pos;
- gint num_pos;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
-
- priv = entry->priv;
-
- if (!priv->text)
- return;
-
- g_object_ref (entry);
-
- len = g_utf8_strlen (priv->text, -1);
- new = g_string_new (priv->text);
-
- if (priv->position == -1)
- {
- num_pos = offset_to_bytes (priv->text, len - num);
- new = g_string_erase (new, num_pos, -1);
- }
- else
- {
- pos = offset_to_bytes (priv->text, priv->position - num);
- num_pos = offset_to_bytes (priv->text, priv->position);
- new = g_string_erase (new, pos, num_pos-pos);
- }
- clutter_entry_set_text (entry, new->str);
-
- if (priv->position > 0)
- clutter_entry_set_cursor_position (entry, priv->position - num);
-
- g_string_free (new, TRUE);
-
- g_object_notify (G_OBJECT (entry), "text");
- g_object_unref (entry);
-}
-
-/**
- * clutter_entry_insert_text:
- * @entry: a #ClutterEntry
- * @text: the text to insert
- * @position: the position at which to insert the text.
- *
- * Insert text at a specifc position.
- *
- * A value of 0 indicates that the text will be inserted before the first
- * character in the entry's text, and a value of -1 indicates that the text
- * will be inserted after the last character in the entry's text.
- *
- * Since: 0.4
- */
-void
-clutter_entry_insert_text (ClutterEntry *entry,
- const gchar *text,
- gssize position)
-{
- ClutterEntryPrivate *priv;
- GString *new = NULL;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
-
- priv = entry->priv;
-
- new = g_string_new (priv->text);
- new = g_string_insert (new, position, text);
-
- clutter_entry_set_text (entry, new->str);
-
- g_string_free (new, TRUE);
-}
-
-/**
- * clutter_entry_delete_text:
- * @entry: a #ClutterEntry
- * @start_pos: the starting position.
- * @end_pos: the end position.
- *
- * Deletes a sequence of characters. The characters that are deleted are
- * those characters at positions from @start_pos up to, but not including,
- * @end_pos. If @end_pos is negative, then the characters deleted will be
- * those characters from @start_pos to the end of the text.
- *
- * Since: 0.4
- */
-void
-clutter_entry_delete_text (ClutterEntry *entry,
- gssize start_pos,
- gssize end_pos)
-{
- ClutterEntryPrivate *priv;
- GString *new = NULL;
- gint start_bytes;
- gint end_bytes;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
-
- priv = entry->priv;
-
- if (!priv->text)
- return;
-
- start_bytes = offset_to_bytes (priv->text, start_pos);
- end_bytes = offset_to_bytes (priv->text, end_pos);
-
- new = g_string_new (priv->text);
- new = g_string_erase (new, start_bytes, end_bytes - start_bytes);
-
- clutter_entry_set_text (entry, new->str);
-
- g_string_free (new, TRUE);
-}
-
-/**
- * clutter_entry_set_visible_cursor:
- * @entry: a #ClutterEntry
- * @visible: whether the input cursor should be visible
- *
- * Sets the visibility of the input cursor.
- *
- * Since: 0.4
- */
-void
-clutter_entry_set_visible_cursor (ClutterEntry *entry,
- gboolean visible)
-{
- ClutterEntryPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
-
- priv = entry->priv;
-
- if (priv->show_cursor != visible)
- {
- priv->show_cursor = visible;
-
- g_object_notify (G_OBJECT (entry), "cursor-visible");
-
- if (CLUTTER_ACTOR_IS_VISIBLE (entry))
- clutter_actor_queue_redraw (CLUTTER_ACTOR (entry));
- }
-}
-
-/**
- * clutter_entry_get_visible_cursor:
- * @entry: a #ClutterEntry
- *
- * Returns the input cursor's visibility
- *
- * Return value: whether the input cursor is visible
- *
- * Since: 0.4
- */
-gboolean
-clutter_entry_get_visible_cursor (ClutterEntry *entry)
-{
- g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), FALSE);
-
- return entry->priv->show_cursor;
-}
-
-/**
- * clutter_entry_set_visibility:
- * @entry: a #ClutterEntry
- * @visible: %TRUE if the contents of the entry are displayed as plaintext.
- *
- * Sets whether the contents of the entry are visible or not. When visibility
- * is set to %FALSE, characters are displayed as the invisible char, and will
- * also appear that way when the text in the entry widget is copied elsewhere.
- *
- * The default invisible char is the asterisk '*', but it can be changed with
- * clutter_entry_set_invisible_char().
- *
- * Since: 0.4
- */
-void
-clutter_entry_set_visibility (ClutterEntry *entry, gboolean visible)
-{
- ClutterEntryPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
-
- priv = entry->priv;
-
- priv->text_visible = visible;
-
- clutter_entry_clear_layout (entry);
- clutter_entry_clear_cursor_position (entry);
-
- if (CLUTTER_ACTOR_IS_VISIBLE (entry))
- clutter_actor_queue_redraw (CLUTTER_ACTOR (entry));
-}
-
-/**
- * clutter_entry_get_visibility:
- * @entry: a #ClutterEntry
- *
- * Returns the entry text visibility.
- *
- * Return value: %TRUE if the contents of the entry are displayed as plaintext.
- *
- * Since: 0.4
- */
-gboolean
-clutter_entry_get_visibility (ClutterEntry *entry)
-{
- g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), TRUE);
-
- return entry->priv->text_visible;
-}
-
-/**
- * clutter_entry_set_invisible_char:
- * @entry: a #ClutterEntry
- * @wc: a Unicode character
- *
- * Sets the character to use in place of the actual text when
- * clutter_entry_set_visibility() has been called to set text visibility
- * to %FALSE. i.e. this is the character used in "password mode" to show the
- * user how many characters have been typed. The default invisible char is an
- * asterisk ('*'). If you set the invisible char to 0, then the user will get
- * no feedback at all; there will be no text on the screen as they type.
- *
- * Since: 0.4
- */
-void
-clutter_entry_set_invisible_char (ClutterEntry *entry, gunichar wc)
-{
- ClutterEntryPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
-
- priv = entry->priv;
-
- priv->priv_char = wc;
-
- if (!priv->text_visible)
- return;
-
- clutter_entry_clear_layout (entry);
- clutter_entry_clear_cursor_position (entry);
-
- if (CLUTTER_ACTOR_IS_VISIBLE (entry))
- clutter_actor_queue_redraw (CLUTTER_ACTOR (entry));
-}
-
-/**
- * clutter_entry_get_invisible_char:
- * @entry: a #ClutterEntry
- *
- * Returns the character to use in place of the actual text when text-visibility
- * is set to %FALSE
- *
- * Return value: a Unicode character
- *
- **/
-gunichar
-clutter_entry_get_invisible_char (ClutterEntry *entry)
-{
- ClutterEntryPrivate *priv;
-
- g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), TRUE);
-
- priv = entry->priv;
-
- return priv->priv_char;
-}
-
-/**
- * clutter_entry_set_max_length:
- * @entry: a #ClutterEntry
- * @max: the maximum number of characters allowed in the entry; 0
- * to disable or -1 to set the length of the current string
- *
- * Sets the maximum allowed length of the contents of the actor. If the
- * current contents are longer than the given length, then they will be
- * truncated to fit.
- *
- * Since: 0.4
- */
-void
-clutter_entry_set_max_length (ClutterEntry *entry,
- gint max)
-{
- ClutterEntryPrivate *priv;
- gchar *new = NULL;
-
- g_return_if_fail (CLUTTER_IS_ENTRY (entry));
-
- priv = entry->priv;
-
- if (priv->max_length != max)
- {
- g_object_ref (entry);
-
- if (max < 0)
- max = g_utf8_strlen (priv->text, -1);
-
- priv->max_length = max;
-
- new = g_strdup (priv->text);
- clutter_entry_set_text (entry, new);
- g_free (new);
-
- g_object_notify (G_OBJECT (entry), "max-length");
- g_object_unref (entry);
- }
-}
-
-/**
- * clutter_entry_get_max_length:
- * @entry: a #ClutterEntry
- *
- * Gets the maximum length of text that can be set into @entry.
- * See clutter_entry_set_max_length().
- *
- * Return value: the maximum number of characters.
- *
- * Since: 0.4
- */
-gint
-clutter_entry_get_max_length (ClutterEntry *entry)
-{
- g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), -1);
-
- return entry->priv->max_length;
-}
diff --git a/clutter/clutter-entry.h b/clutter/clutter-entry.h
deleted file mode 100644
index b43408522..000000000
--- a/clutter/clutter-entry.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Clutter.
- *
- * An OpenGL based 'interactive canvas' library.
- *
- * Authored By Matthew Allum
- * Neil Jagdish Patel .
- */
-
-#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
-#error "Only can be included directly."
-#endif
-
-#ifndef __CLUTTER_ENTRY_H__
-#define __CLUTTER_ENTRY_H__
-
-#include
-#include
-#include
-#include
-
-
-G_BEGIN_DECLS
-
-#define CLUTTER_TYPE_ENTRY (clutter_entry_get_type ())
-
-#define CLUTTER_ENTRY(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
- CLUTTER_TYPE_ENTRY, ClutterEntry))
-
-#define CLUTTER_ENTRY_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), \
- CLUTTER_TYPE_ENTRY, ClutterEntryClass))
-
-#define CLUTTER_IS_ENTRY(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
- CLUTTER_TYPE_ENTRY))
-
-#define CLUTTER_IS_ENTRY_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), \
- CLUTTER_TYPE_ENTRY))
-
-#define CLUTTER_ENTRY_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), \
- CLUTTER_TYPE_ENTRY, ClutterEntryClass))
-
-typedef struct _ClutterEntry ClutterEntry;
-typedef struct _ClutterEntryClass ClutterEntryClass;
-typedef struct _ClutterEntryPrivate ClutterEntryPrivate;
-
-struct _ClutterEntry
-{
- /*< private >*/
- ClutterActor parent_instance;
-
- ClutterEntryPrivate *priv;
-};
-
-/**
- * ClutterEntryClass:
- * @paint_cursor: virtual function for subclasses to use to draw a custom
- * cursor instead of the default one
- * @text_changed: signal class handler for ClutterEntry::text-changed
- * @cursor_event: signal class handler for ClutterEntry::cursor-event
- * @activate: signal class handler for ClutterEntry::activate
- *
- * Class fo entry actors.
- *
- * Since: 0.4
- */
-struct _ClutterEntryClass
-{
- /*< private >*/
- ClutterActorClass parent_class;
-
- /*< public >*/
- /* vfuncs, not signals */
- void (* paint_cursor) (ClutterEntry *entry);
-
- /* signals */
- void (* text_changed) (ClutterEntry *entry);
- void (* cursor_event) (ClutterEntry *entry,
- ClutterGeometry *geometry);
- void (* activate) (ClutterEntry *entry);
-
- /*< private >*/
- /* padding for future */
- void (*_clutter_entry_1) (void);
- void (*_clutter_entry_2) (void);
- void (*_clutter_entry_3) (void);
- void (*_clutter_entry_4) (void);
-};
-
-GType clutter_entry_get_type (void) G_GNUC_CONST;
-
-ClutterActor * clutter_entry_new (void);
-ClutterActor * clutter_entry_new_full (const gchar *font_name,
- const gchar *text,
- const ClutterColor *color);
-ClutterActor * clutter_entry_new_with_text (const gchar *font_name,
- const gchar *text);
-void clutter_entry_set_text (ClutterEntry *entry,
- const gchar *text);
-G_CONST_RETURN gchar *clutter_entry_get_text (ClutterEntry *entry);
-void clutter_entry_set_font_name (ClutterEntry *entry,
- const gchar *font_name);
-G_CONST_RETURN gchar *clutter_entry_get_font_name (ClutterEntry *entry);
-void clutter_entry_set_color (ClutterEntry *entry,
- const ClutterColor *color);
-void clutter_entry_get_color (ClutterEntry *entry,
- ClutterColor *color);
-PangoLayout * clutter_entry_get_layout (ClutterEntry *entry);
-void clutter_entry_set_alignment (ClutterEntry *entry,
- PangoAlignment alignment);
-PangoAlignment clutter_entry_get_alignment (ClutterEntry *entry);
-void clutter_entry_set_cursor_position (ClutterEntry *entry,
- gint position);
-gint clutter_entry_get_cursor_position (ClutterEntry *entry);
-void clutter_entry_insert_unichar (ClutterEntry *entry,
- gunichar wc);
-void clutter_entry_delete_chars (ClutterEntry *entry,
- guint len);
-void clutter_entry_insert_text (ClutterEntry *entry,
- const gchar *text,
- gssize position);
-void clutter_entry_delete_text (ClutterEntry *entry,
- gssize start_pos,
- gssize end_pos);
-void clutter_entry_set_visible_cursor (ClutterEntry *entry,
- gboolean visible);
-gboolean clutter_entry_get_visible_cursor (ClutterEntry *entry);
-
-void clutter_entry_set_visibility (ClutterEntry *entry,
- gboolean visible);
-gboolean clutter_entry_get_visibility (ClutterEntry *entry);
-void clutter_entry_set_invisible_char (ClutterEntry *entry,
- gunichar wc);
-gunichar clutter_entry_get_invisible_char (ClutterEntry *entry);
-void clutter_entry_set_max_length (ClutterEntry *entry,
- gint max);
-gint clutter_entry_get_max_length (ClutterEntry *entry);
-
-#ifndef CLUTTER_DISABLE_DEPRECATED
-void clutter_entry_handle_key_event (ClutterEntry *entry,
- ClutterKeyEvent *kev);
-#endif
-
-G_END_DECLS
-
-#endif /* __CLUTTER_ENTRY_H__ */
diff --git a/clutter/clutter-label.c b/clutter/clutter-label.c
deleted file mode 100644
index 74434e246..000000000
--- a/clutter/clutter-label.c
+++ /dev/null
@@ -1,1347 +0,0 @@
-/*
- * Clutter.
- *
- * An OpenGL based 'interactive canvas' library.
- *
- * Authored By Matthew Allum
- *
- * 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-label
- * @short_description: Actor for displaying text
- *
- * #ClutterLabel is a #ClutterActor that displays text using Pango.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "clutter-label.h"
-#include "clutter-main.h"
-#include "clutter-enum-types.h"
-#include "clutter-private.h"
-#include "clutter-debug.h"
-#include "clutter-units.h"
-
-#include "cogl-pango.h"
-
-#define DEFAULT_FONT_NAME "Sans 10"
-
-G_DEFINE_TYPE (ClutterLabel, clutter_label, CLUTTER_TYPE_ACTOR)
-
-/* Probably move into main */
-static PangoContext *_context = NULL;
-
-static const ClutterColor default_text_color = { 0, 0, 0, 255 };
-
-enum
-{
- PROP_0,
- PROP_FONT_NAME,
- PROP_TEXT,
- PROP_COLOR,
- PROP_ATTRIBUTES,
- PROP_USE_MARKUP,
- PROP_ALIGNMENT,
- PROP_WRAP,
- PROP_WRAP_MODE,
- PROP_JUSTIFY,
- PROP_ELLIPSIZE,
-};
-
-#define CLUTTER_LABEL_GET_PRIVATE(obj) \
-(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_LABEL, ClutterLabelPrivate))
-
-typedef struct _ClutterLabelCachedLayout ClutterLabelCachedLayout;
-
-struct _ClutterLabelCachedLayout
-{
- /* Cached layout. Pango internally caches the computed extents when
- they are requested so there is no need to cache that as well */
- PangoLayout *layout;
- /* The width that used to generate this layout */
- ClutterUnit width;
- /* A number representing the age of this cache (so that when a new
- layout is needed the last used cache is replaced) */
- guint age;
-};
-
-/* We need at least three cached layouts to run the allocation without
- regenerating a new layout. First the layout will be generated at
- full width to get the preferred width, then it will be generated at
- the preferred width to get the preferred height and then it might
- be regenerated at a different width to get the height for the
- actual allocated width */
-#define CLUTTER_LABEL_N_CACHED_LAYOUTS 3
-
-struct _ClutterLabelPrivate
-{
- PangoFontDescription *font_desc;
-
- ClutterColor fgcol;
-
- gchar *text;
- gchar *font_name;
-
- PangoAttrList *attrs;
- PangoAttrList *effective_attrs;
-
- ClutterLabelCachedLayout cached_layouts[CLUTTER_LABEL_N_CACHED_LAYOUTS];
- guint cache_age;
-
- guint alignment : 2;
- guint wrap : 1;
- guint use_underline : 1;
- guint use_markup : 1;
- guint ellipsize : 3;
- guint single_line_mode : 1;
- guint wrap_mode : 3;
- guint justify : 1;
-};
-
-/*
- * clutter_label_create_layout_no_cache:
- * @label: a #ClutterLabel
- * @allocation_width: the width of the layout, or -1
- *
- * Creates a new #PangoLayout for the given @allocation_width, using
- * the layout properties of the @label.
- *
- * This function will not touch the glyphs cache.
- *
- * This function should be used by clutter_label_get_preferred_width()
- * and clutter_label_get_preferred_height().
- */
-static PangoLayout *
-clutter_label_create_layout_no_cache (ClutterLabel *label,
- ClutterUnit allocation_width)
-{
- ClutterLabelPrivate *priv = label->priv;
- PangoLayout *layout;
-
- layout = pango_layout_new (_context);
-
- if (priv->effective_attrs)
- pango_layout_set_attributes (layout, priv->effective_attrs);
-
- pango_layout_set_alignment (layout, priv->alignment);
- pango_layout_set_single_paragraph_mode (layout, priv->single_line_mode);
-
- pango_layout_set_font_description (layout, priv->font_desc);
- pango_layout_set_justify (layout, priv->justify);
-
- if (priv->text)
- {
- if (!priv->use_markup)
- pango_layout_set_text (layout, priv->text, -1);
- else
- pango_layout_set_markup (layout, priv->text, -1);
- }
-
- if (allocation_width > 0 &&
- (priv->ellipsize != PANGO_ELLIPSIZE_NONE || priv->wrap))
- {
- int layout_width, layout_height;
-
- pango_layout_get_size (layout, &layout_width, &layout_height);
-
- /* No need to set ellipsize or wrap if we already have enough
- * space, since we don't want to make the layout wider than it
- * would be otherwise.
- */
-
- if (CLUTTER_UNITS_FROM_PANGO_UNIT (layout_width) > allocation_width)
- {
- if (priv->ellipsize != PANGO_ELLIPSIZE_NONE)
- {
- gint width;
-
- width = allocation_width > 0
- ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width)
- : -1;
-
- pango_layout_set_ellipsize (layout, priv->ellipsize);
- pango_layout_set_width (layout, width);
- }
- else if (priv->wrap)
- {
- gint width;
-
- width = allocation_width > 0
- ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width)
- : -1;
-
- pango_layout_set_wrap (layout, priv->wrap_mode);
- pango_layout_set_width (layout, width);
- }
- }
- }
-
- return layout;
-}
-
-static void
-clutter_label_dirty_cache (ClutterLabel *label)
-{
- ClutterLabelPrivate *priv = label->priv;
- int i;
-
- /* Delete the cached layouts so they will be recreated the next time
- they are needed */
- for (i = 0; i < CLUTTER_LABEL_N_CACHED_LAYOUTS; i++)
- if (priv->cached_layouts[i].layout)
- {
- g_object_unref (priv->cached_layouts[i].layout);
- priv->cached_layouts[i].layout = NULL;
- }
-}
-
-/*
- * clutter_label_create_layout:
- * @label: a #ClutterLabel
- * @allocation_width: the allocation width
- *
- * Like clutter_label_create_layout_no_cache(), but will also ensure
- * the glyphs cache. If a previously cached layout generated using the
- * same width is available then that will be used instead of
- * generating a new one.
- */
-static PangoLayout *
-clutter_label_create_layout (ClutterLabel *label,
- ClutterUnit allocation_width)
-{
- ClutterLabelPrivate *priv = label->priv;
- int i;
- ClutterLabelCachedLayout *oldest_cache = priv->cached_layouts;
- gboolean found_free_cache = FALSE;
-
- /* Search for a cached layout with the same width and keep track of
- the oldest one */
- for (i = 0; i < CLUTTER_LABEL_N_CACHED_LAYOUTS; i++)
- {
- if (priv->cached_layouts[i].layout == NULL)
- {
- /* Always prefer free cache spaces */
- found_free_cache = TRUE;
- oldest_cache = priv->cached_layouts + i;
- }
- /* If this cached layout is using the same width then we can
- just return that directly */
- else if (priv->cached_layouts[i].width == allocation_width)
- {
- CLUTTER_NOTE (ACTOR, "ClutterLabel: %p: cache hit for width %i",
- label, CLUTTER_UNITS_TO_DEVICE (allocation_width));
- return priv->cached_layouts[i].layout;
- }
- else if (!found_free_cache && (priv->cached_layouts[i].age
- < oldest_cache->age))
- oldest_cache = priv->cached_layouts + i;
- }
-
- CLUTTER_NOTE (ACTOR, "ClutterLabel: %p: cache miss for width %i",
- label, CLUTTER_UNITS_TO_DEVICE (allocation_width));
-
- /* If we make it here then we didn't have a cached version so we
- need to recreate the layout */
- if (oldest_cache->layout)
- g_object_unref (oldest_cache->layout);
-
- oldest_cache->layout
- = clutter_label_create_layout_no_cache (label, allocation_width);
-
- cogl_pango_ensure_glyph_cache_for_layout (oldest_cache->layout);
-
- /* Mark the 'time' this cache was created and advance the time */
- oldest_cache->age = priv->cache_age++;
-
- oldest_cache->width = allocation_width;
-
- return oldest_cache->layout;
-}
-
-static void
-clutter_label_paint (ClutterActor *self)
-{
- ClutterLabel *label = CLUTTER_LABEL (self);
- ClutterLabelPrivate *priv = label->priv;
- PangoLayout *layout;
- ClutterActorBox alloc = { 0, };
- CoglColor color = { 0, };
-
- if (priv->font_desc == NULL || priv->text == NULL)
- {
- CLUTTER_NOTE (ACTOR, "desc: %p, text %p",
- priv->font_desc ? priv->font_desc : 0x0,
- priv->text ? priv->text : 0x0);
- return;
- }
-
- CLUTTER_NOTE (PAINT, "painting label (text:`%s')", priv->text);
-
- clutter_actor_get_allocation_box (self, &alloc);
- layout = clutter_label_create_layout (label, alloc.x2 - alloc.x1);
-
- cogl_color_set_from_4ub (&color,
- priv->fgcol.red,
- priv->fgcol.green,
- priv->fgcol.blue,
- clutter_actor_get_paint_opacity (self));
-
- cogl_pango_render_layout (layout, 0, 0, &color, 0);
-}
-
-static void
-clutter_label_get_preferred_width (ClutterActor *self,
- ClutterUnit for_height,
- ClutterUnit *min_width_p,
- ClutterUnit *natural_width_p)
-{
- ClutterLabel *label = CLUTTER_LABEL (self);
- ClutterLabelPrivate *priv = label->priv;
- PangoRectangle logical_rect = { 0, };
- PangoLayout *layout;
- ClutterUnit layout_width;
-
- layout = clutter_label_create_layout (label, -1);
-
- pango_layout_get_extents (layout, NULL, &logical_rect);
-
- layout_width = logical_rect.width > 0
- ? CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.width)
- : 1;
-
- if (min_width_p)
- {
- if (priv->wrap || priv->ellipsize)
- *min_width_p = 1;
- else
- *min_width_p = layout_width;
- }
-
- if (natural_width_p)
- *natural_width_p = layout_width;
-}
-
-static void
-clutter_label_get_preferred_height (ClutterActor *self,
- ClutterUnit for_width,
- ClutterUnit *min_height_p,
- ClutterUnit *natural_height_p)
-{
- ClutterLabel *label = CLUTTER_LABEL (self);
-
- if (for_width == 0)
- {
- if (min_height_p)
- *min_height_p = 0;
-
- if (natural_height_p)
- *natural_height_p = 0;
- }
- else
- {
- PangoLayout *layout;
- PangoRectangle logical_rect = { 0, };
- ClutterUnit height;
-
- layout = clutter_label_create_layout (label, for_width);
-
- pango_layout_get_extents (layout, NULL, &logical_rect);
- height = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_rect.height);
-
- if (min_height_p)
- *min_height_p = height;
-
- if (natural_height_p)
- *natural_height_p = height;
- }
-}
-
-static void
-clutter_label_allocate (ClutterActor *self,
- const ClutterActorBox *box,
- gboolean origin_changed)
-{
- ClutterLabel *label = CLUTTER_LABEL (self);
- ClutterActorClass *parent_class;
-
- /* Ensure that there is a cached label with the right width so that
- we don't need to create the label during the paint run */
- clutter_label_create_layout (label, box->x2 - box->x1);
-
- parent_class = CLUTTER_ACTOR_CLASS (clutter_label_parent_class);
- parent_class->allocate (self, box, origin_changed);
-}
-
-static void
-clutter_label_dispose (GObject *object)
-{
- ClutterLabel *self = CLUTTER_LABEL(object);
- ClutterLabelPrivate *priv;
-
- priv = self->priv;
-
- /* Get rid of the cached layouts */
- clutter_label_dirty_cache (self);
-
- G_OBJECT_CLASS (clutter_label_parent_class)->dispose (object);
-}
-
-static void
-clutter_label_finalize (GObject *object)
-{
- ClutterLabel *self = CLUTTER_LABEL(object);
- ClutterLabelPrivate *priv;
-
- priv = self->priv;
-
- if (priv->font_desc)
- pango_font_description_free (priv->font_desc);
-
- g_free (priv->text);
- g_free (priv->font_name);
-
- G_OBJECT_CLASS (clutter_label_parent_class)->finalize (object);
-}
-
-static void
-clutter_label_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ClutterLabel *label;
- ClutterLabelPrivate *priv;
-
- label = CLUTTER_LABEL(object);
- priv = label->priv;
-
- switch (prop_id)
- {
- case PROP_FONT_NAME:
- clutter_label_set_font_name (label, g_value_get_string (value));
- break;
- case PROP_TEXT:
- clutter_label_set_text (label, g_value_get_string (value));
- break;
- case PROP_COLOR:
- clutter_label_set_color (label, clutter_value_get_color (value));
- break;
- case PROP_ATTRIBUTES:
- clutter_label_set_attributes (label, g_value_get_boxed (value));
- break;
- case PROP_ALIGNMENT:
- clutter_label_set_alignment (label, g_value_get_enum (value));
- break;
- case PROP_USE_MARKUP:
- clutter_label_set_use_markup (label, g_value_get_boolean (value));
- break;
- case PROP_WRAP:
- clutter_label_set_line_wrap (label, g_value_get_boolean (value));
- break;
- case PROP_JUSTIFY:
- clutter_label_set_justify (label, g_value_get_boolean (value));
- break;
- case PROP_WRAP_MODE:
- clutter_label_set_line_wrap_mode (label, g_value_get_enum (value));
- break;
- case PROP_ELLIPSIZE:
- clutter_label_set_ellipsize (label, g_value_get_enum (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-clutter_label_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ClutterLabel *label;
- ClutterLabelPrivate *priv;
-
- label = CLUTTER_LABEL (object);
- priv = label->priv;
-
- switch (prop_id)
- {
- case PROP_FONT_NAME:
- g_value_set_string (value, priv->font_name);
- break;
- case PROP_TEXT:
- g_value_set_string (value, priv->text);
- break;
- case PROP_COLOR:
- clutter_value_set_color (value, &priv->fgcol);
- break;
- case PROP_ATTRIBUTES:
- g_value_set_boxed (value, priv->attrs);
- break;
- case PROP_ALIGNMENT:
- g_value_set_enum (value, priv->alignment);
- break;
- case PROP_USE_MARKUP:
- g_value_set_boolean (value, priv->use_markup);
- break;
- case PROP_JUSTIFY:
- g_value_set_boolean (value, priv->justify);
- break;
- case PROP_WRAP:
- g_value_set_boolean (value, priv->wrap);
- break;
- case PROP_WRAP_MODE:
- g_value_set_enum (value, priv->wrap_mode);
- break;
- case PROP_ELLIPSIZE:
- g_value_set_enum (value, priv->ellipsize);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-clutter_label_class_init (ClutterLabelClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
- GParamSpec *pspec;
-
- actor_class->paint = clutter_label_paint;
- actor_class->get_preferred_width = clutter_label_get_preferred_width;
- actor_class->get_preferred_height = clutter_label_get_preferred_height;
- actor_class->allocate = clutter_label_allocate;
-
- gobject_class->finalize = clutter_label_finalize;
- gobject_class->dispose = clutter_label_dispose;
- gobject_class->set_property = clutter_label_set_property;
- gobject_class->get_property = clutter_label_get_property;
-
- /**
- * ClutterLabel:font-name:
- *
- * The font to be used by the #ClutterLabel, as a string
- * that can be parsed by pango_font_description_from_string().
- *
- * Since: 0.2
- */
- pspec = g_param_spec_string ("font-name",
- "Font Name",
- "The font to be used by the label",
- NULL,
- CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_FONT_NAME, pspec);
-
- pspec = g_param_spec_string ("text",
- "Text",
- "The text to render",
- NULL,
- CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_TEXT, pspec);
-
- pspec = clutter_param_spec_color ("color",
- "Font Color",
- "Color of the font used by the label",
- &default_text_color,
- CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_COLOR, pspec);
-
- pspec = g_param_spec_boxed ("attributes",
- "Attributes",
- "A list of style attributes to apply to "
- "the text of the label",
- PANGO_TYPE_ATTR_LIST,
- CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, pspec);
-
- /**
- * ClutterLabel:use-markup:
- *
- * Whether the text of the label includes Pango markup. See
- * pango_layout_set_markup() in the Pango documentation.
- *
- * Since: 0.2
- */
- pspec = g_param_spec_boolean ("use-markup",
- "Use markup",
- "Whether or not the text of the label "
- "includes Pango markup",
- FALSE,
- CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_USE_MARKUP, pspec);
-
- /**
- * ClutterLabel:wrap:
- *
- * Whether to wrap the lines of #ClutterLabel:text if the contents
- * exceed the available allocation. The wrapping strategy is
- * controlled by the #ClutterLabel:wrap-mode property.
- *
- * Since: 0.2
- */
- pspec = g_param_spec_boolean ("wrap",
- "Line wrap",
- "If set, wrap the lines if the text "
- "becomes too wide",
- FALSE,
- CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_WRAP, pspec);
-
- /**
- * ClutterLabel:wrap-mode:
- *
- * If #ClutterLabel:wrap is set to %TRUE, this property will
- * control how the text is wrapped.
- *
- * Since: 0.2
- */
- pspec = g_param_spec_enum ("wrap-mode",
- "Line wrap mode",
- "Control how line-wrapping is done",
- PANGO_TYPE_WRAP_MODE,
- PANGO_WRAP_WORD,
- CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_WRAP_MODE, pspec);
-
- pspec = g_param_spec_enum ("ellipsize",
- "Ellipsize",
- "The preferred place to ellipsize the string, "
- "if the label does not have enough room to "
- "display the entire string",
- PANGO_TYPE_ELLIPSIZE_MODE,
- PANGO_ELLIPSIZE_NONE,
- CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_ELLIPSIZE, pspec);
-
- /**
- * ClutterLabel:alignment:
- *
- * The preferred alignment for the text. This property controls
- * the alignment of multi-line paragraphs.
- *
- * Since: 0.2
- */
- pspec = g_param_spec_enum ("alignment",
- "Alignment",
- "The preferred alignment for the string, "
- "for multi-line text",
- PANGO_TYPE_ALIGNMENT,
- PANGO_ALIGN_LEFT,
- CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_ALIGNMENT, pspec);
-
- /**
- * ClutterLabel:justify:
- *
- * Whether the contents of the label should be justified on both
- * margins.
- *
- * Since: 0.6
- */
- pspec = g_param_spec_boolean ("justify",
- "Justify",
- "Whether the contents of the label "
- "should be justified",
- FALSE,
- CLUTTER_PARAM_READWRITE);
- g_object_class_install_property (gobject_class, PROP_JUSTIFY, pspec);
-
- g_type_class_add_private (gobject_class, sizeof (ClutterLabelPrivate));
-}
-
-static void
-clutter_label_init (ClutterLabel *self)
-{
- ClutterLabelPrivate *priv;
- int i;
-
- self->priv = priv = CLUTTER_LABEL_GET_PRIVATE (self);
-
- if (G_UNLIKELY (_context == NULL))
- _context = _clutter_context_create_pango_context (CLUTTER_CONTEXT ());
-
- priv->alignment = PANGO_ALIGN_LEFT;
- priv->wrap = FALSE;
- priv->wrap_mode = PANGO_WRAP_WORD;
- priv->ellipsize = PANGO_ELLIPSIZE_NONE;
- priv->use_underline = FALSE;
- priv->use_markup = FALSE;
- priv->justify = FALSE;
-
- for (i = 0; i < CLUTTER_LABEL_N_CACHED_LAYOUTS; i++)
- priv->cached_layouts[i].layout = NULL;
-
- priv->text = NULL;
- priv->attrs = NULL;
-
- priv->fgcol = default_text_color;
-
- priv->font_name = g_strdup (DEFAULT_FONT_NAME);
- priv->font_desc = pango_font_description_from_string (priv->font_name);
-}
-
-/**
- * clutter_label_new_with_text:
- * @font_name: the name (and size) of the font to be used
- * @text: the text to be displayed
- *
- * Creates a new #ClutterLabel displaying @text using @font_name.
- *
- * Return value: a #ClutterLabel
- */
-ClutterActor*
-clutter_label_new_with_text (const gchar *font_name,
- const gchar *text)
-{
- return g_object_new (CLUTTER_TYPE_LABEL,
- "font-name", font_name,
- "text", text,
- NULL);
-}
-
-/**
- * clutter_label_new_full:
- * @font_name: the name (and size) of the font to be used
- * @text: the text to be displayed
- * @color: #ClutterColor for text
- *
- * Creates a new #ClutterLabel displaying @text with @color
- * using @font_name.
- *
- * Return value: a #ClutterLabel
- */
-ClutterActor*
-clutter_label_new_full (const gchar *font_name,
- const gchar *text,
- const ClutterColor *color)
-{
- return g_object_new (CLUTTER_TYPE_LABEL,
- "font-name", font_name,
- "text", text,
- "color", color,
- NULL);
-}
-
-/**
- * clutter_label_new:
- *
- * Creates a new, empty #ClutterLabel.
- *
- * Returns: the newly created #ClutterLabel
- */
-ClutterActor *
-clutter_label_new (void)
-{
- return g_object_new (CLUTTER_TYPE_LABEL, NULL);
-}
-
-/**
- * clutter_label_get_text:
- * @label: a #ClutterLabel
- *
- * Retrieves the text displayed by @label
- *
- * Return value: the text of the label. The returned string is
- * owned by #ClutterLabel and should not be modified or freed.
- */
-G_CONST_RETURN gchar *
-clutter_label_get_text (ClutterLabel *label)
-{
- g_return_val_if_fail (CLUTTER_IS_LABEL (label), NULL);
-
- return label->priv->text;
-}
-
-/**
- * clutter_label_set_text:
- * @label: a #ClutterLabel
- * @text: the text to be displayed
- *
- * Sets @text as the text to be displayed by @label.
- */
-void
-clutter_label_set_text (ClutterLabel *label,
- const gchar *text)
-{
- ClutterLabelPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_LABEL (label));
-
- priv = label->priv;
-
- g_free (priv->text);
-
- priv->text = g_strdup (text);
-
- clutter_label_dirty_cache (label);
-
- clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
-
- g_object_notify (G_OBJECT (label), "text");
-}
-
-/**
- * clutter_label_get_font_name:
- * @label: a #ClutterLabel
- *
- * Retrieves the font used by @label.
- *
- * Return value: a string containing the font name, in a format
- * understandable by pango_font_description_from_string(). The
- * string is owned by @label and should not be modified
- * or freed.
- */
-G_CONST_RETURN gchar *
-clutter_label_get_font_name (ClutterLabel *label)
-{
- g_return_val_if_fail (CLUTTER_IS_LABEL (label), NULL);
-
- return label->priv->font_name;
-}
-
-/**
- * clutter_label_set_font_name:
- * @label: a #ClutterLabel
- * @font_name: a font name and size, or %NULL for the default font
- *
- * Sets @font_name as the font used by @label.
- *
- * @font_name must be a string containing the font name and its
- * size, similarly to what you would feed to the
- * pango_font_description_from_string() function.
- */
-void
-clutter_label_set_font_name (ClutterLabel *label,
- const gchar *font_name)
-{
- ClutterLabelPrivate *priv;
- PangoFontDescription *desc;
-
- g_return_if_fail (CLUTTER_IS_LABEL (label));
-
- if (!font_name || font_name[0] == '\0')
- font_name = DEFAULT_FONT_NAME;
-
- priv = label->priv;
-
- if (strcmp (priv->font_name, font_name) == 0)
- return;
-
- desc = pango_font_description_from_string (font_name);
- if (!desc)
- {
- g_warning ("Attempting to create a PangoFontDescription for "
- "font name `%s', but failed.",
- font_name);
- return;
- }
-
- g_free (priv->font_name);
- priv->font_name = g_strdup (font_name);
-
- if (priv->font_desc)
- pango_font_description_free (priv->font_desc);
-
- priv->font_desc = desc;
-
- clutter_label_dirty_cache (label);
-
- if (label->priv->text && label->priv->text[0] != '\0')
- clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
-
- g_object_notify (G_OBJECT (label), "font-name");
-}
-
-
-/**
- * clutter_label_set_color:
- * @label: a #ClutterLabel
- * @color: a #ClutterColor
- *
- * Sets the color of @label.
- */
-void
-clutter_label_set_color (ClutterLabel *label,
- const ClutterColor *color)
-{
- ClutterActor *actor;
- ClutterLabelPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_LABEL (label));
- g_return_if_fail (color != NULL);
-
- priv = label->priv;
-
- g_object_ref (label);
-
- priv->fgcol.red = color->red;
- priv->fgcol.green = color->green;
- priv->fgcol.blue = color->blue;
- priv->fgcol.alpha = color->alpha;
-
- actor = CLUTTER_ACTOR (label);
-
- clutter_actor_set_opacity (actor, priv->fgcol.alpha);
-
- if (CLUTTER_ACTOR_IS_VISIBLE (actor))
- clutter_actor_queue_redraw (actor);
-
- g_object_notify (G_OBJECT (label), "color");
- g_object_unref (label);
-}
-
-/**
- * clutter_label_get_color:
- * @label: a #ClutterLabel
- * @color: return location for a #ClutterColor
- *
- * Retrieves the color of @label.
- */
-void
-clutter_label_get_color (ClutterLabel *label,
- ClutterColor *color)
-{
- ClutterLabelPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_LABEL (label));
- g_return_if_fail (color != NULL);
-
- priv = label->priv;
-
- color->red = priv->fgcol.red;
- color->green = priv->fgcol.green;
- color->blue = priv->fgcol.blue;
- color->alpha = priv->fgcol.alpha;
-}
-
-/**
- * clutter_label_set_ellipsize:
- * @label: a #ClutterLabel
- * @mode: a #PangoEllipsizeMode
- *
- * Sets the mode used to ellipsize (add an ellipsis: "...") to the text
- * if there is not enough space to render the entire string.
- *
- * Since: 0.2
- **/
-void
-clutter_label_set_ellipsize (ClutterLabel *label,
- PangoEllipsizeMode mode)
-{
- ClutterLabelPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_LABEL (label));
- g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE &&
- mode <= PANGO_ELLIPSIZE_END);
-
- priv = label->priv;
-
- if ((PangoEllipsizeMode) priv->ellipsize != mode)
- {
- priv->ellipsize = mode;
-
- clutter_label_dirty_cache (label);
-
- clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
-
- g_object_notify (G_OBJECT (label), "ellipsize");
- }
-}
-
-/**
- * clutter_label_get_ellipsize:
- * @label: a #ClutterLabel
- *
- * Returns the ellipsizing position of the label.
- * See clutter_label_set_ellipsize().
- *
- * Return value: #PangoEllipsizeMode
- *
- * Since: 0.2
- **/
-PangoEllipsizeMode
-clutter_label_get_ellipsize (ClutterLabel *label)
-{
- g_return_val_if_fail (CLUTTER_IS_LABEL (label), PANGO_ELLIPSIZE_NONE);
-
- return label->priv->ellipsize;
-}
-
-/**
- * clutter_label_set_line_wrap:
- * @label: a #ClutterLabel
- * @wrap: the setting
- *
- * Toggles line wrapping within the #ClutterLabel widget. %TRUE makes
- * it break lines if text exceeds the widget's size. %FALSE lets the
- * text get cut off by the edge of the widget if it exceeds the widget
- * size.
- *
- * Since: 0.2
- */
-void
-clutter_label_set_line_wrap (ClutterLabel *label,
- gboolean wrap)
-{
- ClutterLabelPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_LABEL (label));
-
- priv = label->priv;
-
- wrap = wrap != FALSE;
-
- if (priv->wrap != wrap)
- {
- priv->wrap = wrap;
-
- clutter_label_dirty_cache (label);
-
- clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
-
- g_object_notify (G_OBJECT (label), "wrap");
- }
-}
-
-/**
- * clutter_label_get_line_wrap:
- * @label: a #ClutterLabel
- *
- * Returns whether lines in the label are automatically wrapped.
- * See clutter_label_set_line_wrap ().
- *
- * Return value: %TRUE if the lines of the label are automatically wrapped.
- *
- * Since: 0.2
- */
-gboolean
-clutter_label_get_line_wrap (ClutterLabel *label)
-{
- g_return_val_if_fail (CLUTTER_IS_LABEL (label), FALSE);
-
- return label->priv->wrap;
-}
-
-/**
- * clutter_label_set_line_wrap_mode:
- * @label: a #ClutterLabel
- * @wrap_mode: the line wrapping mode
- *
- * If line wrapping is on (see clutter_label_set_line_wrap()) this controls how
- * the line wrapping is done. The default is %PANGO_WRAP_WORD which means
- * wrap on word boundaries.
- *
- * Since: 0.2
- **/
-void
-clutter_label_set_line_wrap_mode (ClutterLabel *label,
- PangoWrapMode wrap_mode)
-{
- ClutterLabelPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_LABEL (label));
-
- priv = label->priv;
-
- if (priv->wrap_mode != wrap_mode)
- {
- priv->wrap_mode = wrap_mode;
-
- clutter_label_dirty_cache (label);
-
- clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
-
- g_object_notify (G_OBJECT (label), "wrap-mode");
- }
-}
-
-/**
- * clutter_label_get_line_wrap_mode:
- * @label: a #ClutterLabel
- *
- * Returns line wrap mode used by the label.
- * See clutter_label_set_line_wrap_mode ().
- *
- * Return value: %TRUE if the lines of the label are automatically wrapped.
- *
- * Since: 0.2
- */
-PangoWrapMode
-clutter_label_get_line_wrap_mode (ClutterLabel *label)
-{
- g_return_val_if_fail (CLUTTER_IS_LABEL (label), FALSE);
-
- return label->priv->wrap_mode;
-}
-
-/**
- * clutter_label_get_layout:
- * @label: a #ClutterLabel
- *
- * Gets the #PangoLayout used to display the label.
- * The layout is useful to e.g. convert text positions to
- * pixel positions.
- * The returned layout is owned by the label so need not be
- * freed by the caller.
- *
- * Return value: the #PangoLayout for this label
- *
- * Since: 0.2
- **/
-PangoLayout *
-clutter_label_get_layout (ClutterLabel *label)
-{
- ClutterUnit width;
-
- g_return_val_if_fail (CLUTTER_IS_LABEL (label), NULL);
-
- width = clutter_actor_get_widthu (CLUTTER_ACTOR (label));
-
- return clutter_label_create_layout (label, width);
-}
-
-static inline void
-clutter_label_set_attributes_internal (ClutterLabel *label,
- PangoAttrList *attrs)
-{
-}
-
-/**
- * clutter_label_set_attributes:
- * @label: a #ClutterLabel
- * @attrs: a #PangoAttrList
- *
- * Sets a #PangoAttrList; the attributes in the list are applied to the
- * label text. The attributes set with this function will be ignored
- * if the "use_markup" property
- * is %TRUE.
- *
- * Since: 0.2
- **/
-void
-clutter_label_set_attributes (ClutterLabel *label,
- PangoAttrList *attrs)
-{
- ClutterLabelPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_LABEL (label));
-
- priv = label->priv;
-
- if (attrs)
- pango_attr_list_ref (attrs);
-
- if (priv->attrs)
- pango_attr_list_unref (priv->attrs);
-
- if (!priv->use_markup)
- {
- if (attrs)
- pango_attr_list_ref (attrs);
-
- if (priv->effective_attrs)
- pango_attr_list_unref (priv->effective_attrs);
-
- priv->effective_attrs = attrs;
- }
-
- priv->attrs = attrs;
-
- clutter_label_dirty_cache (label);
-
- g_object_notify (G_OBJECT (label), "attributes");
-
- clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
-}
-
-/**
- * clutter_label_get_attributes:
- * @label: a #ClutterLabel
- *
- * Gets the attribute list that was set on the label using
- * clutter_label_set_attributes(), if any.
- *
- * Return value: the attribute list, or %NULL if none was set.
- *
- * Since: 0.2
- **/
-PangoAttrList *
-clutter_label_get_attributes (ClutterLabel *label)
-{
- g_return_val_if_fail (CLUTTER_IS_LABEL (label), NULL);
-
- return label->priv->attrs;
-}
-
-/**
- * clutter_label_set_use_markup:
- * @label: a #ClutterLabel
- * @setting: %TRUE if the label's text should be parsed for markup.
- *
- * Sets whether the text of the label contains markup in Pango's text markup
- * language.
- **/
-void
-clutter_label_set_use_markup (ClutterLabel *label,
- gboolean setting)
-{
- ClutterLabelPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_LABEL (label));
-
- priv = label->priv;
-
- if (priv->use_markup != setting)
- {
- priv->use_markup = setting;
-
- clutter_label_dirty_cache (label);
-
- clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
-
- g_object_notify (G_OBJECT (label), "use-markup");
- }
-}
-
-/**
- * clutter_label_get_use_markup:
- * @label: a #ClutterLabel
- *
- * Returns whether the label's text is interpreted as marked up with
- * the Pango text markup
- * language. See clutter_label_set_use_markup ().
- *
- * Return value: %TRUE if the label's text will be parsed for markup.
- **/
-gboolean
-clutter_label_get_use_markup (ClutterLabel *label)
-{
- g_return_val_if_fail (CLUTTER_IS_LABEL (label), FALSE);
-
- return label->priv->use_markup;
-}
-
-/**
- * clutter_label_set_alignment:
- * @label: a #ClutterLabel
- * @alignment: A #PangoAlignment
- *
- * Sets text alignment of the label.
- *
- * The alignment will only be used when the contents of the
- * label are enough to wrap, and the #ClutterLabel:wrap
- * property is set to %TRUE.
- **/
-void
-clutter_label_set_alignment (ClutterLabel *label,
- PangoAlignment alignment)
-{
- ClutterLabelPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_LABEL (label));
-
- priv = label->priv;
-
- if (priv->alignment != alignment)
- {
- priv->alignment = alignment;
-
- clutter_label_dirty_cache (label);
-
- clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
-
- g_object_notify (G_OBJECT (label), "alignment");
- }
-}
-
-/**
- * clutter_label_get_alignment:
- * @label: a #ClutterLabel
- *
- * Returns the label's text alignment
- *
- * Return value: The label's #PangoAlignment
- *
- * Since: 0.2
- **/
-PangoAlignment
-clutter_label_get_alignment (ClutterLabel *label)
-{
- g_return_val_if_fail (CLUTTER_IS_LABEL (label), FALSE);
-
- return label->priv->alignment;
-}
-
-/**
- * clutter_label_set_justify:
- * @label: a #ClutterLabel
- * @justify: whether the text should be justified
- *
- * Sets whether the text of the @label actor should be justified
- * on both margins. This setting is ignored if Clutter is compiled
- * against Pango < 1.18.
- *
- * Since: 0.6
- */
-void
-clutter_label_set_justify (ClutterLabel *label,
- gboolean justify)
-{
- ClutterLabelPrivate *priv;
-
- g_return_if_fail (CLUTTER_IS_LABEL (label));
-
- priv = label->priv;
-
- if (priv->justify != justify)
- {
- priv->justify = justify;
-
- clutter_label_dirty_cache (label);
-
- clutter_actor_queue_relayout (CLUTTER_ACTOR (label));
-
- g_object_notify (G_OBJECT (label), "justify");
- }
-}
-
-/**
- * clutter_label_get_justify:
- * @label: a #ClutterLabel
- *
- * Retrieves whether the label should justify the text on both margins.
- *
- * Return value: %TRUE if the text should be justified
- *
- * Since: 0.6
- */
-gboolean
-clutter_label_get_justify (ClutterLabel *label)
-{
- g_return_val_if_fail (CLUTTER_IS_LABEL (label), FALSE);
-
- return label->priv->justify;
-}
diff --git a/clutter/clutter-label.h b/clutter/clutter-label.h
deleted file mode 100644
index d6021c2f3..000000000
--- a/clutter/clutter-label.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Clutter.
- *
- * An OpenGL based 'interactive canvas' library.
- *
- * Authored By Matthew Allum
- *
- * 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, see .
- */
-
-#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
-#error "Only can be included directly."
-#endif
-
-#ifndef __CLUTTER_LABEL_H__
-#define __CLUTTER_LABEL_H__
-
-#include
-#include
-#include
-
-
-G_BEGIN_DECLS
-
-#define CLUTTER_TYPE_LABEL (clutter_label_get_type ())
-
-#define CLUTTER_LABEL(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
- CLUTTER_TYPE_LABEL, ClutterLabel))
-
-#define CLUTTER_LABEL_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), \
- CLUTTER_TYPE_LABEL, ClutterLabelClass))
-
-#define CLUTTER_IS_LABEL(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
- CLUTTER_TYPE_LABEL))
-
-#define CLUTTER_IS_LABEL_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), \
- CLUTTER_TYPE_LABEL))
-
-#define CLUTTER_LABEL_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), \
- CLUTTER_TYPE_LABEL, ClutterLabelClass))
-
-typedef struct _ClutterLabel ClutterLabel;
-typedef struct _ClutterLabelClass ClutterLabelClass;
-typedef struct _ClutterLabelPrivate ClutterLabelPrivate;
-
-struct _ClutterLabel
-{
- ClutterActor parent;
-
- /*< private >*/
- ClutterLabelPrivate *priv;
-};
-
-struct _ClutterLabelClass
-{
- /*< private >*/
- ClutterActorClass parent_class;
-
- void (*_clutter_label_1) (void);
- void (*_clutter_label_2) (void);
- void (*_clutter_label_3) (void);
- void (*_clutter_label_4) (void);
-};
-
-GType clutter_label_get_type (void) G_GNUC_CONST;
-
-ClutterActor * clutter_label_new (void);
-
-ClutterActor* clutter_label_new_full (const gchar *font_name,
- const gchar *text,
- const ClutterColor *color);
-
-ClutterActor * clutter_label_new_with_text (const gchar *font_name,
- const gchar *text);
-void clutter_label_set_text (ClutterLabel *label,
- const gchar *text);
-G_CONST_RETURN gchar *clutter_label_get_text (ClutterLabel *label);
-void clutter_label_set_font_name (ClutterLabel *label,
- const gchar *font_name);
-G_CONST_RETURN gchar *clutter_label_get_font_name (ClutterLabel *label);
-void clutter_label_set_color (ClutterLabel *label,
- const ClutterColor *color);
-void clutter_label_get_color (ClutterLabel *label,
- ClutterColor *color);
-void clutter_label_set_ellipsize (ClutterLabel *label,
- PangoEllipsizeMode mode);
-PangoEllipsizeMode clutter_label_get_ellipsize (ClutterLabel *label);
-void clutter_label_set_line_wrap (ClutterLabel *label,
- gboolean wrap);
-gboolean clutter_label_get_line_wrap (ClutterLabel *label);
-void clutter_label_set_line_wrap_mode (ClutterLabel *label,
- PangoWrapMode wrap_mode);
-PangoWrapMode clutter_label_get_line_wrap_mode (ClutterLabel *label);
-PangoLayout * clutter_label_get_layout (ClutterLabel *label);
-void clutter_label_set_attributes (ClutterLabel *label,
- PangoAttrList *attrs);
-PangoAttrList * clutter_label_get_attributes (ClutterLabel *label);
-void clutter_label_set_use_markup (ClutterLabel *label,
- gboolean setting);
-gboolean clutter_label_get_use_markup (ClutterLabel *label);
-void clutter_label_set_alignment (ClutterLabel *label,
- PangoAlignment alignment);
-PangoAlignment clutter_label_get_alignment (ClutterLabel *label);
-void clutter_label_set_justify (ClutterLabel *label,
- gboolean justify);
-gboolean clutter_label_get_justify (ClutterLabel *label);
-
-G_END_DECLS
-
-#endif /* __CLUTTER_LABEL_H__ */
diff --git a/clutter/clutter-main.c b/clutter/clutter-main.c
index 9edbce8c6..745fcbbd7 100644
--- a/clutter/clutter-main.c
+++ b/clutter/clutter-main.c
@@ -53,21 +53,23 @@
#include "pango/cogl-pango.h"
/* main context */
-static ClutterMainContext *ClutterCntx = NULL;
+static ClutterMainContext *ClutterCntx = NULL;
/* main lock and locking/unlocking functions */
-static GMutex *clutter_threads_mutex = NULL;
-static GCallback clutter_threads_lock = NULL;
-static GCallback clutter_threads_unlock = NULL;
+static GMutex *clutter_threads_mutex = NULL;
+static GCallback clutter_threads_lock = NULL;
+static GCallback clutter_threads_unlock = NULL;
-static gboolean clutter_is_initialized = FALSE;
-static gboolean clutter_show_fps = FALSE;
-static gboolean clutter_fatal_warnings = FALSE;
+static gboolean clutter_is_initialized = FALSE;
+static gboolean clutter_show_fps = FALSE;
+static gboolean clutter_fatal_warnings = FALSE;
-static guint clutter_default_fps = 60;
+static guint clutter_default_fps = 60;
-static guint clutter_main_loop_level = 0;
-static GSList *main_loops = NULL;
+static guint clutter_main_loop_level = 0;
+static GSList *main_loops = NULL;
+
+static PangoDirection clutter_text_direction = PANGO_DIRECTION_LTR;
guint clutter_debug_flags = 0; /* global clutter debug flag */
@@ -401,23 +403,100 @@ _clutter_do_pick (ClutterStage *stage,
return clutter_get_actor_by_gid (id);
}
+static PangoDirection
+clutter_get_text_direction (void)
+{
+ PangoDirection dir = PANGO_DIRECTION_LTR;
+ const gchar *direction;
+
+ direction = g_getenv ("CLUTTER_TEXT_DIRECTION");
+ if (direction && *direction != '\0')
+ {
+ if (strcmp (direction, "rtl") == 0)
+ dir = PANGO_DIRECTION_RTL;
+ else if (strcmp (direction, "ltr") == 0)
+ dir = PANGO_DIRECTION_LTR;
+ }
+ else
+ {
+ /* Translate to default:RTL if you want your widgets
+ * to be RTL, otherwise translate to default:LTR.
+ *
+ * Do *not* translate it to "predefinito:LTR": if it
+ * it isn't default:LTR or default:RTL it will not work
+ */
+ char *e = _("default:LTR");
+
+ if (strcmp (e, "default:RTL") == 0)
+ dir = PANGO_DIRECTION_RTL;
+ else if (strcmp (e, "default:LTR") == 0)
+ dir = PANGO_DIRECTION_LTR;
+ else
+ g_warning ("Whoever translated default:LTR did so wrongly.");
+ }
+
+ return dir;
+}
+
+static void
+update_pango_context (ClutterBackend *backend,
+ PangoContext *context)
+{
+ PangoFontDescription *font_desc;
+ cairo_font_options_t *font_options;
+ const gchar *font_name;
+ gdouble resolution;
+
+ /* update the text direction */
+ pango_context_set_base_dir (context, clutter_text_direction);
+
+ /* get the configuration for the PangoContext from the backend */
+ font_name = clutter_backend_get_font_name (backend);
+ font_options = clutter_backend_get_font_options (backend);
+ resolution = clutter_backend_get_resolution (backend);
+
+ font_desc = pango_font_description_from_string (font_name);
+
+ if (resolution < 0)
+ resolution = 96.0; /* fall back */
+
+ pango_context_set_font_description (context, font_desc);
+ pango_cairo_context_set_font_options (context, font_options);
+ pango_cairo_context_set_resolution (context, resolution);
+
+ pango_font_description_free (font_desc);
+}
+
+PangoContext *
+_clutter_context_get_pango_context (ClutterMainContext *self)
+{
+ if (G_UNLIKELY (self->pango_context == NULL))
+ {
+ PangoContext *context;
+
+ context = cogl_pango_font_map_create_context (self->font_map);
+ self->pango_context = context;
+
+ g_signal_connect (self->backend, "resolution-changed",
+ G_CALLBACK (update_pango_context),
+ self->pango_context);
+ g_signal_connect (self->backend, "font-changed",
+ G_CALLBACK (update_pango_context),
+ self->pango_context);
+ }
+
+ update_pango_context (self->backend, self->pango_context);
+
+ return self->pango_context;
+}
+
PangoContext *
_clutter_context_create_pango_context (ClutterMainContext *self)
{
PangoContext *context;
- gdouble resolution;
- cairo_font_options_t *font_options;
-
- resolution = clutter_backend_get_resolution (self->backend);
- if (resolution < 0)
- resolution = 96.0; /* fall back */
context = cogl_pango_font_map_create_context (self->font_map);
-
- pango_cairo_context_set_resolution (context, resolution);
-
- font_options = clutter_backend_get_font_options (self->backend);
- pango_cairo_context_set_font_options (context, font_options);
+ update_pango_context (self->backend, context);
return context;
}
@@ -1004,6 +1083,17 @@ clutter_get_timestamp (void)
#endif
}
+static gboolean
+clutter_arg_direction_cb (const char *key,
+ const char *value,
+ gpointer user_data)
+{
+ clutter_text_direction =
+ (strcmp (value, "rtl") == 0) ? PANGO_DIRECTION_RTL
+ : PANGO_DIRECTION_LTR;
+
+ return TRUE;
+}
#ifdef CLUTTER_ENABLE_DEBUG
static gboolean
@@ -1077,6 +1167,8 @@ clutter_init_real (GError **error)
cogl_pango_font_map_set_resolution (ctx->font_map, resolution);
cogl_pango_font_map_set_use_mipmapping (ctx->font_map, TRUE);
+ clutter_text_direction = clutter_get_text_direction ();
+
/* Stage will give us a GL Context etc */
stage = clutter_stage_get_default ();
if (!stage)
@@ -1142,16 +1234,19 @@ clutter_init_real (GError **error)
static GOptionEntry clutter_args[] = {
{ "clutter-show-fps", 0, 0, G_OPTION_ARG_NONE, &clutter_show_fps,
- "Show frames per second", NULL },
+ N_("Show frames per second"), NULL },
{ "clutter-default-fps", 0, 0, G_OPTION_ARG_INT, &clutter_default_fps,
- "Default frame rate", "FPS" },
+ N_("Default frame rate"), "FPS" },
{ "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &clutter_fatal_warnings,
- "Make all warnings fatal", NULL },
+ N_("Make all warnings fatal"), NULL },
+ { "clutter-text-direction", 0, 0, G_OPTION_ARG_CALLBACK,
+ clutter_arg_direction_cb,
+ N_("Direction for the text"), "DIRECTION" },
#ifdef CLUTTER_ENABLE_DEBUG
{ "clutter-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_debug_cb,
- "Clutter debugging flags to set", "FLAGS" },
+ N_("Clutter debugging flags to set"), "FLAGS" },
{ "clutter-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, clutter_arg_no_debug_cb,
- "Clutter debugging flags to unset", "FLAGS" },
+ N_("Clutter debugging flags to unset"), "FLAGS" },
#endif /* CLUTTER_ENABLE_DEBUG */
{ NULL, },
};
@@ -1294,13 +1389,14 @@ clutter_get_option_group (void)
context = clutter_context_get_default ();
group = g_option_group_new ("clutter",
- "Clutter Options",
- "Show Clutter Options",
+ _("Clutter Options"),
+ _("Show Clutter Options"),
NULL,
NULL);
g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
g_option_group_add_entries (group, clutter_args);
+ g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
/* add backend-specific options */
_clutter_backend_add_options (context->backend, group);
@@ -2118,6 +2214,9 @@ clutter_base_init (void)
initialised = TRUE;
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
/* initialise GLib type system */
g_type_init ();
diff --git a/clutter/clutter-private.h b/clutter/clutter-private.h
index 81e030adf..c65bfb066 100644
--- a/clutter/clutter-private.h
+++ b/clutter/clutter-private.h
@@ -38,6 +38,8 @@
#include
+#include "pango/cogl-pango.h"
+
#include "clutter-backend.h"
#include "clutter-event.h"
#include "clutter-feature.h"
@@ -45,7 +47,6 @@
#include "clutter-stage-manager.h"
#include "clutter-stage-window.h"
#include "clutter-stage.h"
-#include "pango/cogl-pango.h"
G_BEGIN_DECLS
@@ -125,15 +126,17 @@ struct _ClutterMainContext
gint fb_r_mask, fb_g_mask, fb_b_mask;
gint fb_r_mask_used, fb_g_mask_used, fb_b_mask_used;
- CoglPangoFontMap *font_map; /* Global font map */
+ PangoContext *pango_context; /* Global Pango context */
+ CoglPangoFontMap *font_map; /* Global font map */
- GSList *input_devices; /* For extra input devices, i.e
- MultiTouch */
+ GSList *input_devices; /* For extra input devices, i.e
+ MultiTouch */
};
#define CLUTTER_CONTEXT() (clutter_context_get_default ())
ClutterMainContext *clutter_context_get_default (void);
PangoContext *_clutter_context_create_pango_context (ClutterMainContext *self);
+PangoContext *_clutter_context_get_pango_context (ClutterMainContext *self);
#define CLUTTER_PRIVATE_FLAGS(a) (((ClutterActor *) (a))->private_flags)
#define CLUTTER_SET_PRIVATE_FLAGS(a,f) (CLUTTER_PRIVATE_FLAGS (a) |= (f))
diff --git a/clutter/clutter-stage.c b/clutter/clutter-stage.c
index 7e5abe76f..f6d42288f 100644
--- a/clutter/clutter-stage.c
+++ b/clutter/clutter-stage.c
@@ -1201,7 +1201,7 @@ clutter_stage_read_pixels (ClutterStage *stage,
/* The y co-ordinate should be given in OpenGL's coordinate system
so 0 is the bottom row */
- y = stage_height - 1 - y - height;
+ y = stage_height - y - height;
glFinish ();
diff --git a/clutter/clutter-text.c b/clutter/clutter-text.c
new file mode 100644
index 000000000..4b7ae3f13
--- /dev/null
+++ b/clutter/clutter-text.c
@@ -0,0 +1,3757 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2008 Intel Corporation.
+ *
+ * Authored By: Øyvind Kolås
+ * Emmanuele Bassi
+ *
+ * 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, see .
+ */
+
+/**
+ * SECTION:clutter-text
+ * @short_description: An actor for displaying and editing text
+ *
+ * #ClutterText is an actor that displays custom text using Pango
+ * as the text rendering engine.
+ *
+ * #ClutterText also allows inline editing of the text if the
+ * actor is set editable using clutter_text_set_editable().
+ *
+ * Selection using keyboard or pointers can be enabled using
+ * clutter_text_set_selectable().
+ *
+ * #ClutterText is available since Clutter 1.0
+ */
+
+/* TODO: undo/redo hooks? */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+
+#include "clutter-text.h"
+
+#include "clutter-binding-pool.h"
+#include "clutter-debug.h"
+#include "clutter-enum-types.h"
+#include "clutter-keysyms.h"
+#include "clutter-main.h"
+#include "clutter-private.h" /* includes pango/cogl-pango.h */
+#include "clutter-units.h"
+
+/* cursor width in pixels */
+#define DEFAULT_CURSOR_SIZE 2
+
+/* We need at least three cached layouts to run the allocation without
+ * regenerating a new layout. First the layout will be generated at
+ * full width to get the preferred width, then it will be generated at
+ * the preferred width to get the preferred height and then it might
+ * be regenerated at a different width to get the height for the
+ * actual allocated width
+ */
+#define N_CACHED_LAYOUTS 3
+
+#define CLUTTER_TEXT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_TEXT, ClutterTextPrivate))
+
+typedef struct _LayoutCache LayoutCache;
+
+static const ClutterColor default_cursor_color = { 0, 0, 0, 255 };
+static const ClutterColor default_text_color = { 0, 0, 0, 255 };
+
+G_DEFINE_TYPE (ClutterText, clutter_text, CLUTTER_TYPE_ACTOR);
+
+struct _LayoutCache
+{
+ /* Cached layout. Pango internally caches the computed extents
+ * when they are requested so there is no need to cache that as
+ * well
+ */
+ PangoLayout *layout;
+
+ /* The width that used to generate this layout */
+ ClutterUnit width;
+
+ /* A number representing the age of this cache (so that when a
+ * new layout is needed the last used cache is replaced)
+ */
+ guint age;
+};
+
+struct _ClutterTextPrivate
+{
+ PangoFontDescription *font_desc;
+
+ gchar *text;
+ gchar *font_name;
+
+ ClutterColor text_color;
+
+ LayoutCache cached_layouts[N_CACHED_LAYOUTS];
+ guint cache_age;
+
+ PangoAttrList *attrs;
+ PangoAttrList *effective_attrs;
+
+ guint alignment : 2;
+ guint wrap : 1;
+ guint use_underline : 1;
+ guint use_markup : 1;
+ guint ellipsize : 3;
+ guint single_line_mode : 1;
+ guint wrap_mode : 3;
+ guint justify : 1;
+ guint editable : 1;
+ guint cursor_visible : 1;
+ guint activatable : 1;
+ guint selectable : 1;
+ guint in_select_drag : 1;
+ guint cursor_color_set : 1;
+
+ /* current cursor position */
+ gint position;
+
+ /* current 'other end of selection' position */
+ gint selection_bound;
+
+ /* the x position in the PangoLayout, used to
+ * avoid drifting when repeatedly moving up|down
+ */
+ gint x_pos;
+
+ /* the x position of the PangoLayout when in
+ * single line mode, to scroll the contents of the
+ * text actor
+ */
+ gint text_x;
+
+ /* the length of the text, in bytes */
+ gint n_bytes;
+
+ /* the length of the text, in characters */
+ gint n_chars;
+
+ /* Where to draw the cursor */
+ ClutterGeometry cursor_pos;
+ ClutterColor cursor_color;
+ guint cursor_size;
+
+ gint max_length;
+
+ gunichar password_char;
+};
+
+enum
+{
+ PROP_0,
+
+ PROP_FONT_NAME,
+ PROP_TEXT,
+ PROP_COLOR,
+ PROP_USE_MARKUP,
+ PROP_ATTRIBUTES,
+ PROP_ALIGNMENT,
+ PROP_LINE_WRAP,
+ PROP_LINE_WRAP_MODE,
+ PROP_JUSTIFY,
+ PROP_ELLIPSIZE,
+ PROP_POSITION,
+ PROP_SELECTION_BOUND,
+ PROP_CURSOR_VISIBLE,
+ PROP_CURSOR_COLOR,
+ PROP_CURSOR_COLOR_SET,
+ PROP_CURSOR_SIZE,
+ PROP_EDITABLE,
+ PROP_SELECTABLE,
+ PROP_ACTIVATABLE,
+ PROP_PASSWORD_CHAR,
+ PROP_MAX_LENGTH,
+ PROP_SINGLE_LINE_MODE
+};
+
+enum
+{
+ TEXT_CHANGED,
+ CURSOR_EVENT,
+ ACTIVATE,
+
+ LAST_SIGNAL
+};
+
+static guint text_signals[LAST_SIGNAL] = { 0, };
+
+#define offset_real(t,p) ((p) == -1 ? g_utf8_strlen ((t), -1) : (p))
+
+static gint
+offset_to_bytes (const gchar *text,
+ gint pos)
+{
+ gchar *c = NULL;
+ gint i, j, len;
+
+ if (pos < 0)
+ return strlen (text);
+
+ c = g_utf8_next_char (text);
+ j = 1;
+ len = strlen (text);
+
+ for (i = 0; i < len; i++)
+ {
+ if (&text[i] == c)
+ {
+ if (j == pos)
+ break;
+ else
+ {
+ c = g_utf8_next_char (c);
+ j++;
+ }
+ }
+ }
+
+ return i;
+}
+
+#define bytes_to_offset(t,p) (g_utf8_pointer_to_offset ((t), (t) + (p)))
+
+
+static inline void
+clutter_text_clear_selection (ClutterText *self)
+{
+ ClutterTextPrivate *priv = self->priv;
+
+ priv->selection_bound = priv->position;
+}
+
+static PangoLayout *
+clutter_text_create_layout_no_cache (ClutterText *text,
+ ClutterUnit allocation_width)
+{
+ ClutterTextPrivate *priv = text->priv;
+ PangoContext *context;
+ PangoLayout *layout;
+
+ context = clutter_actor_get_pango_context (CLUTTER_ACTOR (text));
+ layout = pango_layout_new (context);
+
+ pango_layout_set_font_description (layout, priv->font_desc);
+
+ if (priv->effective_attrs)
+ pango_layout_set_attributes (layout, priv->effective_attrs);
+
+ pango_layout_set_alignment (layout, priv->alignment);
+ pango_layout_set_single_paragraph_mode (layout, priv->single_line_mode);
+ pango_layout_set_justify (layout, priv->justify);
+
+ if (priv->text)
+ {
+ if (priv->use_markup && !priv->editable)
+ pango_layout_set_markup (layout, priv->text, -1);
+ else
+ {
+ if (G_LIKELY (priv->password_char == 0))
+ pango_layout_set_text (layout, priv->text, priv->n_bytes);
+ else
+ {
+ GString *str = g_string_sized_new (priv->n_bytes);
+ gunichar invisible_char;
+ gchar buf[7];
+ gint char_len, i;
+
+ invisible_char = priv->password_char;
+
+ /* we need to convert the string built of invisible
+ * characters into UTF-8 for it to be fed to the Pango
+ * layout
+ */
+ memset (buf, 0, sizeof (buf));
+ char_len = g_unichar_to_utf8 (invisible_char, buf);
+
+ for (i = 0; i < priv->n_chars; i++)
+ g_string_append_len (str, buf, char_len);
+
+ pango_layout_set_text (layout, str->str, str->len);
+
+ g_string_free (str, TRUE);
+ }
+ }
+ }
+
+ if (allocation_width > 0 &&
+ (priv->ellipsize != PANGO_ELLIPSIZE_NONE || priv->wrap))
+ {
+ int layout_width, layout_height;
+
+ pango_layout_get_size (layout, &layout_width, &layout_height);
+
+ /* No need to set ellipsize or wrap if we already have enough
+ * space, since we don't want to make the layout wider than it
+ * would be otherwise.
+ */
+
+ if (CLUTTER_UNITS_FROM_PANGO_UNIT (layout_width) > allocation_width)
+ {
+ if (priv->ellipsize != PANGO_ELLIPSIZE_NONE)
+ {
+ gint width;
+
+ width = allocation_width > 0
+ ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width)
+ : -1;
+
+ pango_layout_set_ellipsize (layout, priv->ellipsize);
+ pango_layout_set_width (layout, width);
+ }
+ else if (priv->wrap)
+ {
+ gint width;
+
+ width = allocation_width > 0
+ ? CLUTTER_UNITS_TO_PANGO_UNIT (allocation_width)
+ : -1;
+
+ pango_layout_set_wrap (layout, priv->wrap_mode);
+ pango_layout_set_width (layout, width);
+ }
+ }
+ }
+
+ return layout;
+}
+
+static void
+clutter_text_dirty_cache (ClutterText *text)
+{
+ ClutterTextPrivate *priv = text->priv;
+ int i;
+
+ /* Delete the cached layouts so they will be recreated the next time
+ they are needed */
+ for (i = 0; i < N_CACHED_LAYOUTS; i++)
+ if (priv->cached_layouts[i].layout)
+ {
+ g_object_unref (priv->cached_layouts[i].layout);
+ priv->cached_layouts[i].layout = NULL;
+ }
+}
+
+/*
+ * clutter_text_create_layout:
+ * @text: a #ClutterText
+ * @allocation_width: the allocation width
+ *
+ * Like clutter_text_create_layout_no_cache(), but will also ensure
+ * the glyphs cache. If a previously cached layout generated using the
+ * same width is available then that will be used instead of
+ * generating a new one.
+ */
+static PangoLayout *
+clutter_text_create_layout (ClutterText *text,
+ ClutterUnit allocation_width)
+{
+ ClutterTextPrivate *priv = text->priv;
+ LayoutCache *oldest_cache = priv->cached_layouts;
+ gboolean found_free_cache = FALSE;
+ int i;
+
+ /* Search for a cached layout with the same width and keep track of
+ the oldest one */
+ for (i = 0; i < N_CACHED_LAYOUTS; i++)
+ {
+ if (priv->cached_layouts[i].layout == NULL)
+ {
+ /* Always prefer free cache spaces */
+ found_free_cache = TRUE;
+ oldest_cache = priv->cached_layouts + i;
+ }
+ /* If this cached layout is using the same width then we can
+ just return that directly */
+ else if (priv->cached_layouts[i].width == allocation_width)
+ {
+ CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache hit for width %i",
+ text,
+ CLUTTER_UNITS_TO_DEVICE (allocation_width));
+
+ return priv->cached_layouts[i].layout;
+ }
+ else if (!found_free_cache &&
+ (priv->cached_layouts[i].age < oldest_cache->age))
+ {
+ oldest_cache = priv->cached_layouts + i;
+ }
+ }
+
+ CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache miss for width %i",
+ text,
+ CLUTTER_UNITS_TO_DEVICE (allocation_width));
+
+ /* If we make it here then we didn't have a cached version so we
+ need to recreate the layout */
+ if (oldest_cache->layout)
+ g_object_unref (oldest_cache->layout);
+
+ oldest_cache->layout =
+ clutter_text_create_layout_no_cache (text, allocation_width);
+
+ cogl_pango_ensure_glyph_cache_for_layout (oldest_cache->layout);
+
+ /* Mark the 'time' this cache was created and advance the time */
+ oldest_cache->age = priv->cache_age++;
+ oldest_cache->width = allocation_width;
+
+ return oldest_cache->layout;
+}
+
+static gint
+clutter_text_coords_to_position (ClutterText *text,
+ gint x,
+ gint y)
+{
+ gint index_;
+ gint px, py;
+ gint trailing;
+
+ px = x * PANGO_SCALE;
+ py = y * PANGO_SCALE;
+
+ pango_layout_xy_to_index (clutter_text_get_layout (text),
+ px, py,
+ &index_, &trailing);
+
+ return index_ + trailing;
+}
+
+/*
+ * clutter_text_position_to_coords:
+ * @self: a #ClutterText
+ * @position: position in characters
+ * @x: return location for the X coordinate, or %NULL
+ * @y: return location for the Y coordinate, or %NULL
+ * @line_height: return location for the line height, or %NULL
+ *
+ * Retrieves the coordinates of the given @position.
+ *
+ * Return value: %TRUE if the conversion was successful
+ */
+static gboolean
+clutter_text_position_to_coords (ClutterText *self,
+ gint position,
+ ClutterUnit *x,
+ ClutterUnit *y,
+ ClutterUnit *line_height)
+{
+ ClutterTextPrivate *priv = self->priv;
+ PangoRectangle rect;
+ gint password_char_bytes = 1;
+ gint index_;
+
+ if (priv->password_char != 0)
+ password_char_bytes = g_unichar_to_utf8 (priv->password_char, NULL);
+
+ if (position == -1)
+ {
+ if (priv->password_char == 0)
+ index_ = priv->n_bytes;
+ else
+ index_ = priv->n_chars * password_char_bytes;
+ }
+ else if (position == 0)
+ {
+ index_ = 0;
+ }
+ else
+ {
+ if (priv->password_char == 0)
+ index_ = offset_to_bytes (priv->text, position);
+ else
+ index_ = priv->position * password_char_bytes;
+ }
+
+ pango_layout_get_cursor_pos (clutter_text_get_layout (self), index_,
+ &rect, NULL);
+
+ if (x)
+ *x = CLUTTER_UNITS_FROM_PANGO_UNIT (rect.x);
+
+ if (y)
+ *y = CLUTTER_UNITS_FROM_PANGO_UNIT (rect.y);
+
+ if (line_height)
+ *line_height = CLUTTER_UNITS_FROM_PANGO_UNIT (rect.height);
+
+ /* FIXME: should return false if coords were outside text */
+ return TRUE;
+}
+
+static inline void
+clutter_text_ensure_cursor_position (ClutterText *self)
+{
+ ClutterTextPrivate *priv = self->priv;
+ ClutterUnit x, y, cursor_height;
+
+ x = y = cursor_height = 0;
+ clutter_text_position_to_coords (self, priv->position,
+ &x, &y,
+ &cursor_height);
+
+ priv->cursor_pos.x = CLUTTER_UNITS_TO_DEVICE (x);
+ priv->cursor_pos.y = CLUTTER_UNITS_TO_DEVICE (y);
+ priv->cursor_pos.width = priv->cursor_size;
+ priv->cursor_pos.height = CLUTTER_UNITS_TO_DEVICE (cursor_height) - 2;
+
+ g_signal_emit (self, text_signals[CURSOR_EVENT], 0, &priv->cursor_pos);
+}
+
+static gboolean
+clutter_text_truncate_selection (ClutterText *self)
+{
+ ClutterTextPrivate *priv = self->priv;
+ gint start_index;
+ gint end_index;
+
+ if (!priv->text)
+ return TRUE;
+
+ start_index = offset_real (priv->text, priv->position);
+ end_index = offset_real (priv->text, priv->selection_bound);
+
+ if (end_index == start_index)
+ return FALSE;
+
+ if (end_index < start_index)
+ {
+ gint temp = start_index;
+ start_index = end_index;
+ end_index = temp;
+ }
+
+ clutter_text_delete_text (self, start_index, end_index);
+
+ priv->position = start_index;
+ priv->selection_bound = start_index;
+
+ return TRUE;
+}
+
+static void
+clutter_text_set_property (GObject *gobject,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterText *self = CLUTTER_TEXT (gobject);
+
+ switch (prop_id)
+ {
+ case PROP_TEXT:
+ clutter_text_set_text (self, g_value_get_string (value));
+ break;
+
+ case PROP_COLOR:
+ clutter_text_set_color (self, clutter_value_get_color (value));
+ break;
+
+ case PROP_FONT_NAME:
+ clutter_text_set_font_name (self, g_value_get_string (value));
+ break;
+
+ case PROP_USE_MARKUP:
+ clutter_text_set_use_markup (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_ATTRIBUTES:
+ clutter_text_set_attributes (self, g_value_get_boxed (value));
+ break;
+
+ case PROP_ALIGNMENT:
+ clutter_text_set_alignment (self, g_value_get_enum (value));
+ break;
+
+ case PROP_LINE_WRAP:
+ clutter_text_set_line_wrap (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_LINE_WRAP_MODE:
+ clutter_text_set_line_wrap_mode (self, g_value_get_enum (value));
+ break;
+
+ case PROP_JUSTIFY:
+ clutter_text_set_justify (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_ELLIPSIZE:
+ clutter_text_set_ellipsize (self, g_value_get_enum (value));
+ break;
+
+ case PROP_POSITION:
+ clutter_text_set_cursor_position (self, g_value_get_int (value));
+ break;
+
+ case PROP_SELECTION_BOUND:
+ clutter_text_set_selection_bound (self, g_value_get_int (value));
+ break;
+
+ case PROP_CURSOR_VISIBLE:
+ clutter_text_set_cursor_visible (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_CURSOR_COLOR:
+ clutter_text_set_cursor_color (self, g_value_get_boxed (value));
+ break;
+
+ case PROP_CURSOR_SIZE:
+ clutter_text_set_cursor_size (self, g_value_get_int (value));
+ break;
+
+ case PROP_EDITABLE:
+ clutter_text_set_editable (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_ACTIVATABLE:
+ clutter_text_set_activatable (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_SELECTABLE:
+ clutter_text_set_selectable (self, g_value_get_boolean (value));
+ break;
+
+ case PROP_PASSWORD_CHAR:
+ clutter_text_set_password_char (self, g_value_get_uint (value));
+ break;
+
+ case PROP_MAX_LENGTH:
+ clutter_text_set_max_length (self, g_value_get_int (value));
+ break;
+
+ case PROP_SINGLE_LINE_MODE:
+ clutter_text_set_single_line_mode (self, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ }
+}
+
+static void
+clutter_text_get_property (GObject *gobject,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ClutterTextPrivate *priv = CLUTTER_TEXT (gobject)->priv;
+
+ switch (prop_id)
+ {
+ case PROP_TEXT:
+ g_value_set_string (value, priv->text);
+ break;
+
+ case PROP_FONT_NAME:
+ g_value_set_string (value, priv->font_name);
+ break;
+
+ case PROP_COLOR:
+ clutter_value_set_color (value, &priv->text_color);
+ break;
+
+ case PROP_CURSOR_VISIBLE:
+ g_value_set_boolean (value, priv->cursor_visible);
+ break;
+
+ case PROP_CURSOR_COLOR:
+ clutter_value_set_color (value, &priv->cursor_color);
+ break;
+
+ case PROP_CURSOR_COLOR_SET:
+ g_value_set_boolean (value, priv->cursor_color_set);
+ break;
+
+ case PROP_CURSOR_SIZE:
+ g_value_set_int (value, priv->cursor_size);
+ break;
+
+ case PROP_POSITION:
+ g_value_set_int (value, CLUTTER_FIXED_TO_FLOAT (priv->position));
+ break;
+
+ case PROP_SELECTION_BOUND:
+ g_value_set_int (value, CLUTTER_FIXED_TO_FLOAT (priv->selection_bound));
+ break;
+
+ case PROP_EDITABLE:
+ g_value_set_boolean (value, priv->editable);
+ break;
+
+ case PROP_SELECTABLE:
+ g_value_set_boolean (value, priv->selectable);
+ break;
+
+ case PROP_ACTIVATABLE:
+ g_value_set_boolean (value, priv->activatable);
+ break;
+
+ case PROP_PASSWORD_CHAR:
+ g_value_set_uint (value, priv->password_char);
+ break;
+
+ case PROP_MAX_LENGTH:
+ g_value_set_int (value, priv->max_length);
+ break;
+
+ case PROP_SINGLE_LINE_MODE:
+ g_value_set_boolean (value, priv->single_line_mode);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+ }
+}
+
+static void
+clutter_text_dispose (GObject *gobject)
+{
+ ClutterText *self = CLUTTER_TEXT (gobject);
+
+ /* get rid of the entire cache */
+ clutter_text_dirty_cache (self);
+
+ G_OBJECT_CLASS (clutter_text_parent_class)->dispose (gobject);
+}
+
+static void
+clutter_text_finalize (GObject *gobject)
+{
+ ClutterText *self = CLUTTER_TEXT (gobject);
+ ClutterTextPrivate *priv = self->priv;
+
+ if (priv->font_desc)
+ pango_font_description_free (priv->font_desc);
+
+ g_free (priv->text);
+ g_free (priv->font_name);
+
+ G_OBJECT_CLASS (clutter_text_parent_class)->finalize (gobject);
+}
+
+static void
+cursor_paint (ClutterText *self)
+{
+ ClutterTextPrivate *priv = self->priv;
+ ClutterActor *actor = CLUTTER_ACTOR (self);
+ guint8 real_opacity;
+
+ if (priv->editable && priv->cursor_visible)
+ {
+ if (priv->cursor_color_set)
+ {
+ real_opacity = clutter_actor_get_paint_opacity (actor)
+ * priv->cursor_color.alpha
+ / 255;
+
+ cogl_set_source_color4ub (priv->cursor_color.red,
+ priv->cursor_color.green,
+ priv->cursor_color.blue,
+ real_opacity);
+ }
+ else
+ {
+ real_opacity = clutter_actor_get_paint_opacity (actor)
+ * priv->text_color.alpha
+ / 255;
+
+ cogl_set_source_color4ub (priv->text_color.red,
+ priv->text_color.green,
+ priv->text_color.blue,
+ real_opacity);
+ }
+
+ if (priv->position == 0)
+ priv->cursor_pos.x -= priv->cursor_size;
+
+ if (priv->position == priv->selection_bound)
+ {
+ cogl_rectangle (priv->cursor_pos.x,
+ priv->cursor_pos.y,
+ priv->cursor_pos.width,
+ priv->cursor_pos.height);
+ }
+ else
+ {
+ PangoLayout *layout = clutter_text_get_layout (self);
+ const gchar *utf8 = priv->text;
+ gint lines;
+ gint start_index;
+ gint end_index;
+ gint line_no;
+
+ if (priv->position == 0)
+ start_index = 0;
+ else
+ start_index = offset_to_bytes (utf8, priv->position);
+
+ if (priv->selection_bound == 0)
+ end_index = 0;
+ else
+ end_index = offset_to_bytes (utf8, priv->selection_bound);
+
+ if (start_index > end_index)
+ {
+ gint temp = start_index;
+ start_index = end_index;
+ end_index = temp;
+ }
+
+ lines = pango_layout_get_line_count (layout);
+
+ for (line_no = 0; line_no < lines; line_no++)
+ {
+ PangoLayoutLine *line;
+ gint n_ranges;
+ gint *ranges;
+ gint i;
+ gint index_;
+ gint maxindex;
+ ClutterUnit y, height;
+
+ line = pango_layout_get_line_readonly (layout, line_no);
+ pango_layout_line_x_to_index (line, G_MAXINT, &maxindex, NULL);
+ if (maxindex < start_index)
+ continue;
+
+ pango_layout_line_get_x_ranges (line, start_index, end_index,
+ &ranges,
+ &n_ranges);
+ pango_layout_line_x_to_index (line, 0, &index_, NULL);
+
+ clutter_text_position_to_coords (self,
+ bytes_to_offset (utf8, index_),
+ NULL, &y, &height);
+
+ for (i = 0; i < n_ranges; i++)
+ {
+ gint range_x;
+ gint range_width;
+
+ range_x = ranges[i * 2]
+ / PANGO_SCALE;
+ range_width = (ranges[i * 2 + 1] - ranges[i * 2])
+ / PANGO_SCALE;
+
+ cogl_rectangle (range_x,
+ CLUTTER_UNITS_TO_DEVICE (y),
+ range_width,
+ CLUTTER_UNITS_TO_DEVICE (height));
+ }
+
+ g_free (ranges);
+ }
+ }
+ }
+}
+
+static gboolean
+clutter_text_button_press (ClutterActor *actor,
+ ClutterButtonEvent *event)
+{
+ ClutterText *self = CLUTTER_TEXT (actor);
+ ClutterTextPrivate *priv = self->priv;
+ ClutterUnit x, y;
+ gint index_;
+
+ x = CLUTTER_UNITS_FROM_INT (event->x);
+ y = CLUTTER_UNITS_FROM_INT (event->y);
+
+ clutter_actor_transform_stage_point (actor, x, y, &x, &y);
+
+ index_ = clutter_text_coords_to_position (self,
+ CLUTTER_UNITS_TO_INT (x),
+ CLUTTER_UNITS_TO_INT (y));
+
+ clutter_text_set_cursor_position (self, bytes_to_offset (priv->text, index_));
+ clutter_text_set_selection_bound (self, bytes_to_offset (priv->text, index_));
+
+ /* grab the pointer */
+ priv->in_select_drag = TRUE;
+ clutter_grab_pointer (actor);
+
+ /* we'll steal keyfocus if we do not have it */
+ clutter_actor_grab_key_focus (actor);
+
+ return TRUE;
+}
+
+static gboolean
+clutter_text_motion (ClutterActor *actor,
+ ClutterMotionEvent *mev)
+{
+ ClutterText *ttext = CLUTTER_TEXT (actor);
+ ClutterTextPrivate *priv = ttext->priv;
+ ClutterUnit x, y;
+ gint index_;
+ const gchar *text;
+
+ if (!priv->in_select_drag)
+ return FALSE;
+
+ text = clutter_text_get_text (ttext);
+
+ x = CLUTTER_UNITS_FROM_INT (mev->x);
+ y = CLUTTER_UNITS_FROM_INT (mev->y);
+
+ clutter_actor_transform_stage_point (actor, x, y, &x, &y);
+
+ index_ = clutter_text_coords_to_position (ttext,
+ CLUTTER_UNITS_TO_INT (x),
+ CLUTTER_UNITS_TO_INT (y));
+
+ if (priv->selectable)
+ clutter_text_set_cursor_position (ttext, bytes_to_offset (text, index_));
+ else
+ {
+ clutter_text_set_cursor_position (ttext, bytes_to_offset (text, index_));
+ clutter_text_set_selection_bound (ttext, bytes_to_offset (text, index_));
+ }
+
+ return TRUE;
+}
+
+static gboolean
+clutter_text_button_release (ClutterActor *actor,
+ ClutterButtonEvent *bev)
+{
+ ClutterText *ttext = CLUTTER_TEXT (actor);
+ ClutterTextPrivate *priv = ttext->priv;
+
+ if (priv->in_select_drag)
+ {
+ clutter_ungrab_pointer ();
+ priv->in_select_drag = FALSE;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+clutter_text_key_press (ClutterActor *actor,
+ ClutterKeyEvent *event)
+{
+ ClutterText *self = CLUTTER_TEXT (actor);
+ ClutterTextPrivate *priv = self->priv;
+ ClutterBindingPool *pool;
+ gboolean res;
+ gint keyval;
+
+ if (!priv->editable)
+ return FALSE;
+
+ keyval = clutter_key_event_symbol (event);
+
+ pool = clutter_binding_pool_find (G_OBJECT_TYPE_NAME (actor));
+ g_assert (pool != NULL);
+
+ /* we allow passing synthetic events that only contain
+ * the Unicode value and not the key symbol
+ */
+ if (keyval == 0 && (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC))
+ res = FALSE;
+ else
+ res = clutter_binding_pool_activate (pool, keyval,
+ event->modifier_state,
+ G_OBJECT (actor));
+
+ /* if the key binding has handled the event we bail out
+ * as fast as we can; otherwise, we try to insert the
+ * Unicode character inside the key event into the text
+ * actor
+ */
+ if (res)
+ return TRUE;
+ else
+ {
+ gunichar key_unichar = clutter_key_event_unicode (event);
+
+ /* return is reported as CR, but we want LF */
+ if (key_unichar == '\r')
+ key_unichar = '\n';
+
+ if (g_unichar_validate (key_unichar))
+ {
+ /* truncate the eventual selection so that the
+ * Unicode character can replace it
+ */
+ clutter_text_truncate_selection (self);
+ clutter_text_insert_unichar (self, key_unichar);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+#define TEXT_PADDING 2
+
+static void
+clutter_text_paint (ClutterActor *self)
+{
+ ClutterText *text = CLUTTER_TEXT (self);
+ ClutterTextPrivate *priv = text->priv;
+ PangoLayout *layout;
+ ClutterActorBox alloc = { 0, };
+ CoglColor color = { 0, };
+ guint8 real_opacity;
+ gint text_x = priv->text_x;
+ gboolean clip_set = FALSE;
+
+ if (G_UNLIKELY (priv->font_desc == NULL || priv->text == NULL))
+ {
+ CLUTTER_NOTE (ACTOR, "desc: %p, text %p",
+ priv->font_desc ? priv->font_desc : 0x0,
+ priv->text ? priv->text : 0x0);
+ return;
+ }
+
+ clutter_actor_get_allocation_box (self, &alloc);
+ layout = clutter_text_create_layout (text, alloc.x2 - alloc.x1);
+
+ if (priv->editable && priv->cursor_visible)
+ clutter_text_ensure_cursor_position (text);
+
+ if (priv->editable && priv->single_line_mode)
+ {
+ PangoRectangle logical_rect = { 0, };
+ gint actor_width, text_width;
+
+ pango_layout_get_extents (layout, NULL, &logical_rect);
+
+ cogl_clip_set (0, 0,
+ CLUTTER_UNITS_TO_FIXED (alloc.x2 - alloc.x1),
+ CLUTTER_UNITS_TO_FIXED (alloc.y2 - alloc.y1));
+ clip_set = TRUE;
+
+ actor_width = (CLUTTER_UNITS_TO_DEVICE (alloc.x2 - alloc.x1))
+ - 2 * TEXT_PADDING;
+ text_width = logical_rect.width / PANGO_SCALE;
+
+ if (actor_width < text_width)
+ {
+ gint cursor_x = priv->cursor_pos.x;
+
+ if (priv->position == -1)
+ {
+ text_x = actor_width - text_width;
+ priv->cursor_pos.x += text_x + TEXT_PADDING;
+ }
+ else if (priv->position == 0)
+ {
+ text_x = 0;
+ }
+ else
+ {
+ if (text_x <= 0)
+ {
+ gint diff = -1 * text_x;
+
+ if (cursor_x < diff)
+ text_x += diff - cursor_x;
+ else if (cursor_x > (diff + actor_width))
+ text_x -= cursor_x - (diff - actor_width);
+ }
+ }
+ }
+ else
+ {
+ text_x = 0;
+ priv->cursor_pos.x += text_x + TEXT_PADDING;
+ }
+ }
+ else
+ text_x = 0;
+
+ cursor_paint (text);
+
+ real_opacity = clutter_actor_get_paint_opacity (self)
+ * priv->text_color.alpha
+ / 255;
+
+ CLUTTER_NOTE (PAINT, "painting text (text:`%s')", priv->text);
+
+ cogl_color_set_from_4ub (&color,
+ priv->text_color.red,
+ priv->text_color.green,
+ priv->text_color.blue,
+ real_opacity);
+ cogl_pango_render_layout (layout, text_x, 0, &color, 0);
+
+ if (clip_set)
+ cogl_clip_unset ();
+
+ priv->text_x = text_x;
+}
+
+static void
+clutter_text_get_preferred_width (ClutterActor *self,
+ ClutterUnit for_height,
+ ClutterUnit *min_width_p,
+ ClutterUnit *natural_width_p)
+{
+ ClutterText *text = CLUTTER_TEXT (self);
+ ClutterTextPrivate *priv = text->priv;
+ PangoRectangle logical_rect = { 0, };
+ PangoLayout *layout;
+ gint logical_width;
+ ClutterUnit layout_width;
+
+ layout = clutter_text_create_layout (text, -1);
+
+ pango_layout_get_extents (layout, NULL, &logical_rect);
+
+ /* the X coordinate of the logical rectangle might be non-zero
+ * according to the Pango documentation; hence, we need to offset
+ * the width accordingly
+ */
+ logical_width = logical_rect.x + logical_rect.width;
+
+ layout_width = logical_width > 0
+ ? CLUTTER_UNITS_FROM_PANGO_UNIT (logical_width)
+ : 1;
+
+ if (min_width_p)
+ {
+ if (priv->wrap || priv->ellipsize)
+ *min_width_p = 1;
+ else
+ *min_width_p = layout_width;
+ }
+
+ if (natural_width_p)
+ *natural_width_p = layout_width;
+}
+
+static void
+clutter_text_get_preferred_height (ClutterActor *self,
+ ClutterUnit for_width,
+ ClutterUnit *min_height_p,
+ ClutterUnit *natural_height_p)
+{
+ ClutterText *text = CLUTTER_TEXT (self);
+
+ if (for_width == 0)
+ {
+ if (min_height_p)
+ *min_height_p = 0;
+
+ if (natural_height_p)
+ *natural_height_p = 0;
+ }
+ else
+ {
+ PangoLayout *layout;
+ PangoRectangle logical_rect = { 0, };
+ gint logical_height;
+ ClutterUnit layout_height;
+
+ layout = clutter_text_create_layout (text, for_width);
+
+ pango_layout_get_extents (layout, NULL, &logical_rect);
+
+ /* the Y coordinate of the logical rectangle might be non-zero
+ * according to the Pango documentation; hence, we need to offset
+ * the height accordingly
+ */
+ logical_height = logical_rect.y + logical_rect.height;
+
+ layout_height = CLUTTER_UNITS_FROM_PANGO_UNIT (logical_height);
+
+ if (min_height_p)
+ *min_height_p = layout_height;
+
+ if (natural_height_p)
+ *natural_height_p = layout_height;
+ }
+}
+
+static void
+clutter_text_allocate (ClutterActor *self,
+ const ClutterActorBox *box,
+ gboolean origin_changed)
+{
+ ClutterText *text = CLUTTER_TEXT (self);
+ ClutterActorClass *parent_class;
+
+ /* Ensure that there is a cached layout with the right width so
+ * that we don't need to create the text during the paint run
+ */
+ clutter_text_create_layout (text, box->x2 - box->x1);
+
+ parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class);
+ parent_class->allocate (self, box, origin_changed);
+}
+
+static gboolean
+clutter_text_real_move_left (ClutterText *self,
+ const gchar *action,
+ guint keyval,
+ ClutterModifierType modifiers)
+{
+ ClutterTextPrivate *priv = self->priv;
+ gint pos = priv->position;
+ gint len;
+
+ len = priv->n_chars;
+
+ if (pos != 0 && len !=0)
+ {
+ if (pos == -1)
+ clutter_text_set_cursor_position (self, len - 1);
+ else
+ clutter_text_set_cursor_position (self, pos - 1);
+ }
+
+ if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
+ clutter_text_clear_selection (self);
+
+ return TRUE;
+}
+
+static gboolean
+clutter_text_real_move_right (ClutterText *self,
+ const gchar *action,
+ guint keyval,
+ ClutterModifierType modifiers)
+{
+ ClutterTextPrivate *priv = self->priv;
+ gint pos = priv->position;
+ gint len;
+
+ len = priv->n_chars;
+
+ if (pos != -1 && len !=0)
+ {
+ if (pos != len)
+ clutter_text_set_cursor_position (self, pos + 1);
+ }
+
+ if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
+ clutter_text_clear_selection (self);
+
+ return TRUE;
+}
+
+static gboolean
+clutter_text_real_move_up (ClutterText *self,
+ const gchar *action,
+ guint keyval,
+ ClutterModifierType modifiers)
+{
+ ClutterTextPrivate *priv = self->priv;
+ PangoLayoutLine *layout_line;
+ PangoLayout *layout;
+ gint line_no;
+ gint index_;
+ gint x;
+
+ layout = clutter_text_get_layout (self);
+
+ if (priv->position == 0)
+ index_ = 0;
+ else
+ index_ = offset_to_bytes (priv->text, priv->position);
+
+ pango_layout_index_to_line_x (layout, index_,
+ 0,
+ &line_no, &x);
+
+ line_no -= 1;
+ if (line_no < 0)
+ return FALSE;
+
+ if (priv->x_pos != -1)
+ x = priv->x_pos;
+ else
+ priv->x_pos = x;
+
+ layout_line = pango_layout_get_line_readonly (layout, line_no);
+ if (!layout_line)
+ return FALSE;
+
+ pango_layout_line_x_to_index (layout_line, x, &index_, NULL);
+
+ {
+ gint pos = bytes_to_offset (priv->text, index_);
+
+ clutter_text_set_cursor_position (self, pos);
+ }
+
+ if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
+ clutter_text_clear_selection (self);
+
+ return TRUE;
+}
+
+static gboolean
+clutter_text_real_move_down (ClutterText *self,
+ const gchar *action,
+ guint keyval,
+ ClutterModifierType modifiers)
+{
+ ClutterTextPrivate *priv = self->priv;
+ PangoLayoutLine *layout_line;
+ PangoLayout *layout;
+ gint line_no;
+ gint index_;
+ gint x;
+
+ layout = clutter_text_get_layout (self);
+
+ if (priv->position == 0)
+ index_ = 0;
+ else
+ index_ = offset_to_bytes (priv->text, priv->position);
+
+ pango_layout_index_to_line_x (layout, index_,
+ 0,
+ &line_no, &x);
+
+ if (priv->x_pos != -1)
+ x = priv->x_pos;
+ else
+ priv->x_pos = x;
+
+ layout_line = pango_layout_get_line_readonly (layout, line_no + 1);
+ if (!layout_line)
+ return FALSE;
+
+ pango_layout_line_x_to_index (layout_line, x, &index_, NULL);
+
+ {
+ gint pos = bytes_to_offset (priv->text, index_);
+
+ clutter_text_set_cursor_position (self, pos);
+ }
+
+ if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
+ clutter_text_clear_selection (self);
+
+ return TRUE;
+}
+
+static gboolean
+clutter_text_real_line_start (ClutterText *self,
+ const gchar *action,
+ guint keyval,
+ ClutterModifierType modifiers)
+{
+ ClutterTextPrivate *priv = self->priv;
+ PangoLayoutLine *layout_line;
+ PangoLayout *layout;
+ gint line_no;
+ gint index_;
+ gint position;
+
+ layout = clutter_text_get_layout (self);
+
+ if (priv->position == 0)
+ index_ = 0;
+ else
+ index_ = offset_to_bytes (priv->text, priv->position);
+
+ pango_layout_index_to_line_x (layout, index_,
+ 0,
+ &line_no, NULL);
+
+ layout_line = pango_layout_get_line_readonly (layout, line_no);
+ if (!layout_line)
+ return FALSE;
+
+ pango_layout_line_x_to_index (layout_line, 0, &index_, NULL);
+
+ position = bytes_to_offset (priv->text, index_);
+ clutter_text_set_cursor_position (self, position);
+
+ if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
+ clutter_text_clear_selection (self);
+
+ return TRUE;
+}
+
+static gboolean
+clutter_text_real_line_end (ClutterText *self,
+ const gchar *action,
+ guint keyval,
+ ClutterModifierType modifiers)
+{
+ ClutterTextPrivate *priv = self->priv;
+ PangoLayoutLine *layout_line;
+ PangoLayout *layout;
+ gint line_no;
+ gint index_;
+ gint trailing;
+ gint position;
+
+ layout = clutter_text_get_layout (self);
+
+ if (priv->position == 0)
+ index_ = 0;
+ else
+ index_ = offset_to_bytes (priv->text, priv->position);
+
+ pango_layout_index_to_line_x (layout, index_,
+ 0,
+ &line_no, NULL);
+
+ layout_line = pango_layout_get_line_readonly (layout, line_no);
+ if (!layout_line)
+ return FALSE;
+
+ pango_layout_line_x_to_index (layout_line, G_MAXINT, &index_, &trailing);
+ index_ += trailing;
+
+ position = bytes_to_offset (priv->text, index_);
+
+ clutter_text_set_cursor_position (self, position);
+
+ if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
+ clutter_text_clear_selection (self);
+
+ return TRUE;
+}
+
+static gboolean
+clutter_text_real_select_all (ClutterText *self,
+ const gchar *action,
+ guint keyval,
+ ClutterModifierType modifiers)
+{
+ clutter_text_set_cursor_position (self, 0);
+ clutter_text_set_selection_bound (self, self->priv->n_chars);
+
+ return TRUE;
+}
+
+static gboolean
+clutter_text_real_del_next (ClutterText *self,
+ const gchar *action,
+ guint keyval,
+ ClutterModifierType modifiers)
+{
+ ClutterTextPrivate *priv = self->priv;
+ gint pos;
+ gint len;
+
+ if (clutter_text_truncate_selection (self))
+ return TRUE;
+
+ pos = priv->position;
+ len = priv->n_chars;
+
+ if (len && pos != -1 && pos < len)
+ clutter_text_delete_text (self, pos, pos + 1);
+
+ return TRUE;
+}
+
+static gboolean
+clutter_text_real_del_prev (ClutterText *self,
+ const gchar *action,
+ guint keyval,
+ ClutterModifierType modifiers)
+{
+ ClutterTextPrivate *priv = self->priv;
+ gint pos;
+ gint len;
+
+ if (clutter_text_truncate_selection (self))
+ return TRUE;
+
+ pos = priv->position;
+ len = priv->n_chars;
+
+ if (pos != 0 && len != 0)
+ {
+ if (pos == -1)
+ {
+ clutter_text_set_cursor_position (self, len - 1);
+ clutter_text_set_selection_bound (self, len - 1);
+
+ clutter_text_delete_text (self, len - 1, len);
+ }
+ else
+ {
+ clutter_text_set_cursor_position (self, pos - 1);
+ clutter_text_set_selection_bound (self, pos - 1);
+
+ clutter_text_delete_text (self, pos - 1, pos);
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+clutter_text_real_activate (ClutterText *self,
+ const gchar *action,
+ guint keyval,
+ ClutterModifierType modifiers)
+{
+ return clutter_text_activate (self);
+}
+
+static inline void
+clutter_text_add_move_binding (ClutterBindingPool *pool,
+ const gchar *action,
+ guint key_val,
+ GCallback callback)
+{
+ clutter_binding_pool_install_action (pool, action,
+ key_val, 0,
+ callback,
+ NULL, NULL);
+ clutter_binding_pool_install_action (pool, action,
+ key_val, CLUTTER_SHIFT_MASK,
+ callback,
+ NULL, NULL);
+}
+
+static void
+clutter_text_class_init (ClutterTextClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
+ ClutterBindingPool *binding_pool;
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (ClutterTextPrivate));
+
+ gobject_class->set_property = clutter_text_set_property;
+ gobject_class->get_property = clutter_text_get_property;
+ gobject_class->dispose = clutter_text_dispose;
+ gobject_class->finalize = clutter_text_finalize;
+
+ actor_class->paint = clutter_text_paint;
+ actor_class->get_preferred_width = clutter_text_get_preferred_width;
+ actor_class->get_preferred_height = clutter_text_get_preferred_height;
+ actor_class->allocate = clutter_text_allocate;
+ actor_class->key_press_event = clutter_text_key_press;
+ actor_class->button_press_event = clutter_text_button_press;
+ actor_class->button_release_event = clutter_text_button_release;
+ actor_class->motion_event = clutter_text_motion;
+
+ /**
+ * ClutterText:font-name:
+ *
+ * The font to be used by the #ClutterText, as a string
+ * that can be parsed by pango_font_description_from_string().
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_string ("font-name",
+ "Font Name",
+ "The font to be used by the text",
+ NULL,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_FONT_NAME, pspec);
+
+ /**
+ * ClutterText:text:
+ *
+ * The text to render inside the actor.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_string ("text",
+ "Text",
+ "The text to render",
+ "",
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_TEXT, pspec);
+
+ /**
+ * ClutterText:color:
+ *
+ * The color used to render the text.
+ *
+ * Since: 1.0
+ */
+ pspec = clutter_param_spec_color ("color",
+ "Font Color",
+ "Color of the font used by the text",
+ &default_text_color,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_COLOR, pspec);
+
+ /**
+ * ClutterText:editable:
+ *
+ * Whether key events delivered to the actor causes editing.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_boolean ("editable",
+ "Editable",
+ "Whether the text is editable",
+ TRUE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_EDITABLE, pspec);
+
+ /**
+ * ClutterText:selectable:
+ *
+ * Whether it is possible to select text, either using the pointer
+ * or the keyboard.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_boolean ("selectable",
+ "Selectable",
+ "Whether the text is selectable",
+ TRUE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_SELECTABLE, pspec);
+
+ /**
+ * ClutterText:activatable:
+ *
+ * Toggles whether return invokes the activate signal or not.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_boolean ("activatable",
+ "Activatable",
+ "Whether pressing return causes the "
+ "activate signal to be emitted",
+ TRUE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_ACTIVATABLE, pspec);
+
+ /**
+ * ClutterText:cursor-visible:
+ *
+ * Whether the input cursor is visible or not, it will only be visible
+ * if both #ClutterText:cursor-visible and #ClutterText:editable are
+ * set to %TRUE.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_boolean ("cursor-visible",
+ "Cursor Visible",
+ "Whether the input cursor is visible",
+ TRUE,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_CURSOR_VISIBLE, pspec);
+
+ /**
+ * ClutterText:cursor-color:
+ *
+ * The color of the cursor.
+ *
+ * Since: 1.0
+ */
+ pspec = clutter_param_spec_color ("cursor-color",
+ "Cursor Color",
+ "Cursor Color",
+ &default_cursor_color,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_CURSOR_COLOR, pspec);
+
+ /**
+ * ClutterText:cursor-color-set:
+ *
+ * Will be set to %TRUE if #ClutterText:cursor-color has been set.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_boolean ("cursor-color-set",
+ "Cursor Color Set",
+ "Whether the cursor color has been set",
+ FALSE,
+ CLUTTER_PARAM_READABLE);
+ g_object_class_install_property (gobject_class, PROP_CURSOR_COLOR_SET, pspec);
+
+ /**
+ * ClutterText:cursor-size:
+ *
+ * The size of the cursor, in pixels. If set to -1 the size used will
+ * be the default cursor size of 2 pixels.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_int ("cursor-size",
+ "Cursor Size",
+ "The width of the cursor, in pixels",
+ -1, G_MAXINT, DEFAULT_CURSOR_SIZE,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_CURSOR_SIZE, pspec);
+
+ /**
+ * ClutterText:position:
+ *
+ * The current input cursor position. -1 is taken to be the end of the text
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_int ("position",
+ "Position",
+ "The cursor position",
+ -1, G_MAXINT,
+ -1,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_POSITION, pspec);
+
+ /**
+ * ClutterText:selection-bound:
+ *
+ * The current input cursor position. -1 is taken to be the end of the text
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_int ("selection-bound",
+ "Selection-bound",
+ "The cursor position of the other end "
+ "of the selection",
+ -1, G_MAXINT,
+ -1,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_SELECTION_BOUND, pspec);
+
+ /**
+ * ClutterText:attributes:
+ *
+ * A list of #PangoStyleAttributes to be applied to the
+ * contents of the #ClutterText actor.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_boxed ("attributes",
+ "Attributes",
+ "A list of style attributes to apply to "
+ "the contents of the actor",
+ PANGO_TYPE_ATTR_LIST,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, pspec);
+
+ /**
+ * ClutterText:use-markup:
+ *
+ * Whether the text includes Pango markup. See pango_layout_set_markup()
+ * in the Pango documentation.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_boolean ("use-markup",
+ "Use markup",
+ "Whether or not the text "
+ "includes Pango markup",
+ FALSE,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_USE_MARKUP, pspec);
+
+ /**
+ * ClutterText:line-wrap:
+ *
+ * Whether to wrap the lines of #ClutterText:text if the contents
+ * exceed the available allocation. The wrapping strategy is
+ * controlled by the #ClutterText:line-wrap-mode property.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_boolean ("line-wrap",
+ "Line wrap",
+ "If set, wrap the lines if the text "
+ "becomes too wide",
+ FALSE,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_LINE_WRAP, pspec);
+
+ /**
+ * ClutterText:line-wrap-mode:
+ *
+ * If #ClutterText:line-wrap is set to %TRUE, this property will
+ * control how the text is wrapped.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_enum ("line-wrap-mode",
+ "Line wrap mode",
+ "Control how line-wrapping is done",
+ PANGO_TYPE_WRAP_MODE,
+ PANGO_WRAP_WORD,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_LINE_WRAP_MODE, pspec);
+
+ /**
+ * ClutterText:ellipsize:
+ *
+ * The preferred place to ellipsize the contents of the #ClutterText actor
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_enum ("ellipsize",
+ "Ellipsize",
+ "The preferred place to ellipsize the string",
+ PANGO_TYPE_ELLIPSIZE_MODE,
+ PANGO_ELLIPSIZE_NONE,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_ELLIPSIZE, pspec);
+
+ /**
+ * ClutterText:alignment:
+ *
+ * The preferred alignment for the text. This property controls
+ * the alignment of multi-line paragraphs.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_enum ("alignment",
+ "Alignment",
+ "The preferred alignment for the string, "
+ "for multi-line text",
+ PANGO_TYPE_ALIGNMENT,
+ PANGO_ALIGN_LEFT,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_ALIGNMENT, pspec);
+
+ /**
+ * ClutterText:justify:
+ *
+ * Whether the contents of the #ClutterText should be justified
+ * on both margins.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_boolean ("justify",
+ "Justify",
+ "Whether the text should be justified",
+ FALSE,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_JUSTIFY, pspec);
+
+ /**
+ * ClutterText:password-char:
+ *
+ * If non-zero, the character that should be used in place of
+ * the actual text in a password text actor.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_unichar ("password-char",
+ "Password Character",
+ "If non-zero, use this character to "
+ "display the actor's contents",
+ 0,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_PASSWORD_CHAR, pspec);
+
+ /**
+ * ClutterText:max-length:
+ *
+ * The maximum length of the contents of the #ClutterText actor.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_int ("max-length",
+ "Max Length",
+ "Maximum length of the text inside the actor",
+ -1, G_MAXINT, 0,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_MAX_LENGTH, pspec);
+
+ /**
+ * ClutterText:single-line-mode:
+ *
+ * Whether the #ClutterText actor should be in single line mode
+ * or not. A single line #ClutterText actor will only contain a
+ * single line of text, scrolling it in case its length is bigger
+ * than the allocated size.
+ *
+ * Setting this property will also set the #ClutterText:activatable
+ * property as a side-effect.
+ *
+ * Since: 1.0
+ */
+ pspec = g_param_spec_boolean ("single-line-mode",
+ "Single Line Mode",
+ "Whether the text should be a single line",
+ FALSE,
+ CLUTTER_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_SINGLE_LINE_MODE, pspec);
+
+ /**
+ * ClutterText::text-changed:
+ * @self: the #ClutterText that emitted the signal
+ *
+ * The ::text-changed signal is emitted after @actor's text changes
+ *
+ * Since: 1.0
+ */
+ text_signals[TEXT_CHANGED] =
+ g_signal_new ("text-changed",
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterTextClass, text_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /**
+ * ClutterText::cursor-event:
+ * @self: the #ClutterText that emitted the signal
+ * @geometry: the coordinates of the cursor
+ *
+ * The ::cursor-event signal is emitted whenever the cursor position
+ * changes inside a #ClutterText actor. Inside @geometry it is stored
+ * the current position and size of the cursor, relative to the actor
+ * itself.
+ *
+ * Since: 1.0
+ */
+ text_signals[CURSOR_EVENT] =
+ g_signal_new ("cursor-event",
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterTextClass, cursor_event),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1,
+ CLUTTER_TYPE_GEOMETRY | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ /**
+ * ClutterText::activate
+ * @self: the #ClutterText that emitted the signal
+ *
+ * The ::activate signal is emitted each time the actor is 'activated'
+ * by the user, normally by pressing the 'Enter' key. The signal is
+ * emitted only if #ClutterText:activatable is set to %TRUE.
+ *
+ * Since: 1.0
+ */
+ text_signals[ACTIVATE] =
+ g_signal_new ("activate",
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ClutterTextClass, activate),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ binding_pool = clutter_binding_pool_get_for_class (klass);
+
+ clutter_text_add_move_binding (binding_pool, "move-left",
+ CLUTTER_Left,
+ G_CALLBACK (clutter_text_real_move_left));
+ clutter_text_add_move_binding (binding_pool, "move-left",
+ CLUTTER_KP_Left,
+ G_CALLBACK (clutter_text_real_move_left));
+ clutter_text_add_move_binding (binding_pool, "move-right",
+ CLUTTER_Right,
+ G_CALLBACK (clutter_text_real_move_right));
+ clutter_text_add_move_binding (binding_pool, "move-right",
+ CLUTTER_KP_Right,
+ G_CALLBACK (clutter_text_real_move_right));
+ clutter_text_add_move_binding (binding_pool, "move-up",
+ CLUTTER_Up,
+ G_CALLBACK (clutter_text_real_move_up));
+ clutter_text_add_move_binding (binding_pool, "move-up",
+ CLUTTER_KP_Up,
+ G_CALLBACK (clutter_text_real_move_up));
+ clutter_text_add_move_binding (binding_pool, "move-down",
+ CLUTTER_Down,
+ G_CALLBACK (clutter_text_real_move_down));
+ clutter_text_add_move_binding (binding_pool, "move-down",
+ CLUTTER_KP_Down,
+ G_CALLBACK (clutter_text_real_move_down));
+
+ clutter_text_add_move_binding (binding_pool, "line-start",
+ CLUTTER_Home,
+ G_CALLBACK (clutter_text_real_line_start));
+ clutter_text_add_move_binding (binding_pool, "line-start",
+ CLUTTER_KP_Home,
+ G_CALLBACK (clutter_text_real_line_start));
+ clutter_text_add_move_binding (binding_pool, "line-start",
+ CLUTTER_Begin,
+ G_CALLBACK (clutter_text_real_line_start));
+ clutter_text_add_move_binding (binding_pool, "line-end",
+ CLUTTER_End,
+ G_CALLBACK (clutter_text_real_line_end));
+ clutter_text_add_move_binding (binding_pool, "line-end",
+ CLUTTER_KP_End,
+ G_CALLBACK (clutter_text_real_line_end));
+
+ clutter_binding_pool_install_action (binding_pool, "select-all",
+ CLUTTER_a, CLUTTER_CONTROL_MASK,
+ G_CALLBACK (clutter_text_real_select_all),
+ NULL, NULL);
+
+ clutter_binding_pool_install_action (binding_pool, "delete-next",
+ CLUTTER_Delete, 0,
+ G_CALLBACK (clutter_text_real_del_next),
+ NULL, NULL);
+ clutter_binding_pool_install_action (binding_pool, "delete-next",
+ CLUTTER_KP_Delete, 0,
+ G_CALLBACK (clutter_text_real_del_next),
+ NULL, NULL);
+ clutter_binding_pool_install_action (binding_pool, "delete-prev",
+ CLUTTER_BackSpace, 0,
+ G_CALLBACK (clutter_text_real_del_prev),
+ NULL, NULL);
+
+ clutter_binding_pool_install_action (binding_pool, "activate",
+ CLUTTER_Return, 0,
+ G_CALLBACK (clutter_text_real_activate),
+ NULL, NULL);
+ clutter_binding_pool_install_action (binding_pool, "activate",
+ CLUTTER_KP_Enter, 0,
+ G_CALLBACK (clutter_text_real_activate),
+ NULL, NULL);
+ clutter_binding_pool_install_action (binding_pool, "activate",
+ CLUTTER_ISO_Enter, 0,
+ G_CALLBACK (clutter_text_real_activate),
+ NULL, NULL);
+}
+
+static void
+clutter_text_init (ClutterText *self)
+{
+ ClutterTextPrivate *priv;
+ const gchar *font_name;
+ int i;
+
+ self->priv = priv = CLUTTER_TEXT_GET_PRIVATE (self);
+
+ priv->alignment = PANGO_ALIGN_LEFT;
+ priv->wrap = FALSE;
+ priv->wrap_mode = PANGO_WRAP_WORD;
+ priv->ellipsize = PANGO_ELLIPSIZE_NONE;
+ priv->use_underline = FALSE;
+ priv->use_markup = FALSE;
+ priv->justify = FALSE;
+
+ for (i = 0; i < N_CACHED_LAYOUTS; i++)
+ priv->cached_layouts[i].layout = NULL;
+
+ /* default to "" so that clutter_text_get_text() will
+ * return a valid string and we can safely call strlen()
+ * or strcmp() on it
+ */
+ priv->text = g_strdup ("");
+
+ priv->text_color = default_text_color;
+ priv->cursor_color = default_cursor_color;
+
+ /* get the default font name from the context */
+ font_name = clutter_backend_get_font_name (clutter_get_default_backend ());
+ priv->font_name = g_strdup (font_name);
+ priv->font_desc = pango_font_description_from_string (font_name);
+
+ priv->position = -1;
+ priv->selection_bound = -1;
+
+ priv->x_pos = -1;
+ priv->cursor_visible = TRUE;
+ priv->editable = FALSE;
+ priv->selectable = TRUE;
+
+ priv->cursor_color_set = FALSE;
+
+ priv->password_char = 0;
+
+ priv->max_length = 0;
+
+ priv->cursor_size = DEFAULT_CURSOR_SIZE;
+}
+
+/**
+ * clutter_text_new:
+ *
+ * Creates a new #ClutterText actor. This actor can be used to
+ * display and edit text.
+ *
+ * Return value: the newly created #ClutterText actor
+ *
+ * Since: 1.0
+ */
+ClutterActor *
+clutter_text_new (void)
+{
+ return g_object_new (CLUTTER_TYPE_TEXT, NULL);
+}
+
+/**
+ * clutter_text_new_full:
+ * @font_name: a string with a font description
+ * @text: the contents of the actor
+ * @color: the color to be used to render @text
+ *
+ * Creates a new #ClutterText actor, using @font_name as the font
+ * description; @text will be used to set the contents of the actor;
+ * and @color will be used as the color to render @text.
+ *
+ * This function is equivalent to calling clutter_text_new(),
+ * clutter_text_set_font_name(), clutter_text_set_text() and
+ * clutter_text_set_color().
+ *
+ * Return value: the newly created #ClutterText actor
+ *
+ * Since: 1.0
+ */
+ClutterActor *
+clutter_text_new_full (const gchar *font_name,
+ const gchar *text,
+ const ClutterColor *color)
+{
+ return g_object_new (CLUTTER_TYPE_TEXT,
+ "font-name", font_name,
+ "text", text,
+ "color", color,
+ NULL);
+}
+
+/**
+ * clutter_text_new_with_text:
+ * @font_name: a string with a font description
+ * @text: the contents of the actor
+ *
+ * Creates a new #ClutterText actor, using @font_name as the font
+ * description; @text will be used to set the contents of the actor.
+ *
+ * This function is equivalent to calling clutter_text_new(),
+ * clutter_text_set_font_name(), and clutter_text_set_text().
+ *
+ * Return value: the newly created #ClutterText actor
+ *
+ * Since: 1.0
+ */
+ClutterActor *
+clutter_text_new_with_text (const gchar *font_name,
+ const gchar *text)
+{
+ return g_object_new (CLUTTER_TYPE_TEXT,
+ "font-name", font_name,
+ "text", text,
+ NULL);
+}
+
+/**
+ * clutter_text_set_editable:
+ * @self: a #ClutterText
+ * @editable: whether the #ClutterText should be editable
+ *
+ * Sets whether the #ClutterText actor should be editable.
+ *
+ * An editable #ClutterText with key focus set using
+ * clutter_actor_grab_key_focus() or clutter_stage_take_key_focus()
+ * will receive key events and will update its contents accordingly.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_editable (ClutterText *self,
+ gboolean editable)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->editable != editable)
+ {
+ priv->editable = editable;
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (self))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "editable");
+ }
+}
+
+/**
+ * clutter_text_get_editable:
+ * @self: a #ClutterText
+ *
+ * Retrieves whether a #ClutterText is editable or not.
+ *
+ * Return value: %TRUE if the actor is editable
+ *
+ * Since: 1.0
+ */
+gboolean
+clutter_text_get_editable (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
+
+ return self->priv->editable;
+}
+
+/**
+ * clutter_text_set_selectable:
+ * @self: a #ClutterText
+ * @selectable: whether the #ClutterText actor should be selectable
+ *
+ * Sets whether a #ClutterText actor should be selectable.
+ *
+ * A selectable #ClutterText will allow selecting its contents using
+ * the pointer or the keyboard.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_selectable (ClutterText *self,
+ gboolean selectable)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->selectable != selectable)
+ {
+ priv->selectable = selectable;
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (self))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "selectable");
+ }
+}
+
+/**
+ * clutter_text_get_selectable:
+ * @self: a #ClutterText
+ *
+ * Retrieves whether a #ClutterText is selectable or not.
+ *
+ * Return value: %TRUE if the actor is selectable
+ *
+ * Since: 1.0
+ */
+gboolean
+clutter_text_get_selectable (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
+
+ return self->priv->selectable;
+}
+
+/**
+ * clutter_text_set_activatable:
+ * @self: a #ClutterText
+ * @activatable: whether the #ClutterText actor should be activatable
+ *
+ * Sets whether a #ClutterText actor should be activatable.
+ *
+ * An activatable #ClutterText actor will emit the #ClutterText::activate
+ * signal whenever the 'Enter' (or 'Return') key is pressed; if it is not
+ * activatable, a new line will be appended to the current content.
+ *
+ * An activatable #ClutterText must also be set as editable using
+ * clutter_text_set_editable().
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_activatable (ClutterText *self,
+ gboolean activatable)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->activatable != activatable)
+ {
+ priv->activatable = activatable;
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (self))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "activatable");
+ }
+}
+
+/**
+ * clutter_text_get_activatable:
+ * @self: a #ClutterText
+ *
+ * Retrieves whether a #ClutterText is activatable or not.
+ *
+ * Return value: %TRUE if the actor is activatable
+ *
+ * Since: 1.0
+ */
+gboolean
+clutter_text_get_activatable (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
+
+ return self->priv->activatable;
+}
+
+/**
+ * clutter_text_activate:
+ * @self: a #ClutterText
+ *
+ * Emits the #ClutterText::activate signal, if @self has been set
+ * as activatable using clutter_text_set_activatable().
+ *
+ * This function can be used to emit the ::activate signal inside
+ * a #ClutterActor::captured-event or #ClutterActor::key-press-event
+ * signal handlers before the default signal handler for the
+ * #ClutterText is invoked.
+ *
+ * Return value: %TRUE if the ::activate signal has been emitted,
+ * and %FALSE otherwise
+ *
+ * Since: 1.0
+ */
+gboolean
+clutter_text_activate (ClutterText *self)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
+
+ priv = self->priv;
+
+ if (priv->activatable)
+ {
+ g_signal_emit (self, text_signals[ACTIVATE], 0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * clutter_text_set_cursor_visible:
+ * @self: a #ClutterText
+ * @cursor_visible: whether the cursor should be visible
+ *
+ * Sets whether the cursor of a #ClutterText actor should be
+ * visible or not.
+ *
+ * The color of the cursor will be the same as the text color
+ * unless clutter_text_set_cursor_color() has been called.
+ *
+ * The size of the cursor can be set using clutter_text_set_cursor_size().
+ *
+ * The position of the cursor can be changed programmatically using
+ * clutter_text_set_cursor_position().
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_cursor_visible (ClutterText *self,
+ gboolean cursor_visible)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->cursor_visible != cursor_visible)
+ {
+ priv->cursor_visible = cursor_visible;
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (self))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "cursor-visible");
+ }
+}
+
+/**
+ * clutter_text_get_cursor_visible:
+ * @self: a #ClutterText
+ *
+ * Retrieves whether the cursor of a #ClutterText actor is visible.
+ *
+ * Return value: %TRUE if the cursor is visible
+ *
+ * Since: 1.0
+ */
+gboolean
+clutter_text_get_cursor_visible (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
+
+ return self->priv->cursor_visible;
+}
+
+/**
+ * clutter_text_set_cursor_color:
+ * @self: a #ClutterText
+ * @color: the color of the cursor, or %NULL to unset it
+ *
+ * Sets the color of the cursor of a #ClutterText actor.
+ *
+ * If @color is %NULL, the cursor color will be the same as the
+ * text color.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_cursor_color (ClutterText *self,
+ const ClutterColor *color)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (color)
+ {
+ priv->cursor_color = *color;
+ priv->cursor_color_set = TRUE;
+ }
+ else
+ priv->cursor_color_set = FALSE;
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (self))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "cursor-color");
+ g_object_notify (G_OBJECT (self), "cursor-color-set");
+}
+
+/**
+ * clutter_text_get_cursor_color:
+ * @self: a #ClutterText
+ * @color: return location for a #ClutterColor
+ *
+ * Retrieves the color of the cursor of a #ClutterText actor.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_get_cursor_color (ClutterText *self,
+ ClutterColor *color)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+ g_return_if_fail (color != NULL);
+
+ priv = self->priv;
+
+ *color = priv->cursor_color;
+}
+
+/**
+ * clutter_text_set_selection:
+ * @self: a #ClutterText
+ * @start_pos: start of the selection, in characters
+ * @end_pos: end of the selection, in characters
+ *
+ * Selects the region of text between @start_pos and @end_pos.
+ *
+ * This function changes the position of the cursor to match
+ * @start_pos and the selection bound to match @end_pos.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_selection (ClutterText *self,
+ gssize start_pos,
+ gssize end_pos)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (end_pos < 0)
+ end_pos = priv->n_chars;
+
+ start_pos = MIN (priv->n_chars, start_pos);
+ end_pos = MIN (priv->n_chars, end_pos);
+
+ g_object_freeze_notify (G_OBJECT (self));
+
+ clutter_text_set_cursor_position (self, start_pos);
+ clutter_text_set_selection_bound (self, end_pos);
+
+ g_object_thaw_notify (G_OBJECT (self));
+}
+
+/**
+ * clutter_text_get_selection:
+ * @self: a #ClutterText
+ *
+ * Retrieves the currently selected text.
+ *
+ * Return value: a newly allocated string containing the currently
+ * selected text, or %NULL. Use g_free() to free the returned
+ * string.
+ *
+ * Since: 1.0
+ */
+gchar *
+clutter_text_get_selection (ClutterText *self)
+{
+ ClutterTextPrivate *priv;
+ gchar *str;
+ gint len;
+ gint start_index, end_index;
+ gint start_offset, end_offset;
+
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
+
+ priv = self->priv;
+
+ start_index = priv->position;
+ end_index = priv->selection_bound;
+
+ if (end_index == start_index)
+ return g_strdup ("");
+
+ if (end_index < start_index)
+ {
+ gint temp = start_index;
+ start_index = end_index;
+ end_index = temp;
+ }
+
+ start_offset = offset_to_bytes (priv->text, start_index);
+ end_offset = offset_to_bytes (priv->text, end_index);
+ len = end_offset - start_offset;
+
+ str = g_malloc (len + 1);
+ g_utf8_strncpy (str, priv->text + start_offset, end_index - start_index);
+
+ return str;
+}
+
+/**
+ * clutter_text_set_selection_bound:
+ * @self: a #ClutterText
+ * @selection_bound: the position of the end of the selection, in characters
+ *
+ * Sets the other end of the selection, starting from the current
+ * cursor position.
+ *
+ * If @selection_bound is -1, the selection unset.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_selection_bound (ClutterText *self,
+ gint selection_bound)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->selection_bound != selection_bound)
+ {
+ priv->selection_bound = selection_bound;
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (self))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "selection-bound");
+ }
+}
+
+/**
+ * clutter_text_get_selection_bound:
+ * @self: a #ClutterText
+ *
+ * Retrieves the other end of the selection of a #ClutterText actor,
+ * in characters from the current cursor position.
+ *
+ * Return value: the position of the other end of the selection
+ *
+ * Since: 1.0
+ */
+gint
+clutter_text_get_selection_bound (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), -1);
+
+ return self->priv->selection_bound;
+}
+
+/**
+ * clutter_text_get_font_name:
+ * @self: a #ClutterText
+ *
+ * Retrieves the font name as set by clutter_text_set_font_name().
+ *
+ * Return value: a string containing the font name. The returned
+ * string is owned by the #ClutterText actor and should not be
+ * modified or freed
+ *
+ * Since: 1.0
+ */
+G_CONST_RETURN gchar *
+clutter_text_get_font_name (ClutterText *text)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (text), NULL);
+
+ return text->priv->font_name;
+}
+
+/**
+ * clutter_text_set_font_name:
+ * @self: a #ClutterText
+ * @font_name: a font name, or %NULL to set the default font name
+ *
+ * Sets the font used by a #ClutterText. The @font_name string
+ * must either be %NULL, which means that the font name from the
+ * default #ClutterBackend will be used; or be something that can
+ * be parsed by the pango_font_description_from_string() function,
+ * like:
+ *
+ * |[
+ * clutter_text_set_font_name (text, "Sans 10pt");
+ * clutter_text_set_font_name (text, "Serif 16px");
+ * clutter_text_set_font_name (text, "Helvetica 10");
+ * ]|
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_font_name (ClutterText *self,
+ const gchar *font_name)
+{
+ ClutterTextPrivate *priv;
+ PangoFontDescription *desc;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ /* get the default font name from the backend */
+ if (!font_name || font_name[0] == '\0')
+ font_name = clutter_backend_get_font_name (clutter_get_default_backend ());
+
+ priv = self->priv;
+
+ if (priv->font_name && strcmp (priv->font_name, font_name) == 0)
+ return;
+
+ desc = pango_font_description_from_string (font_name);
+ if (!desc)
+ {
+ g_warning ("Attempting to create a PangoFontDescription for "
+ "font name `%s', but failed.",
+ font_name);
+ return;
+ }
+
+ g_free (priv->font_name);
+ priv->font_name = g_strdup (font_name);
+
+ if (priv->font_desc)
+ pango_font_description_free (priv->font_desc);
+
+ priv->font_desc = desc;
+
+ clutter_text_dirty_cache (self);
+
+ if (priv->text && priv->text[0] != '\0')
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "font-name");
+}
+
+/**
+ * clutter_text_get_text:
+ * @self: a #ClutterText
+ *
+ * Retrieves a pointer to the current contents of a #ClutterText
+ * actor.
+ *
+ * If you need a copy of the contents for manipulating, either
+ * use g_strdup() on the returned string, or use:
+ *
+ * |[
+ * copy = clutter_text_get_chars (text, 0, -1);
+ * ]|
+ *
+ * Which will return a newly allocated string.
+ *
+ * Return value: the contents of the actor. The returned string
+ * is owned by the #ClutterText actor and should never be
+ * modified or freed
+ *
+ * Since: 1.0
+ */
+G_CONST_RETURN gchar *
+clutter_text_get_text (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
+
+ return self->priv->text;
+}
+
+/**
+ * clutter_text_set_text:
+ * @self: a #ClutterText
+ * @text: the text to set
+ *
+ * Sets the contents of a #ClutterText actor. The @text string
+ * must not be %NULL; to unset the current contents of the
+ * #ClutterText actor simply pass "" (an empty string).
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_text (ClutterText *self,
+ const gchar *text)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+ g_return_if_fail (text != NULL);
+
+ priv = self->priv;
+
+ if (priv->max_length > 0)
+ {
+ gint len = g_utf8_strlen (text, -1);
+
+ if (len < priv->max_length)
+ {
+ g_free (priv->text);
+
+ priv->text = g_strdup (text);
+ priv->n_bytes = strlen (text);
+ priv->n_chars = len;
+ }
+ else
+ {
+ gchar *n = g_malloc0 (priv->max_length + 1);
+
+ g_free (priv->text);
+
+ g_utf8_strncpy (n, text, priv->max_length);
+
+ priv->text = n;
+ priv->n_bytes = strlen (n);
+ priv->n_chars = priv->max_length;
+ }
+ }
+ else
+ {
+ g_free (priv->text);
+
+ priv->text = g_strdup (text);
+ priv->n_bytes = strlen (text);
+ priv->n_chars = g_utf8_strlen (text, -1);
+ }
+
+ clutter_text_dirty_cache (self);
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+
+ g_signal_emit (self, text_signals[TEXT_CHANGED], 0);
+
+ g_object_notify (G_OBJECT (self), "text");
+}
+
+/**
+ * clutter_text_get_layout:
+ * @self: a #ClutterText
+ *
+ * Retrieves the current #PangoLayout used by a #ClutterText actor.
+ *
+ * Return value: a #PangoLayout. The returned object is owned by
+ * the #ClutterText actor and should not be modified or freed
+ *
+ * Since: 1.0
+ */
+PangoLayout *
+clutter_text_get_layout (ClutterText *self)
+{
+ ClutterUnit width;
+
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
+
+ width = clutter_actor_get_widthu (CLUTTER_ACTOR (self));
+
+ return clutter_text_create_layout (self, width);
+}
+
+/**
+ * clutter_text_set_color:
+ * @self: a #ClutterText
+ * @color: a #ClutterColor
+ *
+ * Sets the color of the contents of a #ClutterText actor.
+ *
+ * The overall opacity of the #ClutterText actor will be the
+ * result of the alpha value of @color and the composited
+ * opacity of the actor itself on the scenegraph, as returned
+ * by clutter_actor_get_paint_opacity().
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_color (ClutterText *self,
+ const ClutterColor *color)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+ g_return_if_fail (color != NULL);
+
+ priv = self->priv;
+
+ priv->text_color = *color;
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (self))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "color");
+}
+
+/**
+ * clutter_text_get_color:
+ * @self: a #ClutterText
+ * @color: return location for a #ClutterColor
+ *
+ * Retrieves the text color as set by clutter_text_get_color().
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_get_color (ClutterText *self,
+ ClutterColor *color)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+ g_return_if_fail (color != NULL);
+
+ priv = self->priv;
+
+ *color = priv->text_color;
+}
+
+/**
+ * clutter_text_set_ellipsize:
+ * @self: a #ClutterText
+ * @mode: a #PangoEllipsizeMode
+ *
+ * Sets the mode used to ellipsize (add an ellipsis: "...") to the
+ * text if there is not enough space to render the entire contents
+ * of a #ClutterText actor
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_ellipsize (ClutterText *self,
+ PangoEllipsizeMode mode)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+ g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE &&
+ mode <= PANGO_ELLIPSIZE_END);
+
+ priv = self->priv;
+
+ if ((PangoEllipsizeMode) priv->ellipsize != mode)
+ {
+ priv->ellipsize = mode;
+
+ clutter_text_dirty_cache (self);
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "ellipsize");
+ }
+}
+
+/**
+ * clutter_text_get_ellipsize:
+ * @self: a #ClutterText
+ *
+ * Returns the ellipsizing position of a #ClutterText actor, as
+ * set by clutter_text_set_ellipsize().
+ *
+ * Return value: #PangoEllipsizeMode
+ *
+ * Since: 1.0
+ */
+PangoEllipsizeMode
+clutter_text_get_ellipsize (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_ELLIPSIZE_NONE);
+
+ return self->priv->ellipsize;
+}
+
+/**
+ * clutter_text_get_line_wrap:
+ * @self: a #ClutterText
+ *
+ * Retrieves the value set using clutter_text_set_line_wrap().
+ *
+ * Return value: %TRUE if the #ClutterText actor should wrap
+ * its contents
+ *
+ * Since: 1.0
+ */
+gboolean
+clutter_text_get_line_wrap (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
+
+ return self->priv->wrap;
+}
+
+/**
+ * clutter_text_set_line_wrap:
+ * @self: a #ClutterText
+ * @line_wrap: whether the contents should wrap
+ *
+ * Sets whether the contents of a #ClutterText actor should wrap,
+ * if they don't fit the size assigned to the actor.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_line_wrap (ClutterText *self,
+ gboolean line_wrap)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->wrap != line_wrap)
+ {
+ priv->wrap = line_wrap;
+
+ clutter_text_dirty_cache (self);
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "line-wrap");
+ }
+}
+
+/**
+ * clutter_text_set_line_wrap_mode:
+ * @self: a #ClutterText
+ * @wrap_mode: the line wrapping mode
+ *
+ * If line wrapping is enabled (see clutter_text_set_line_wrap()) this
+ * function controls how the line wrapping is performed. The default is
+ * %PANGO_WRAP_WORD which means wrap on word boundaries.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_line_wrap_mode (ClutterText *self,
+ PangoWrapMode wrap_mode)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->wrap_mode != wrap_mode)
+ {
+ priv->wrap_mode = wrap_mode;
+
+ clutter_text_dirty_cache (self);
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "line-wrap-mode");
+ }
+}
+
+/**
+ * clutter_text_get_line_wrap_mode:
+ * @self: a #ClutterText
+ *
+ * Retrieves the line wrap mode used by the #ClutterText actor.
+ *
+ * See clutter_text_set_line_wrap_mode ().
+ *
+ * Return value: the wrap mode used by the #ClutterText
+ *
+ * Since: 1.0
+ */
+PangoWrapMode
+clutter_text_get_line_wrap_mode (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_WRAP_WORD);
+
+ return self->priv->wrap_mode;
+}
+
+/**
+ * clutter_text_set_attributes:
+ * @self: a #ClutterText
+ * @attrs: a #PangoAttrList or %NULL to unset the attributes
+ *
+ * Sets the attributes list that are going to be applied to the
+ * #ClutterText contents. The attributes set with this function
+ * will be ignored if the #ClutterText:use_markup property is
+ * set to %TRUE.
+ *
+ * The #ClutterText actor will take a reference on the #PangoAttrList
+ * passed to this function.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_attributes (ClutterText *self,
+ PangoAttrList *attrs)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (attrs)
+ pango_attr_list_ref (attrs);
+
+ if (priv->attrs)
+ pango_attr_list_unref (priv->attrs);
+
+ if (!priv->use_markup)
+ {
+ if (attrs)
+ pango_attr_list_ref (attrs);
+
+ if (priv->effective_attrs)
+ pango_attr_list_unref (priv->effective_attrs);
+
+ priv->effective_attrs = attrs;
+ }
+
+ priv->attrs = attrs;
+
+ clutter_text_dirty_cache (self);
+
+ g_object_notify (G_OBJECT (self), "attributes");
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+}
+
+/**
+ * clutter_text_get_attributes:
+ * @self: a #ClutterText
+ *
+ * Gets the attribute list that was set on the #ClutterText actor
+ * clutter_text_set_attributes(), if any.
+ *
+ * Return value: the attribute list, or %NULL if none was set. The
+ * returned value is owned by the #ClutterText and should not be
+ * unreferenced.
+ *
+ * Since: 1.0
+ */
+PangoAttrList *
+clutter_text_get_attributes (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
+
+ return self->priv->attrs;
+}
+
+/**
+ * clutter_text_set_alignment:
+ * @self: a #ClutterText
+ * @alignment: A #PangoAlignment
+ *
+ * Sets text alignment of the #ClutterText actor.
+ *
+ * The alignment will only be used when the contents of the
+ * #ClutterText actor are enough to wrap, and the #ClutterText:line-wrap
+ * property is set to %TRUE.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_alignment (ClutterText *self,
+ PangoAlignment alignment)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->alignment != alignment)
+ {
+ priv->alignment = alignment;
+
+ clutter_text_dirty_cache (self);
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "alignment");
+ }
+}
+
+/**
+ * clutter_text_get_alignment:
+ * @self: a #ClutterText
+ *
+ * Retrieves the alignment of @self.
+ *
+ * Return value: a #PangoAlignment
+ *
+ * Since 1.0
+ */
+PangoAlignment
+clutter_text_get_alignment (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_ALIGN_LEFT);
+
+ return self->priv->alignment;
+}
+
+/**
+ * clutter_text_set_use_markup:
+ * @self: a #ClutterText
+ * @setting: %TRUE if the text should be parsed for markup.
+ *
+ * Sets whether the contents of the #ClutterText actor contains markup
+ * in Pango's text markup language.
+ *
+ * Calling this function on an editable #ClutterText will not cause
+ * the actor to parse any markup.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_use_markup (ClutterText *self,
+ gboolean setting)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->use_markup != setting)
+ {
+ priv->use_markup = setting;
+
+ clutter_text_dirty_cache (self);
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "use-markup");
+ }
+}
+
+/**
+ * clutter_text_get_use_markup:
+ * @self: a #ClutterText
+ *
+ * Retrieves whether the contents of the #ClutterText actor should be
+ * parsed for the Pango text markup.
+ *
+ * Return value: %TRUE if the contents will be parsed for markup
+ *
+ * Since: 1.0
+ */
+gboolean
+clutter_text_get_use_markup (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
+
+ return self->priv->use_markup;
+}
+
+/**
+ * clutter_text_set_justify:
+ * @self: a #ClutterText
+ * @justify: whether the text should be justified
+ *
+ * Sets whether the text of the #ClutterText actor should be justified
+ * on both margins. This setting is ignored if Clutter is compiled
+ * against Pango < 1.18.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_justify (ClutterText *self,
+ gboolean justify)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->justify != justify)
+ {
+ priv->justify = justify;
+
+ clutter_text_dirty_cache (self);
+
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "justify");
+ }
+}
+
+/**
+ * clutter_text_get_justify:
+ * @self: a #ClutterText
+ *
+ * Retrieves whether the #ClutterText actor should justify its contents
+ * on both margins.
+ *
+ * Return value: %TRUE if the text should be justified
+ *
+ * Since: 0.6
+ */
+gboolean
+clutter_text_get_justify (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
+
+ return self->priv->justify;
+}
+
+/**
+ * clutter_text_get_cursor_position:
+ * @self: a #ClutterText
+ *
+ * Retrieves the cursor position.
+ *
+ * Return value: the cursor position, in characters
+ *
+ * Since: 1.0
+ */
+gint
+clutter_text_get_cursor_position (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), -1);
+
+ return self->priv->position;
+}
+
+/**
+ * clutter_text_set_cursor_position:
+ * @self: a #ClutterText
+ * @position: the new cursor position, in characters
+ *
+ * Sets the cursor of a #ClutterText actor at @position.
+ *
+ * The position is expressed in characters, not in bytes.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_cursor_position (ClutterText *self,
+ gint position)
+{
+ ClutterTextPrivate *priv;
+ gint len;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ len = priv->n_chars;
+
+ if (position < 0 || position >= len)
+ priv->position = -1;
+ else
+ priv->position = position;
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (self))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+}
+
+/**
+ * clutter_text_set_cursor_size:
+ * @self: a #ClutterText
+ * @size: the size of the cursor, in pixels, or -1 to use the
+ * default value
+ *
+ * Sets the size of the cursor of a #ClutterText. The cursor
+ * will only be visible if the #ClutterText:cursor-visible property
+ * is set to %TRUE.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_cursor_size (ClutterText *self,
+ gint size)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->cursor_size != size)
+ {
+ if (size < 0)
+ size = DEFAULT_CURSOR_SIZE;
+
+ priv->cursor_size = size;
+
+ if (CLUTTER_ACTOR_IS_VISIBLE (self))
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "cursor-size");
+ }
+}
+
+/**
+ * clutter_text_get_cursor_size:
+ * @self: a #ClutterText
+ *
+ * Retrieves the size of the cursor of a #ClutterText actor.
+ *
+ * Return value: the size of the cursor, in pixels
+ *
+ * Since: 1.0
+ */
+guint
+clutter_text_get_cursor_size (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), DEFAULT_CURSOR_SIZE);
+
+ return self->priv->cursor_size;
+}
+
+/**
+ * clutter_text_set_password_char:
+ * @self: a #ClutterText
+ * @wc: a Unicode character, or 0 to unset the password character
+ *
+ * Sets the character to use in place of the actual text in a
+ * password text actor.
+ *
+ * If @wc is 0 the text will be displayed as it is entered in the
+ * #ClutterText actor.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_password_char (ClutterText *self,
+ gunichar wc)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->password_char != wc)
+ {
+ priv->password_char = wc;
+
+ clutter_text_dirty_cache (self);
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "password-char");
+ }
+}
+
+/**
+ * clutter_text_get_password_char:
+ * @self: a #ClutterText
+ *
+ * Retrieves the character to use in place of the actual text
+ * as set by clutter_text_set_password_char().
+ *
+ * Return value: a Unicode character or 0 if the password
+ * character is not set
+ *
+ * Since: 1.0
+ */
+gunichar
+clutter_text_get_password_char (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
+
+ return self->priv->password_char;
+}
+
+/**
+ * clutter_text_set_max_length:
+ * @self: a #ClutterText
+ * @max: the maximum number of characters allowed in the text actor; 0
+ * to disable or -1 to set the length of the current string
+ *
+ * Sets the maximum allowed length of the contents of the actor. If the
+ * current contents are longer than the given length, then they will be
+ * truncated to fit.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_max_length (ClutterText *self,
+ gint max)
+{
+ ClutterTextPrivate *priv;
+ gchar *new = NULL;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->max_length != max)
+ {
+ if (max < 0)
+ max = priv->n_chars;
+
+ priv->max_length = max;
+
+ new = g_strdup (priv->text);
+ clutter_text_set_text (self, new);
+ g_free (new);
+
+ g_object_notify (G_OBJECT (self), "max-length");
+ }
+}
+
+/**
+ * clutter_text_get_max_length:
+ * @self: a #ClutterText
+ *
+ * Gets the maximum length of text that can be set into a text actor.
+ *
+ * See clutter_text_set_max_length().
+ *
+ * Return value: the maximum number of characters.
+ *
+ * Since: 1.0
+ */
+gint
+clutter_text_get_max_length (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
+
+ return self->priv->max_length;
+}
+
+/**
+ * clutter_text_insert_unichar:
+ * @self: a #ClutterText
+ * @wc: a Unicode character
+ *
+ * Inserts @wc at the current cursor position of a
+ * #ClutterText actor.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_insert_unichar (ClutterText *self,
+ gunichar wc)
+{
+ ClutterTextPrivate *priv;
+ GString *new = NULL;
+ glong pos;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+ g_return_if_fail (g_unichar_validate (wc));
+
+ if (wc == 0)
+ return;
+
+ priv = self->priv;
+
+ new = g_string_new (priv->text);
+
+ if (priv->text)
+ pos = offset_to_bytes (priv->text, priv->position);
+ else
+ pos = 0;
+
+ new = g_string_insert_unichar (new, pos, wc);
+
+ clutter_text_set_text (self, new->str);
+
+ if (priv->position >= 0)
+ {
+ clutter_text_set_cursor_position (self, priv->position + 1);
+ clutter_text_set_selection_bound (self, priv->position);
+ }
+
+ g_string_free (new, TRUE);
+}
+
+/**
+ * clutter_text_insert_text:
+ * @self: a #ClutterText
+ * @text: the text to be inserted
+ * @position: the position of the insertion, or -1
+ *
+ * Inserts @text into a #ClutterActor at the given position.
+ *
+ * If @position is a negative number, the text will be appended
+ * at the end of the current contents of the #ClutterText.
+ *
+ * The position is expressed in characters, not in bytes.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_insert_text (ClutterText *self,
+ const gchar *text,
+ gssize position)
+{
+ ClutterTextPrivate *priv;
+ GString *new = NULL;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+ g_return_if_fail (text != NULL);
+
+ priv = self->priv;
+
+ new = g_string_new (priv->text);
+ new = g_string_insert (new, position, text);
+
+ clutter_text_set_text (self, new->str);
+
+ g_string_free (new, TRUE);
+}
+
+/**
+ * clutter_text_delete_text:
+ * @self: a #ClutterText
+ * @start_pos: starting position
+ * @end_pos: ending position
+ *
+ * Deletes the text inside a #ClutterText actor between @start_pos
+ * and @end_pos.
+ *
+ * The starting and ending positions are expressed in characters,
+ * not in bytes.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_delete_text (ClutterText *self,
+ gssize start_pos,
+ gssize end_pos)
+{
+ ClutterTextPrivate *priv;
+ GString *new = NULL;
+ gint start_bytes;
+ gint end_bytes;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (!priv->text)
+ return;
+
+ if (start_pos == 0)
+ start_bytes = 0;
+ else
+ start_bytes = offset_to_bytes (priv->text, start_pos);
+
+ if (end_pos == -1)
+ end_bytes = offset_to_bytes (priv->text, priv->n_chars);
+ else
+ end_bytes = offset_to_bytes (priv->text, end_pos);
+
+ new = g_string_new (priv->text);
+ new = g_string_erase (new, start_bytes, end_bytes - start_bytes);
+
+ clutter_text_set_text (self, new->str);
+
+ g_string_free (new, TRUE);
+}
+
+/**
+ * clutter_text_delete_chars:
+ * @self: a #ClutterText
+ * @n_chars: the number of characters to delete
+ *
+ * Deletes @n_chars inside a #ClutterText actor, starting from the
+ * current cursor position.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_delete_chars (ClutterText *self,
+ guint n_chars)
+{
+ ClutterTextPrivate *priv;
+ GString *new = NULL;
+ gint len;
+ gint pos;
+ gint num_pos;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (!priv->text)
+ return;
+
+ len = priv->n_chars;
+ new = g_string_new (priv->text);
+
+ if (priv->position == -1)
+ {
+ num_pos = offset_to_bytes (priv->text, priv->n_chars - n_chars);
+ new = g_string_erase (new, num_pos, -1);
+ }
+ else
+ {
+ pos = offset_to_bytes (priv->text, priv->position - n_chars);
+ num_pos = offset_to_bytes (priv->text, priv->position);
+ new = g_string_erase (new, pos, num_pos - pos);
+ }
+
+ clutter_text_set_text (self, new->str);
+
+ if (priv->position > 0)
+ clutter_text_set_cursor_position (self, priv->position - n_chars);
+
+ g_string_free (new, TRUE);
+
+ g_object_notify (G_OBJECT (self), "text");
+}
+
+/**
+ * clutter_text_get_chars:
+ * @self: a #ClutterText
+ * @start_pos: start of text, in characters
+ * @end_pos: end of text, in characters
+ *
+ * Retrieves the contents of the #ClutterText actor between
+ * @start_pos and @end_pos.
+ *
+ * The positions are specified in characters, not in bytes.
+ *
+ * Return value: a newly allocated string with the contents of
+ * the text actor between the specified positions. Use g_free()
+ * to free the resources when done
+ *
+ * Since: 1.0
+ */
+gchar *
+clutter_text_get_chars (ClutterText *self,
+ gssize start_pos,
+ gssize end_pos)
+{
+ ClutterTextPrivate *priv;
+ gint start_index, end_index;
+
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
+
+ priv = self->priv;
+
+ if (end_pos < 0)
+ end_pos = priv->n_chars;
+
+ start_pos = MIN (priv->n_chars, start_pos);
+ end_pos = MIN (priv->n_chars, end_pos);
+
+ start_index = g_utf8_offset_to_pointer (priv->text, start_pos)
+ - priv->text;
+ end_index = g_utf8_offset_to_pointer (priv->text, end_pos)
+ - priv->text;
+
+ return g_strndup (priv->text + start_index, end_index - start_index);
+}
+
+/**
+ * clutter_text_set_single_line_mode:
+ * @self: a #ClutterText
+ * @single_line: whether to enable single line mode
+ *
+ * Sets whether a #ClutterText actor should be in single line mode
+ * or not.
+ *
+ * A text actor in single line mode will not wrap text and will clip
+ * the the visible area to the predefined size. The contents of the
+ * text actor will scroll to display the end of the text if its length
+ * is bigger than the allocated width.
+ *
+ * When setting the single line mode the #ClutterText:activatable
+ * property is also set as a side effect. Instead of entering a new
+ * line character, the text actor will emit the #ClutterText::activate
+ * signal.
+ *
+ * Since: 1.0
+ */
+void
+clutter_text_set_single_line_mode (ClutterText *self,
+ gboolean single_line)
+{
+ ClutterTextPrivate *priv;
+
+ g_return_if_fail (CLUTTER_IS_TEXT (self));
+
+ priv = self->priv;
+
+ if (priv->single_line_mode != single_line)
+ {
+ g_object_freeze_notify (G_OBJECT (self));
+
+ priv->single_line_mode = single_line;
+
+ if (priv->single_line_mode)
+ {
+ priv->activatable = TRUE;
+
+ g_object_notify (G_OBJECT (self), "activatable");
+ }
+
+ clutter_text_dirty_cache (self);
+ clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
+
+ g_object_notify (G_OBJECT (self), "single-line-mode");
+
+ g_object_thaw_notify (G_OBJECT (self));
+ }
+}
+
+/**
+ * clutter_text_get_single_line_mode:
+ * @self: a #ClutterText
+ *
+ * Retrieves whether the #ClutterText actor is in single line mode.
+ *
+ * Return value: %TRUE if the #ClutterText actor is in single line mode
+ *
+ * Since: 1.0
+ */
+gboolean
+clutter_text_get_single_line_mode (ClutterText *self)
+{
+ g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
+
+ return self->priv->single_line_mode;
+}
diff --git a/clutter/clutter-text.h b/clutter/clutter-text.h
new file mode 100644
index 000000000..2dc4bfa04
--- /dev/null
+++ b/clutter/clutter-text.h
@@ -0,0 +1,198 @@
+/*
+ * Clutter.
+ *
+ * An OpenGL based 'interactive canvas' library.
+ *
+ * Copyright (C) 2008 Intel Corporation.
+ *
+ * Authored By: Øyvind Kolås
+ * Emmanuele Bassi
+ *
+ * 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, see .
+ */
+
+#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only can be included directly."
+#endif
+
+#ifndef __CLUTTER_TEXT_H__
+#define __CLUTTER_TEXT_H__
+
+#include
+#include
+
+G_BEGIN_DECLS
+
+#define CLUTTER_TYPE_TEXT (clutter_text_get_type ())
+#define CLUTTER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TEXT, ClutterText))
+#define CLUTTER_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_TEXT, ClutterTextClass))
+#define CLUTTER_IS_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_TEXT))
+#define CLUTTER_IS_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_TEXT))
+#define CLUTTER_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_TEXT, ClutterTextClass))
+
+typedef struct _ClutterText ClutterText;
+typedef struct _ClutterTextPrivate ClutterTextPrivate;
+typedef struct _ClutterTextClass ClutterTextClass;
+
+/**
+ * ClutterText:
+ *
+ * The #ClutterText struct contains only private data.
+ *
+ * Since: 1.0
+ */
+struct _ClutterText
+{
+ /*< private >*/
+ ClutterActor parent_instance;
+
+ ClutterTextPrivate *priv;
+};
+
+/**
+ * ClutterTextClass:
+ * @text_changed: class handler for the #ClutterText::text-changed signal
+ * @activate: class handler for the #ClutterText::activate signal
+ * @cursor_event: class handler for the #ClutterText::cursor_event signal
+ *
+ * The #ClutterTextClass struct contains only private data.
+ *
+ * Since: 1.0
+ */
+struct _ClutterTextClass
+{
+ /*< private >*/
+ ClutterActorClass parent_class;
+
+ /*< public >*/
+ /* signals, not vfuncs */
+ void (* text_changed) (ClutterText *self);
+ void (* activate) (ClutterText *self);
+ void (* cursor_event) (ClutterText *self,
+ const ClutterGeometry *geometry);
+
+ /*< private >*/
+ /* padding for future expansion */
+ void (* _clutter_reserved1) (void);
+ void (* _clutter_reserved2) (void);
+ void (* _clutter_reserved3) (void);
+ void (* _clutter_reserved4) (void);
+ void (* _clutter_reserved5) (void);
+ void (* _clutter_reserved6) (void);
+ void (* _clutter_reserved7) (void);
+ void (* _clutter_reserved8) (void);
+};
+
+GType clutter_text_get_type (void) G_GNUC_CONST;
+
+ClutterActor * clutter_text_new (void);
+ClutterActor * clutter_text_new_full (const gchar *font_name,
+ const gchar *text,
+ const ClutterColor *color);
+ClutterActor * clutter_text_new_with_text (const gchar *font_name,
+ const gchar *text);
+
+G_CONST_RETURN gchar *clutter_text_get_text (ClutterText *self);
+void clutter_text_set_text (ClutterText *self,
+ const gchar *text);
+PangoLayout * clutter_text_get_layout (ClutterText *self);
+void clutter_text_set_color (ClutterText *self,
+ const ClutterColor *color);
+void clutter_text_get_color (ClutterText *self,
+ ClutterColor *color);
+void clutter_text_set_font_name (ClutterText *self,
+ const gchar *font_name);
+G_CONST_RETURN gchar *clutter_text_get_font_name (ClutterText *self);
+
+void clutter_text_set_ellipsize (ClutterText *self,
+ PangoEllipsizeMode mode);
+PangoEllipsizeMode clutter_text_get_ellipsize (ClutterText *self);
+void clutter_text_set_line_wrap (ClutterText *self,
+ gboolean line_wrap);
+gboolean clutter_text_get_line_wrap (ClutterText *self);
+void clutter_text_set_line_wrap_mode (ClutterText *self,
+ PangoWrapMode wrap_mode);
+PangoWrapMode clutter_text_get_line_wrap_mode (ClutterText *self);
+PangoLayout * clutter_text_get_layout (ClutterText *self);
+void clutter_text_set_attributes (ClutterText *self,
+ PangoAttrList *attrs);
+PangoAttrList * clutter_text_get_attributes (ClutterText *self);
+void clutter_text_set_use_markup (ClutterText *self,
+ gboolean setting);
+gboolean clutter_text_get_use_markup (ClutterText *self);
+void clutter_text_set_alignment (ClutterText *self,
+ PangoAlignment alignment);
+PangoAlignment clutter_text_get_alignment (ClutterText *self);
+void clutter_text_set_justify (ClutterText *self,
+ gboolean justify);
+gboolean clutter_text_get_justify (ClutterText *self);
+
+void clutter_text_insert_unichar (ClutterText *self,
+ gunichar wc);
+void clutter_text_delete_chars (ClutterText *self,
+ guint n_chars);
+void clutter_text_insert_text (ClutterText *self,
+ const gchar *text,
+ gssize position);
+void clutter_text_delete_text (ClutterText *self,
+ gssize start_pos,
+ gssize end_pos);
+gchar * clutter_text_get_chars (ClutterText *self,
+ gssize start_pos,
+ gssize end_pos);
+void clutter_text_set_editable (ClutterText *self,
+ gboolean editable);
+gboolean clutter_text_get_editable (ClutterText *self);
+void clutter_text_set_activatable (ClutterText *self,
+ gboolean activatable);
+gboolean clutter_text_get_activatable (ClutterText *self);
+
+gint clutter_text_get_cursor_position (ClutterText *self);
+void clutter_text_set_cursor_position (ClutterText *self,
+ gint position);
+void clutter_text_set_cursor_visible (ClutterText *self,
+ gboolean cursor_visible);
+gboolean clutter_text_get_cursor_visible (ClutterText *self);
+void clutter_text_set_cursor_color (ClutterText *self,
+ const ClutterColor *color);
+void clutter_text_get_cursor_color (ClutterText *self,
+ ClutterColor *color);
+void clutter_text_set_cursor_size (ClutterText *self,
+ gint size);
+guint clutter_text_get_cursor_size (ClutterText *self);
+void clutter_text_set_selectable (ClutterText *self,
+ gboolean selectable);
+gboolean clutter_text_get_selectable (ClutterText *self);
+void clutter_text_set_selection_bound (ClutterText *self,
+ gint selection_bound);
+gint clutter_text_get_selection_bound (ClutterText *self);
+void clutter_text_set_selection (ClutterText *self,
+ gssize start_pos,
+ gssize end_pos);
+gchar * clutter_text_get_selection (ClutterText *self);
+void clutter_text_set_password_char (ClutterText *self,
+ gunichar wc);
+gunichar clutter_text_get_password_char (ClutterText *self);
+void clutter_text_set_max_length (ClutterText *self,
+ gint max);
+gint clutter_text_get_max_length (ClutterText *self);
+void clutter_text_set_single_line_mode (ClutterText *self,
+ gboolean single_line);
+gboolean clutter_text_get_single_line_mode (ClutterText *self);
+
+gboolean clutter_text_activate (ClutterText *self);
+
+G_END_DECLS
+
+#endif /* __CLUTTER_TEXT_H__ */
diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c
index dd95fc0a1..086a5134c 100644
--- a/clutter/clutter-texture.c
+++ b/clutter/clutter-texture.c
@@ -252,8 +252,8 @@ clutter_texture_realize (ClutterActor *actor)
if (priv->texture != COGL_INVALID_HANDLE)
cogl_texture_unref (priv->texture);
- priv->texture
- = cogl_texture_new_with_size
+ priv->texture
+ = cogl_texture_new_with_size
(priv->width,
priv->height,
priv->no_slice ? -1 : priv->max_tile_waste,
@@ -376,12 +376,12 @@ clutter_texture_get_preferred_height (ClutterActor *self,
{
/* Set the natural height so as to preserve the aspect ratio */
ClutterFixed ratio, width;
-
+
ratio = COGL_FIXED_DIV (COGL_FIXED_FROM_INT (priv->height),
COGL_FIXED_FROM_INT (priv->width));
width = CLUTTER_UNITS_TO_FIXED (for_width);
-
+
*natural_height_p =
CLUTTER_UNITS_FROM_FIXED (COGL_FIXED_MUL (ratio, width));
}
@@ -417,7 +417,8 @@ clutter_texture_set_fbo_projection (ClutterActor *self)
ClutterTexturePrivate *priv = CLUTTER_TEXTURE (self)->priv;
ClutterVertex verts[4];
ClutterFixed viewport[4];
- ClutterFixed x_min, x_max, y_min, y_max;
+ ClutterUnit x_min, x_max, y_min, y_max;
+ ClutterFixed tx_min, tx_max, ty_min, ty_max;
ClutterPerspective perspective;
ClutterStage *stage;
ClutterFixed tan_angle, near_size;
@@ -450,21 +451,26 @@ clutter_texture_set_fbo_projection (ClutterActor *self)
/* Convert the coordinates back to [-1,1] range */
cogl_get_viewport (viewport);
- x_min = COGL_FIXED_DIV (x_min, viewport[2]) * 2 - COGL_FIXED_1;
- x_max = COGL_FIXED_DIV (x_max, viewport[2]) * 2 - COGL_FIXED_1;
- y_min = COGL_FIXED_DIV (y_min, viewport[3]) * 2 - COGL_FIXED_1;
- y_max = COGL_FIXED_DIV (y_max, viewport[3]) * 2 - COGL_FIXED_1;
+
+ tx_min = COGL_FIXED_DIV (CLUTTER_UNITS_TO_FIXED (x_min), viewport[2])
+ * 2 - COGL_FIXED_1;
+ tx_max = COGL_FIXED_DIV (CLUTTER_UNITS_TO_FIXED (x_max), viewport[2])
+ * 2 - COGL_FIXED_1;
+ ty_min = COGL_FIXED_DIV (CLUTTER_UNITS_TO_FIXED (y_min), viewport[3])
+ * 2 - COGL_FIXED_1;
+ ty_max = COGL_FIXED_DIV (CLUTTER_UNITS_TO_FIXED (y_max), viewport[3])
+ * 2 - COGL_FIXED_1;
/* Set up a projection matrix so that the actor will be projected as
if it was drawn at its original location */
- tan_angle = clutter_tani (CLUTTER_ANGLE_FROM_DEGX (perspective.fovy / 2));
+ tan_angle = cogl_angle_tan (COGL_ANGLE_FROM_DEGX (perspective.fovy / 2));
near_size = COGL_FIXED_MUL (perspective.z_near, tan_angle);
- cogl_frustum (COGL_FIXED_MUL (x_min, near_size),
- COGL_FIXED_MUL (x_max, near_size),
- COGL_FIXED_MUL (-y_min, near_size),
- COGL_FIXED_MUL (-y_max, near_size),
- perspective.z_near, perspective.z_far);
+ cogl_frustum (COGL_FIXED_MUL (tx_min, near_size),
+ COGL_FIXED_MUL (tx_max, near_size),
+ COGL_FIXED_MUL (-ty_min, near_size),
+ COGL_FIXED_MUL (-ty_max, near_size),
+ perspective.z_near, perspective.z_far);
}
static void
@@ -544,8 +550,10 @@ clutter_texture_paint (ClutterActor *self)
/* Restore the perspective matrix using cogl_perspective so that
the inverse matrix will be right */
- cogl_perspective (perspective.fovy, perspective.aspect,
- perspective.z_near, perspective.z_far);
+ cogl_perspective (perspective.fovy,
+ perspective.aspect,
+ perspective.z_near,
+ perspective.z_far);
/* If there is a shader on top of the shader stack, turn it back on. */
if (shader)
@@ -588,9 +596,9 @@ clutter_texture_paint (ClutterActor *self)
/* Paint will have translated us */
cogl_texture_rectangle (priv->texture, 0, 0,
- COGL_FIXED_FROM_INT (x_2 - x_1),
- COGL_FIXED_FROM_INT (y_2 - y_1),
- 0, 0, t_w, t_h);
+ COGL_FIXED_FROM_INT (x_2 - x_1),
+ COGL_FIXED_FROM_INT (y_2 - y_1),
+ 0, 0, t_w, t_h);
}
static void
@@ -938,7 +946,7 @@ clutter_scriptable_iface_init (ClutterScriptableIface *iface)
parent_scriptable_iface = g_type_interface_peek_parent (iface);
if (!parent_scriptable_iface)
- parent_scriptable_iface = g_type_default_interface_peek
+ parent_scriptable_iface = g_type_default_interface_peek
(CLUTTER_TYPE_SCRIPTABLE);
iface->set_custom_property = clutter_texture_set_custom_property;
@@ -1028,7 +1036,7 @@ clutter_texture_load_from_local_data (ClutterTexture *texture)
priv->local_data_rowstride,
priv->local_data_has_alpha ? 4: 3,
0, NULL);
-
+
g_free (priv->local_data);
priv->local_data = NULL;
}
@@ -1136,7 +1144,7 @@ clutter_texture_set_from_data (ClutterTexture *texture,
priv = texture->priv;
- if ((new_texture = cogl_texture_new_from_data
+ if ((new_texture = cogl_texture_new_from_data
(width, height,
priv->no_slice ? -1 : priv->max_tile_waste,
priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH,
@@ -1171,7 +1179,7 @@ clutter_texture_set_from_data (ClutterTexture *texture,
* @width: Width in pixels of image data.
* @height: Height in pixels of image data
* @rowstride: Distance in bytes between row starts.
- * @bpp: bytes per pixel (Currently only 3 and 4 supported,
+ * @bpp: bytes per pixel (Currently only 3 and 4 supported,
* depending on @has_alpha)
* @flags: #ClutterTextureFlags
* @error: return location for a #GError, or %NULL.
@@ -1318,7 +1326,7 @@ clutter_texture_set_from_file (ClutterTexture *texture,
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- if ((new_texture = cogl_texture_new_from_file
+ if ((new_texture = cogl_texture_new_from_file
(filename,
priv->no_slice ? -1 : priv->max_tile_waste,
priv->filter_quality == CLUTTER_TEXTURE_QUALITY_HIGH,
@@ -1577,7 +1585,7 @@ clutter_texture_get_base_size (ClutterTexture *texture,
* @width: Width in pixels of region to update.
* @height: Height in pixels of region to update.
* @rowstride: Distance in bytes between row starts on source buffer.
- * @bpp: bytes per pixel (Currently only 3 and 4 supported,
+ * @bpp: bytes per pixel (Currently only 3 and 4 supported,
* depending on @has_alpha)
* @flags: #ClutterTextureFlags
* @error: return location for a #GError, or %NULL
@@ -1736,7 +1744,7 @@ on_fbo_parent_change (ClutterActor *actor,
*
* Note this function is intented as a utility call for uniformly applying
* shaders to groups and other potential visual effects. It requires that
- * the %CLUTTER_FEATURE_OFFSCREEN feature is supported by the current backend
+ * the %CLUTTER_FEATURE_OFFSCREEN feature is supported by the current backend
* and the target system.
*
* Some tips on usage:
@@ -1829,7 +1837,7 @@ clutter_texture_new_from_actor (ClutterActor *actor)
return NULL;
/* Hopefully now were good.. */
- texture = g_object_new (CLUTTER_TYPE_TEXTURE,
+ texture = g_object_new (CLUTTER_TYPE_TEXTURE,
"disable-slicing", TRUE,
NULL);
diff --git a/clutter/clutter-texture.h b/clutter/clutter-texture.h
index 84f6889b8..e15f798b1 100644
--- a/clutter/clutter-texture.h
+++ b/clutter/clutter-texture.h
@@ -80,8 +80,8 @@ struct _ClutterTextureClass
{
ClutterActorClass parent_class;
- void (*size_change) (ClutterTexture *texture,
- gint width,
+ void (*size_change) (ClutterTexture *texture,
+ gint width,
gint height);
void (*pixbuf_change) (ClutterTexture *texture);
diff --git a/clutter/clutter.h b/clutter/clutter.h
index 15208ce17..817dbef6c 100644
--- a/clutter/clutter.h
+++ b/clutter/clutter.h
@@ -47,14 +47,12 @@
#include "clutter-container.h"
#include "clutter-deprecated.h"
#include "clutter-effect.h"
-#include "clutter-entry.h"
#include "clutter-event.h"
#include "clutter-feature.h"
#include "clutter-frame-source.h"
#include "clutter-group.h"
#include "clutter-interval.h"
#include "clutter-keysyms.h"
-#include "clutter-label.h"
#include "clutter-list-model.h"
#include "clutter-main.h"
#include "clutter-media.h"
@@ -69,6 +67,7 @@
#include "clutter-stage.h"
#include "clutter-stage-manager.h"
#include "clutter-texture.h"
+#include "clutter-text.h"
#include "clutter-timeline.h"
#include "clutter-timeout-pool.h"
#include "clutter-types.h"
diff --git a/clutter/cogl/cogl-texture.h b/clutter/cogl/cogl-texture.h
index 117a12b14..3ca0d8137 100644
--- a/clutter/cogl/cogl-texture.h
+++ b/clutter/cogl/cogl-texture.h
@@ -148,7 +148,7 @@ gboolean cogl_is_texture (CoglHandle handle);
/**
* cogl_texture_get_width:
* @handle: a #CoglHandle for a texture.
- *
+ *
* Query the width of a cogl texture.
*
* Returns: the width of the GPU side texture in pixels:
@@ -158,7 +158,7 @@ guint cogl_texture_get_width (CoglHandle handle);
/**
* cogl_texture_get_height:
* @handle: a #CoglHandle for a texture.
- *
+ *
* Query the height of a cogl texture.
*
* Returns: the height of the GPU side texture in pixels:
@@ -168,7 +168,7 @@ guint cogl_texture_get_height (CoglHandle handle);
/**
* cogl_texture_get_format:
* @handle: a #CoglHandle for a texture.
- *
+ *
* Query the #CoglPixelFormat of a cogl texture.
*
* Returns: the #CoglPixelFormat of the GPU side texture.
@@ -179,7 +179,7 @@ CoglPixelFormat cogl_texture_get_format (CoglHandle handle);
/**
* cogl_texture_get_rowstride:
* @handle: a #CoglHandle for a texture.
- *
+ *
* Query the rowstride of a cogl texture.
*
* Returns: the offset in bytes between each consequetive row of pixels.
@@ -189,7 +189,7 @@ guint cogl_texture_get_rowstride (CoglHandle handle);
/**
* cogl_texture_get_max_waste:
* @handle: a #CoglHandle for a texture.
- *
+ *
* Query the maximum wasted (unused) pixels in one dimension of a GPU side
* texture.
*
@@ -200,7 +200,7 @@ gint cogl_texture_get_max_waste (CoglHandle handle);
/**
* cogl_texture_get_min_filter:
* @handle: a #CoglHandle for a texture.
- *
+ *
* Query the currently set downscaling filter for a cogl texture.
*
* Returns: the current downscaling filter for a cogl texture.
@@ -210,7 +210,7 @@ COGLenum cogl_texture_get_min_filter (CoglHandle handle);
/**
* cogl_texture_get_mag_filter:
* @handle: a #CoglHandle for a texture.
- *
+ *
* Query the currently set downscaling filter for a cogl texture.
*
* Returns: the current downscaling filter for a cogl texture.
@@ -220,7 +220,7 @@ COGLenum cogl_texture_get_mag_filter (CoglHandle handle);
/**
* cogl_texture_is_sliced:
* @handle: a #CoglHandle for a texture.
- *
+ *
* Query if a texture is sliced (stored as multiple GPU side tecture
* objects).
*
@@ -235,7 +235,7 @@ gboolean cogl_texture_is_sliced (CoglHandle handle);
* @out_gl_handle: pointer to return location for the textures GL handle, or
* NULL.
* @out_gl_target: pointer to return location for the GL target type, or NULL.
- *
+ *
* Query the GL handles for a GPU side texture through it's #CoglHandle,
* if the texture is spliced the data for the first sub texture will be
* queried.
@@ -255,7 +255,7 @@ gboolean cogl_texture_get_gl_texture (CoglHandle handle,
* specified.
* @data: memory location to write contents of buffer, or %NULL if we're
* only querying the data size through the return value.
- *
+ *
* Copy the pixel data from a cogl texture to system memory.
*
* Returns: the size of the texture data in bytes (or 0 if the texture
@@ -271,7 +271,7 @@ gint cogl_texture_get_data (CoglHandle handle,
* @handle: a #CoglHandle.
* @min_filter: the filter used when scaling the texture down.
* @mag_filter: the filter used when magnifying the texture.
- *
+ *
* Changes the decimation and interpolation filters used when the texture is
* drawn at other scales than 100%.
*/
@@ -297,7 +297,7 @@ void cogl_texture_set_filters (CoglHandle handle,
* @data: the actual pixel data.
*
* Sets the pixels in a rectangular subregion of @handle from an in-memory
- * buffer containing pixel data.
+ * buffer containing pixel data.
*
* Returns: %TRUE if the subregion upload was successful, otherwise %FALSE.
*/
@@ -385,6 +385,29 @@ void cogl_texture_polygon (CoglHandle handle,
CoglTextureVertex *vertices,
gboolean use_color);
+/**
+ * cogl_texture_multiple_rectangles:
+ * @handle: a @CoglHandle.
+ * @verts: an array of vertices
+ * @n_rects: number of rectangles to draw
+ *
+ * Draws a series of rectangles in the same way that
+ * cogl_texture_rectangle() does. In some situations it can give a
+ * significant performance boost to use this function rather than
+ * calling cogl_texture_rectangle() separately for each rectangle.
+ *
+ * @verts should point to an array of #CoglFixeds with
+ * @n_rects * 8 elements. Each group of 8 values corresponds to the
+ * parameters x1, y1, x2, y2, tx1, ty1, tx2 and ty2 and have the same
+ * meaning as in cogl_texture_rectangle().
+ *
+ * Since: 1.0
+ */
+void cogl_texture_multiple_rectangles
+ (CoglHandle handle,
+ const CoglFixed *verts,
+ guint n_rects);
+
G_END_DECLS
#endif /* __COGL_TEXTURE_H__ */
diff --git a/clutter/cogl/gl/cogl-context.c b/clutter/cogl/gl/cogl-context.c
index d75086fbc..e2421f4ff 100644
--- a/clutter/cogl/gl/cogl-context.c
+++ b/clutter/cogl/gl/cogl-context.c
@@ -41,27 +41,29 @@ cogl_create_context ()
{
if (_context != NULL)
return FALSE;
-
+
/* Allocate context memory */
_context = (CoglContext*) g_malloc (sizeof (CoglContext));
-
+
/* Init default values */
_context->feature_flags = 0;
_context->features_cached = FALSE;
-
+
_context->enable_flags = 0;
_context->color_alpha = 255;
-
+
_context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
_context->last_path = 0;
-
+
_context->texture_handles = NULL;
- _context->texture_vertices_size = 0;
- _context->texture_vertices = NULL;
-
+ _context->texture_vertices = g_array_new (FALSE, FALSE,
+ sizeof (CoglTextureGLVertex));
+ _context->texture_indices = g_array_new (FALSE, FALSE,
+ sizeof (GLushort));
+
_context->fbo_handles = NULL;
_context->draw_buffer = COGL_WINDOW_BUFFER;
-
+
_context->blend_src_factor = CGL_SRC_ALPHA;
_context->blend_dst_factor = CGL_ONE_MINUS_SRC_ALPHA;
@@ -70,7 +72,7 @@ cogl_create_context ()
_context->program_handles = NULL;
_context->mesh_handles = NULL;
-
+
_context->pf_glGenRenderbuffersEXT = NULL;
_context->pf_glBindRenderbufferEXT = NULL;
_context->pf_glRenderbufferStorageEXT = NULL;
@@ -82,7 +84,7 @@ cogl_create_context ()
_context->pf_glDeleteFramebuffersEXT = NULL;
_context->pf_glBlitFramebufferEXT = NULL;
_context->pf_glRenderbufferStorageMultisampleEXT = NULL;
-
+
_context->pf_glCreateProgramObjectARB = NULL;
_context->pf_glCreateShaderObjectARB = NULL;
_context->pf_glShaderSourceARB = NULL;
@@ -115,7 +117,7 @@ cogl_create_context ()
_context->pf_glUniformMatrix4fvARB = NULL;
_context->pf_glDrawRangeElements = NULL;
-
+
/* Init OpenGL state */
GE( glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) );
GE( glColorMask (TRUE, TRUE, TRUE, FALSE) );
@@ -124,7 +126,7 @@ cogl_create_context ()
/* Initialise the clip stack */
_cogl_clip_stack_state_init ();
-
+
return TRUE;
}
@@ -147,7 +149,12 @@ cogl_destroy_context ()
g_array_free (_context->shader_handles, TRUE);
if (_context->program_handles)
g_array_free (_context->program_handles, TRUE);
-
+
+ if (_context->texture_vertices)
+ g_array_free (_context->texture_vertices, TRUE);
+ if (_context->texture_indices)
+ g_array_free (_context->texture_indices, TRUE);
+
g_free (_context);
}
@@ -157,6 +164,6 @@ _cogl_context_get_default ()
/* Create if doesn't exist yet */
if (_context == NULL)
cogl_create_context ();
-
+
return _context;
}
diff --git a/clutter/cogl/gl/cogl-context.h b/clutter/cogl/gl/cogl-context.h
index 8a2fc877d..d49330763 100644
--- a/clutter/cogl/gl/cogl-context.h
+++ b/clutter/cogl/gl/cogl-context.h
@@ -41,7 +41,7 @@ typedef struct
/* Features cache */
CoglFeatureFlags feature_flags;
gboolean features_cached;
-
+
/* Enable cache */
gulong enable_flags;
guint8 color_alpha;
@@ -49,7 +49,7 @@ typedef struct
COGLenum blend_dst_factor;
gboolean enable_backface_culling;
-
+
/* Primitives */
CoglFixedVec2 path_start;
CoglFixedVec2 path_pen;
@@ -60,12 +60,18 @@ typedef struct
/* Cache of inverse projection matrix */
GLfloat inverse_projection[16];
-
+
/* Textures */
GArray *texture_handles;
- CoglTextureGLVertex *texture_vertices;
- gulong texture_vertices_size;
-
+ GArray *texture_vertices;
+ GArray *texture_indices;
+ /* The gl texture number that the above vertices apply to. This to
+ detect when a different slice is encountered so that the vertices
+ can be flushed */
+ GLuint texture_current;
+ GLenum texture_target;
+ GLenum texture_wrap_mode;
+
/* Framebuffer objects */
GArray *fbo_handles;
CoglBufferTarget draw_buffer;
@@ -78,10 +84,10 @@ typedef struct
/* Clip stack */
CoglClipStackState clip;
-
+
/* Mesh */
GArray *mesh_handles;
-
+
/* Relying on glext.h to define these */
COGL_PFNGLGENRENDERBUFFERSEXTPROC pf_glGenRenderbuffersEXT;
COGL_PFNGLDELETERENDERBUFFERSEXTPROC pf_glDeleteRenderbuffersEXT;
@@ -95,7 +101,7 @@ typedef struct
COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC pf_glDeleteFramebuffersEXT;
COGL_PFNGLBLITFRAMEBUFFEREXTPROC pf_glBlitFramebufferEXT;
COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC pf_glRenderbufferStorageMultisampleEXT;
-
+
COGL_PFNGLCREATEPROGRAMOBJECTARBPROC pf_glCreateProgramObjectARB;
COGL_PFNGLCREATESHADEROBJECTARBPROC pf_glCreateShaderObjectARB;
COGL_PFNGLSHADERSOURCEARBPROC pf_glShaderSourceARB;
@@ -151,6 +157,6 @@ _cogl_context_get_default ();
CoglContext *ctxvar = _cogl_context_get_default (); \
if (ctxvar == NULL) return retval;
-#define NO_RETVAL
+#define NO_RETVAL
#endif /* __COGL_CONTEXT_H */
diff --git a/clutter/cogl/gl/cogl-texture.c b/clutter/cogl/gl/cogl-texture.c
index 5a202ae6b..a27a8b253 100644
--- a/clutter/cogl/gl/cogl-texture.c
+++ b/clutter/cogl/gl/cogl-texture.c
@@ -76,7 +76,7 @@ _cogl_texture_bitmap_free (CoglTexture *tex)
{
if (tex->bitmap.data != NULL && tex->bitmap_owner)
g_free (tex->bitmap.data);
-
+
tex->bitmap.data = NULL;
tex->bitmap_owner = FALSE;
}
@@ -87,7 +87,7 @@ _cogl_texture_bitmap_swap (CoglTexture *tex,
{
if (tex->bitmap.data != NULL && tex->bitmap_owner)
g_free (tex->bitmap.data);
-
+
tex->bitmap = *new_bitmap;
tex->bitmap_owner = TRUE;
}
@@ -99,11 +99,11 @@ _cogl_span_iter_update (CoglSpanIter *iter)
iter->span = &g_array_index (iter->array,
CoglTexSliceSpan,
iter->index);
-
+
/* Offset next position by span size */
iter->next_pos = iter->pos +
COGL_FIXED_FROM_INT (iter->span->size - iter->span->waste);
-
+
/* Check if span intersects the area to cover */
if (iter->next_pos <= iter->cover_start ||
iter->pos >= iter->cover_end)
@@ -112,15 +112,15 @@ _cogl_span_iter_update (CoglSpanIter *iter)
iter->intersects = FALSE;
return;
}
-
+
iter->intersects = TRUE;
-
+
/* Clip start position to coverage area */
if (iter->pos < iter->cover_start)
iter->intersect_start = iter->cover_start;
else
iter->intersect_start = iter->pos;
-
+
/* Clip end position to coverage area */
if (iter->next_pos > iter->cover_end)
iter->intersect_end = iter->cover_end;
@@ -143,7 +143,7 @@ _cogl_span_iter_begin (CoglSpanIter *iter,
iter->cover_start = cover_start;
iter->cover_end = cover_end;
iter->pos = iter->origin;
-
+
/* Update intersection */
_cogl_span_iter_update (iter);
}
@@ -153,10 +153,10 @@ _cogl_span_iter_next (CoglSpanIter *iter)
{
/* Move current position */
iter->pos = iter->next_pos;
-
+
/* Pick next slice (wrap when last reached) */
iter->index = (iter->index + 1) % iter->array->len;
-
+
/* Update intersection */
_cogl_span_iter_update (iter);
}
@@ -175,10 +175,10 @@ prep_for_gl_pixels_upload (gint pixels_rowstride,
gint pixels_bpp)
{
GE( glPixelStorei (GL_UNPACK_ROW_LENGTH, pixels_rowstride / pixels_bpp) );
-
+
GE( glPixelStorei (GL_UNPACK_SKIP_PIXELS, pixels_src_x) );
GE( glPixelStorei (GL_UNPACK_SKIP_ROWS, pixels_src_y) );
-
+
if (!(pixels_rowstride & 0x7))
GE( glPixelStorei (GL_UNPACK_ALIGNMENT, 8) );
else if (!(pixels_rowstride & 0x3))
@@ -240,7 +240,7 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
gint bpp;
gint x,y;
guchar *waste_buf;
-
+
bpp = _cogl_get_format_bpp (tex->bitmap.format);
waste_buf = _cogl_texture_allocate_waste_buffer (tex);
@@ -249,22 +249,22 @@ _cogl_texture_upload_to_gl (CoglTexture *tex)
for (y = 0; y < tex->slice_y_spans->len; ++y)
{
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y);
-
+
/* Iterate horizontal slices */
for (x = 0; x < tex->slice_x_spans->len; ++x)
{
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
-
+
/* Pick the gl texture object handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
y * tex->slice_x_spans->len + x);
-
+
/* Setup gl alignment to match rowstride and top-left corner */
prep_for_gl_pixels_upload (tex->bitmap.rowstride,
x_span->start,
y_span->start,
bpp);
-
+
/* Upload new image data */
GE( glBindTexture (tex->gl_target, gl_handle) );
@@ -364,27 +364,27 @@ _cogl_texture_download_from_gl (CoglTexture *tex,
gint bpp;
gint x,y;
CoglBitmap slice_bmp;
-
+
bpp = _cogl_get_format_bpp (target_bmp->format);
-
+
/* Iterate vertical slices */
for (y = 0; y < tex->slice_y_spans->len; ++y)
{
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y);
-
+
/* Iterate horizontal slices */
for (x = 0; x < tex->slice_x_spans->len; ++x)
{
/*if (x != 0 || y != 1) continue;*/
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
-
+
/* Pick the gl texture object handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
y * tex->slice_x_spans->len + x);
-
+
/* If there's any waste we need to copy manually
(no glGetTexSubImage) */
-
+
if (y_span->waste != 0 || x_span->waste != 0)
{
/* Setup temp bitmap for slice subregion */
@@ -394,19 +394,19 @@ _cogl_texture_download_from_gl (CoglTexture *tex,
slice_bmp.rowstride = bpp * slice_bmp.width;
slice_bmp.data = (guchar*) g_malloc (slice_bmp.rowstride *
slice_bmp.height);
-
+
/* Setup gl alignment to 0,0 top-left corner */
prep_for_gl_pixels_download (slice_bmp.rowstride);
-
+
/* Download slice image data into temp bmp */
GE( glBindTexture (tex->gl_target, gl_handle) );
-
+
GE (glGetTexImage (tex->gl_target,
0, /* level */
target_gl_format,
target_gl_type,
slice_bmp.data) );
-
+
/* Copy portion of slice from temp to target bmp */
_cogl_bitmap_copy_subregion (&slice_bmp,
target_bmp,
@@ -425,10 +425,10 @@ _cogl_texture_download_from_gl (CoglTexture *tex,
+ y_span->start * target_bmp->rowstride;
prep_for_gl_pixels_download (target_bmp->rowstride);
-
+
/* Download slice image data */
GE( glBindTexture (tex->gl_target, gl_handle) );
-
+
GE( glGetTexImage (tex->gl_target,
0, /* level */
target_gl_format,
@@ -437,7 +437,7 @@ _cogl_texture_download_from_gl (CoglTexture *tex,
}
}
}
-
+
return TRUE;
}
@@ -463,7 +463,7 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
gint inter_w = 0, inter_h = 0;
gint local_x = 0, local_y = 0;
guchar *waste_buf;
-
+
bpp = _cogl_get_format_bpp (source_bmp->format);
waste_buf = _cogl_texture_allocate_waste_buffer (tex);
@@ -473,9 +473,9 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
_cogl_span_iter_begin (&y_iter, tex->slice_y_spans,
0, COGL_FIXED_FROM_INT (dst_y),
COGL_FIXED_FROM_INT (dst_y + height));
-
+
!_cogl_span_iter_end (&y_iter);
-
+
_cogl_span_iter_next (&y_iter),
source_y += inter_h )
{
@@ -494,9 +494,9 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
_cogl_span_iter_begin (&x_iter, tex->slice_x_spans,
0, COGL_FIXED_FROM_INT (dst_x),
COGL_FIXED_FROM_INT (dst_x + width));
-
+
!_cogl_span_iter_end (&x_iter);
-
+
_cogl_span_iter_next (&x_iter),
source_x += inter_w )
{
@@ -515,27 +515,27 @@ _cogl_texture_upload_subregion_to_gl (CoglTexture *tex,
x_iter.intersect_start);
inter_h = COGL_FIXED_TO_INT (y_iter.intersect_end -
y_iter.intersect_start);
-
+
/* Localize intersection top-left corner to slice*/
local_x = COGL_FIXED_TO_INT (x_iter.intersect_start -
x_iter.pos);
local_y = COGL_FIXED_TO_INT (y_iter.intersect_start -
y_iter.pos);
-
+
/* Pick slice GL handle */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
y_iter.index * tex->slice_x_spans->len +
x_iter.index);
-
+
/* Setup gl alignment to match rowstride and top-left corner */
prep_for_gl_pixels_upload (source_bmp->rowstride,
source_x,
source_y,
bpp);
-
+
/* Upload new image data */
GE( glBindTexture (tex->gl_target, gl_handle) );
-
+
GE( glTexSubImage2D (tex->gl_target, 0,
local_x, local_y,
inter_w, inter_h,
@@ -657,12 +657,12 @@ _cogl_rect_slices_for_size (gint size_to_fill,
{
gint n_spans = 0;
CoglTexSliceSpan span;
-
+
/* Init first slice span */
span.start = 0;
span.size = max_span_size;
span.waste = 0;
-
+
/* Repeat until whole area covered */
while (size_to_fill >= span.size)
{
@@ -672,7 +672,7 @@ _cogl_rect_slices_for_size (gint size_to_fill,
size_to_fill -= span.size;
n_spans++;
}
-
+
/* Add one last smaller slice span */
if (size_to_fill > 0)
{
@@ -680,7 +680,7 @@ _cogl_rect_slices_for_size (gint size_to_fill,
if (out_spans) g_array_append_val (out_spans, span);
n_spans++;
}
-
+
return n_spans;
}
@@ -692,15 +692,15 @@ _cogl_pot_slices_for_size (gint size_to_fill,
{
gint n_spans = 0;
CoglTexSliceSpan span;
-
+
/* Init first slice span */
span.start = 0;
span.size = max_span_size;
span.waste = 0;
-
+
/* Fix invalid max_waste */
if (max_waste < 0) max_waste = 0;
-
+
while (TRUE)
{
/* Is the whole area covered? */
@@ -729,7 +729,7 @@ _cogl_pot_slices_for_size (gint size_to_fill,
}
}
}
-
+
/* Can't get here */
return 0;
}
@@ -744,7 +744,7 @@ _cogl_texture_size_supported (GLenum gl_target,
if (gl_target == GL_TEXTURE_2D)
{
/* Proxy texture allows for a quick check for supported size */
-
+
GLint new_width = 0;
GE( glTexImage2D (GL_PROXY_TEXTURE_2D, 0, GL_RGBA,
@@ -788,7 +788,7 @@ _cogl_texture_set_wrap_mode_parameter (CoglTexture *tex,
static gboolean
_cogl_texture_slices_create (CoglTexture *tex)
-{
+{
gint bpp;
gint max_width;
gint max_height;
@@ -800,11 +800,11 @@ _cogl_texture_slices_create (CoglTexture *tex)
CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span;
const GLfloat transparent_color[4] = { 0x00, 0x00, 0x00, 0x00 };
-
+
gint (*slices_for_size) (gint, gint, gint, GArray*);
-
+
bpp = _cogl_get_format_bpp (tex->bitmap.format);
-
+
/* Initialize size of largest slice according to supported features */
if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT))
{
@@ -820,12 +820,12 @@ _cogl_texture_slices_create (CoglTexture *tex)
tex->gl_target = GL_TEXTURE_2D;
slices_for_size = _cogl_pot_slices_for_size;
}
-
+
/* Negative number means no slicing forced by the user */
if (tex->max_waste <= -1)
{
CoglTexSliceSpan span;
-
+
/* Check if size supported else bail out */
if (!_cogl_texture_size_supported (tex->gl_target,
tex->gl_format,
@@ -835,25 +835,25 @@ _cogl_texture_slices_create (CoglTexture *tex)
{
return FALSE;
}
-
+
n_x_slices = 1;
n_y_slices = 1;
-
- /* Init span arrays */
+
+ /* Init span arrays */
tex->slice_x_spans = g_array_sized_new (FALSE, FALSE,
sizeof (CoglTexSliceSpan),
1);
-
+
tex->slice_y_spans = g_array_sized_new (FALSE, FALSE,
sizeof (CoglTexSliceSpan),
1);
-
+
/* Add a single span for width and height */
span.start = 0;
span.size = max_width;
span.waste = max_width - tex->bitmap.width;
g_array_append_val (tex->slice_x_spans, span);
-
+
span.size = max_height;
span.waste = max_height - tex->bitmap.height;
g_array_append_val (tex->slice_y_spans, span);
@@ -872,46 +872,46 @@ _cogl_texture_slices_create (CoglTexture *tex)
max_width /= 2;
else
max_height /= 2;
-
+
if (max_width == 0 || max_height == 0)
return FALSE;
}
-
+
/* Determine the slices required to cover the bitmap area */
n_x_slices = slices_for_size (tex->bitmap.width,
max_width, tex->max_waste,
NULL);
-
+
n_y_slices = slices_for_size (tex->bitmap.height,
max_height, tex->max_waste,
NULL);
-
+
/* Init span arrays with reserved size */
tex->slice_x_spans = g_array_sized_new (FALSE, FALSE,
sizeof (CoglTexSliceSpan),
n_x_slices);
-
+
tex->slice_y_spans = g_array_sized_new (FALSE, FALSE,
sizeof (CoglTexSliceSpan),
n_y_slices);
-
+
/* Fill span arrays with info */
slices_for_size (tex->bitmap.width,
max_width, tex->max_waste,
tex->slice_x_spans);
-
+
slices_for_size (tex->bitmap.height,
max_height, tex->max_waste,
tex->slice_y_spans);
}
-
+
/* Init and resize GL handle array */
n_slices = n_x_slices * n_y_slices;
-
+
tex->slice_gl_handles = g_array_sized_new (FALSE, FALSE,
sizeof (GLuint),
n_slices);
-
+
g_array_set_size (tex->slice_gl_handles, n_slices);
/* Wrap mode not yet set */
@@ -921,19 +921,19 @@ _cogl_texture_slices_create (CoglTexture *tex)
* (some implementations might supported faster
* re-binding between textures inside a set) */
gl_handles = (GLuint*) tex->slice_gl_handles->data;
-
+
GE( glGenTextures (n_slices, gl_handles) );
-
-
+
+
/* Init each GL texture object */
for (y = 0; y < n_y_slices; ++y)
{
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, y);
-
+
for (x = 0; x < n_x_slices; ++x)
{
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, x);
-
+
#if COGL_DEBUG
printf ("CREATE SLICE (%d,%d)\n", x,y);
printf ("size: (%d x %d)\n",
@@ -964,19 +964,19 @@ _cogl_texture_slices_create (CoglTexture *tex)
tex->gl_format, tex->gl_type, 0) );
}
}
-
+
return TRUE;
}
static void
_cogl_texture_slices_free (CoglTexture *tex)
-{
+{
if (tex->slice_x_spans != NULL)
g_array_free (tex->slice_x_spans, TRUE);
-
+
if (tex->slice_y_spans != NULL)
g_array_free (tex->slice_y_spans, TRUE);
-
+
if (tex->slice_gl_handles != NULL)
{
if (tex->is_foreign == FALSE)
@@ -984,7 +984,7 @@ _cogl_texture_slices_free (CoglTexture *tex)
GE( glDeleteTextures (tex->slice_gl_handles->len,
(GLuint*) tex->slice_gl_handles->data) );
}
-
+
g_array_free (tex->slice_gl_handles, TRUE);
}
}
@@ -998,34 +998,34 @@ _cogl_pixel_format_from_gl_internal (GLenum gl_int_format,
is re-matched against cogl when getting or setting
texture image data.
*/
-
+
switch (gl_int_format)
{
case GL_ALPHA: case GL_ALPHA4: case GL_ALPHA8:
case GL_ALPHA12: case GL_ALPHA16:
-
+
*out_format = COGL_PIXEL_FORMAT_A_8;
return TRUE;
-
+
case GL_LUMINANCE: case GL_LUMINANCE4: case GL_LUMINANCE8:
case GL_LUMINANCE12: case GL_LUMINANCE16:
-
+
*out_format = COGL_PIXEL_FORMAT_G_8;
return TRUE;
-
+
case GL_RGB: case GL_RGB4: case GL_RGB5: case GL_RGB8:
case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_R3_G3_B2:
-
+
*out_format = COGL_PIXEL_FORMAT_RGB_888;
return TRUE;
-
+
case GL_RGBA: case GL_RGBA2: case GL_RGBA4: case GL_RGB5_A1:
case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16:
-
+
*out_format = COGL_PIXEL_FORMAT_RGBA_8888;
return TRUE;
}
-
+
return FALSE;
}
@@ -1039,17 +1039,17 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format,
GLenum glintformat = 0;
GLenum glformat = 0;
GLenum gltype = 0;
-
+
/* No premultiplied formats accepted by GL
* (FIXME: latest hardware?) */
-
+
if (format & COGL_PREMULT_BIT)
format = (format & COGL_UNPREMULT_MASK);
-
+
/* Everything else accepted
* (FIXME: check YUV support) */
required_format = format;
-
+
/* Find GL equivalents */
switch (format)
{
@@ -1063,7 +1063,7 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format,
glformat = GL_LUMINANCE;
gltype = GL_UNSIGNED_BYTE;
break;
-
+
case COGL_PIXEL_FORMAT_RGB_888:
glintformat = GL_RGB;
glformat = GL_RGB;
@@ -1084,7 +1084,7 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format,
glformat = GL_BGRA;
gltype = GL_UNSIGNED_BYTE;
break;
-
+
/* The following two types of channel ordering
* have no GL equivalent unless defined using
* system word byte ordering */
@@ -1097,7 +1097,7 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format,
gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
#endif
break;
-
+
case COGL_PIXEL_FORMAT_ABGR_8888:
glintformat = GL_RGBA;
glformat = GL_RGBA;
@@ -1107,7 +1107,7 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format,
gltype = GL_UNSIGNED_INT_8_8_8_8_REV;
#endif
break;
-
+
/* The following three types of channel ordering
* are always defined using system word byte
* ordering (even according to GLES spec) */
@@ -1126,19 +1126,19 @@ _cogl_pixel_format_to_gl (CoglPixelFormat format,
glformat = GL_RGBA;
gltype = GL_UNSIGNED_SHORT_5_5_5_1;
break;
-
+
/* FIXME: check extensions for YUV support */
default:
break;
}
-
+
if (out_glintformat != NULL)
*out_glintformat = glintformat;
if (out_glformat != NULL)
*out_glformat = glformat;
if (out_gltype != NULL)
*out_gltype = gltype;
-
+
return required_format;
}
@@ -1149,7 +1149,7 @@ _cogl_texture_bitmap_prepare (CoglTexture *tex,
CoglBitmap new_bitmap;
CoglPixelFormat new_data_format;
gboolean success;
-
+
/* Was there any internal conversion requested? */
if (internal_format == COGL_PIXEL_FORMAT_ANY)
internal_format = tex->bitmap.format;
@@ -1159,21 +1159,21 @@ _cogl_texture_bitmap_prepare (CoglTexture *tex,
&tex->gl_intformat,
&tex->gl_format,
&tex->gl_type);
-
+
/* Convert to internal format */
if (new_data_format != tex->bitmap.format)
{
success = _cogl_bitmap_convert_and_premult (&tex->bitmap,
&new_bitmap,
new_data_format);
-
+
if (!success)
return FALSE;
-
+
/* Update texture with new data */
_cogl_texture_bitmap_swap (tex, &new_bitmap);
}
-
+
return TRUE;
}
@@ -1197,15 +1197,15 @@ cogl_texture_new_with_size (guint width,
CoglTexture *tex;
gint bpp;
gint rowstride;
-
+
/* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY)
return COGL_INVALID_HANDLE;
-
+
/* Rowstride from width */
bpp = _cogl_get_format_bpp (internal_format);
rowstride = width * bpp;
-
+
/* Init texture with empty bitmap */
tex = (CoglTexture*) g_malloc (sizeof (CoglTexture));
@@ -1214,36 +1214,36 @@ cogl_texture_new_with_size (guint width,
tex->is_foreign = FALSE;
tex->auto_mipmap = auto_mipmap;
-
+
tex->bitmap.width = width;
tex->bitmap.height = height;
tex->bitmap.format = internal_format;
tex->bitmap.rowstride = rowstride;
tex->bitmap.data = NULL;
tex->bitmap_owner = FALSE;
-
+
tex->slice_x_spans = NULL;
tex->slice_y_spans = NULL;
tex->slice_gl_handles = NULL;
-
+
tex->max_waste = max_waste;
tex->min_filter = CGL_NEAREST;
tex->mag_filter = CGL_NEAREST;
-
+
/* Find closest GL format match */
tex->bitmap.format =
_cogl_pixel_format_to_gl (internal_format,
&tex->gl_intformat,
&tex->gl_format,
&tex->gl_type);
-
+
/* Create slices for the given format and size */
if (!_cogl_texture_slices_create (tex))
{
_cogl_texture_free (tex);
return COGL_INVALID_HANDLE;
}
-
+
return _cogl_texture_handle_new (tex);
}
@@ -1259,20 +1259,20 @@ cogl_texture_new_from_data (guint width,
{
CoglTexture *tex;
gint bpp;
-
+
if (format == COGL_PIXEL_FORMAT_ANY)
return COGL_INVALID_HANDLE;
-
+
if (data == NULL)
return COGL_INVALID_HANDLE;
-
+
/* Rowstride from width if not given */
bpp = _cogl_get_format_bpp (format);
if (rowstride == 0) rowstride = width * bpp;
-
+
/* Create new texture and fill with given data */
tex = (CoglTexture*) g_malloc (sizeof (CoglTexture));
-
+
tex->ref_count = 1;
COGL_HANDLE_DEBUG_NEW (texture, tex);
@@ -1285,40 +1285,40 @@ cogl_texture_new_from_data (guint width,
tex->bitmap.format = format;
tex->bitmap.rowstride = rowstride;
tex->bitmap_owner = FALSE;
-
+
tex->slice_x_spans = NULL;
tex->slice_y_spans = NULL;
tex->slice_gl_handles = NULL;
-
+
tex->max_waste = max_waste;
tex->min_filter = CGL_NEAREST;
tex->mag_filter = CGL_NEAREST;
-
+
/* FIXME: If upload fails we should set some kind of
* error flag but still return texture handle (this
* is to keep the behavior equal to _new_from_file;
* see below) */
-
+
if (!_cogl_texture_bitmap_prepare (tex, internal_format))
{
_cogl_texture_free (tex);
return COGL_INVALID_HANDLE;
}
-
+
if (!_cogl_texture_slices_create (tex))
{
_cogl_texture_free (tex);
return COGL_INVALID_HANDLE;
}
-
+
if (!_cogl_texture_upload_to_gl (tex))
{
_cogl_texture_free (tex);
return COGL_INVALID_HANDLE;
}
-
+
_cogl_texture_bitmap_free (tex);
-
+
return _cogl_texture_handle_new (tex);
}
@@ -1331,7 +1331,7 @@ cogl_texture_new_from_file (const gchar *filename,
{
CoglBitmap bmp;
CoglTexture *tex;
-
+
g_return_val_if_fail (error == NULL || *error == NULL, COGL_INVALID_HANDLE);
/* Try loading with imaging backend */
@@ -1346,27 +1346,27 @@ cogl_texture_new_from_file (const gchar *filename,
*error = NULL;
}
}
-
+
/* Create new texture and fill with loaded data */
tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture));
-
+
tex->ref_count = 1;
COGL_HANDLE_DEBUG_NEW (texture, tex);
-
+
tex->is_foreign = FALSE;
tex->auto_mipmap = auto_mipmap;
tex->bitmap = bmp;
tex->bitmap_owner = TRUE;
-
+
tex->slice_x_spans = NULL;
tex->slice_y_spans = NULL;
tex->slice_gl_handles = NULL;
-
+
tex->max_waste = max_waste;
tex->min_filter = CGL_NEAREST;
tex->mag_filter = CGL_NEAREST;
-
+
/* FIXME: If upload fails we should set some kind of
* error flag but still return texture handle if the
* user decides to destroy another texture and upload
@@ -1374,27 +1374,27 @@ cogl_texture_new_from_file (const gchar *filename,
* in that case). As a rule then, everytime a valid
* CoglHandle is returned, it should also be destroyed
* with cogl_texture_unref at some point! */
-
+
if (!_cogl_texture_bitmap_prepare (tex, internal_format))
{
_cogl_texture_free (tex);
return COGL_INVALID_HANDLE;
}
-
+
if (!_cogl_texture_slices_create (tex))
{
_cogl_texture_free (tex);
return COGL_INVALID_HANDLE;
}
-
+
if (!_cogl_texture_upload_to_gl (tex))
{
_cogl_texture_free (tex);
return COGL_INVALID_HANDLE;
}
-
+
_cogl_texture_bitmap_free (tex);
-
+
return _cogl_texture_handle_new (tex);
}
@@ -1413,7 +1413,7 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
robustness and for completeness in case one day GLES gains
support for them.
*/
-
+
GLenum gl_error = 0;
GLboolean gl_istexture;
GLint gl_compressed = GL_FALSE;
@@ -1448,23 +1448,23 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
glBindTexture (gl_target, gl_handle);
if (glGetError () != GL_NO_ERROR)
return COGL_INVALID_HANDLE;
-
+
/* Obtain texture parameters
(only level 0 we are interested in) */
-
+
GE( glGetTexLevelParameteriv (gl_target, 0,
GL_TEXTURE_COMPRESSED,
&gl_compressed) );
-
+
GE( glGetTexLevelParameteriv (gl_target, 0,
GL_TEXTURE_INTERNAL_FORMAT,
&gl_int_format) );
-
+
GE( glGetTexLevelParameteriv (gl_target, 0,
GL_TEXTURE_WIDTH,
&gl_width) );
-
+
GE( glGetTexLevelParameteriv (gl_target, 0,
GL_TEXTURE_HEIGHT,
&gl_height) );
@@ -1472,57 +1472,57 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
GE( glGetTexParameteriv (gl_target,
GL_TEXTURE_MIN_FILTER,
&gl_min_filter) );
-
+
GE( glGetTexParameteriv (gl_target,
GL_TEXTURE_MAG_FILTER,
&gl_mag_filter) );
-
+
GE( glGetTexParameteriv (gl_target,
GL_GENERATE_MIPMAP,
&gl_gen_mipmap) );
-
+
/* Validate width and height */
if (gl_width <= 0 || gl_height <= 0)
return COGL_INVALID_HANDLE;
-
+
/* Validate pot waste */
if (x_pot_waste < 0 || x_pot_waste >= gl_width ||
y_pot_waste < 0 || y_pot_waste >= gl_height)
return COGL_INVALID_HANDLE;
-
+
/* Compressed texture images not supported */
if (gl_compressed == GL_TRUE)
return COGL_INVALID_HANDLE;
-
+
/* Try and match to a cogl format */
if (!_cogl_pixel_format_from_gl_internal (gl_int_format,
&format))
{
return COGL_INVALID_HANDLE;
}
-
+
/* Create new texture */
tex = (CoglTexture*) g_malloc ( sizeof (CoglTexture));
-
+
tex->ref_count = 1;
COGL_HANDLE_DEBUG_NEW (texture, tex);
-
+
/* Setup bitmap info */
tex->is_foreign = TRUE;
tex->auto_mipmap = (gl_gen_mipmap == GL_TRUE) ? TRUE : FALSE;
-
+
bpp = _cogl_get_format_bpp (format);
tex->bitmap.format = format;
tex->bitmap.width = gl_width - x_pot_waste;
tex->bitmap.height = gl_height - y_pot_waste;
tex->bitmap.rowstride = tex->bitmap.width * bpp;
tex->bitmap_owner = FALSE;
-
+
tex->gl_target = gl_target;
tex->gl_intformat = gl_int_format;
tex->gl_format = gl_int_format;
tex->gl_type = GL_UNSIGNED_BYTE;
-
+
tex->min_filter = gl_min_filter;
tex->mag_filter = gl_mag_filter;
tex->max_waste = 0;
@@ -1534,26 +1534,26 @@ cogl_texture_new_from_foreign (GLuint gl_handle,
tex->slice_x_spans =
g_array_sized_new (FALSE, FALSE,
sizeof (CoglTexSliceSpan), 1);
-
+
tex->slice_y_spans =
g_array_sized_new (FALSE, FALSE,
sizeof (CoglTexSliceSpan), 1);
-
+
tex->slice_gl_handles =
g_array_sized_new (FALSE, FALSE,
sizeof (GLuint), 1);
-
+
/* Store info for a single slice */
x_span.start = 0;
x_span.size = gl_width;
x_span.waste = x_pot_waste;
g_array_append_val (tex->slice_x_spans, x_span);
-
+
y_span.start = 0;
y_span.size = gl_height;
y_span.waste = y_pot_waste;
g_array_append_val (tex->slice_y_spans, y_span);
-
+
g_array_append_val (tex->slice_gl_handles, gl_handle);
return _cogl_texture_handle_new (tex);
@@ -1563,12 +1563,12 @@ guint
cogl_texture_get_width (CoglHandle handle)
{
CoglTexture *tex;
-
+
if (!cogl_is_texture (handle))
return 0;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
return tex->bitmap.width;
}
@@ -1576,12 +1576,12 @@ guint
cogl_texture_get_height (CoglHandle handle)
{
CoglTexture *tex;
-
+
if (!cogl_is_texture (handle))
return 0;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
return tex->bitmap.height;
}
@@ -1589,12 +1589,12 @@ CoglPixelFormat
cogl_texture_get_format (CoglHandle handle)
{
CoglTexture *tex;
-
+
if (!cogl_is_texture (handle))
return COGL_PIXEL_FORMAT_ANY;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
return tex->bitmap.format;
}
@@ -1602,12 +1602,12 @@ guint
cogl_texture_get_rowstride (CoglHandle handle)
{
CoglTexture *tex;
-
+
if (!cogl_is_texture (handle))
return 0;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
return tex->bitmap.rowstride;
}
@@ -1615,12 +1615,12 @@ gint
cogl_texture_get_max_waste (CoglHandle handle)
{
CoglTexture *tex;
-
+
if (!cogl_is_texture (handle))
return 0;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
return tex->max_waste;
}
@@ -1628,18 +1628,18 @@ gboolean
cogl_texture_is_sliced (CoglHandle handle)
{
CoglTexture *tex;
-
+
if (!cogl_is_texture (handle))
return FALSE;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
if (tex->slice_gl_handles == NULL)
return FALSE;
-
+
if (tex->slice_gl_handles->len <= 1)
return FALSE;
-
+
return TRUE;
}
@@ -1649,24 +1649,24 @@ cogl_texture_get_gl_texture (CoglHandle handle,
GLenum *out_gl_target)
{
CoglTexture *tex;
-
+
if (!cogl_is_texture (handle))
return FALSE;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
if (tex->slice_gl_handles == NULL)
return FALSE;
-
+
if (tex->slice_gl_handles->len < 1)
return FALSE;
-
+
if (out_gl_handle != NULL)
*out_gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0);
-
+
if (out_gl_target != NULL)
*out_gl_target = tex->gl_target;
-
+
return TRUE;
}
@@ -1674,12 +1674,12 @@ COGLenum
cogl_texture_get_min_filter (CoglHandle handle)
{
CoglTexture *tex;
-
+
if (!cogl_is_texture (handle))
return 0;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
return tex->min_filter;
}
@@ -1687,12 +1687,12 @@ COGLenum
cogl_texture_get_mag_filter (CoglHandle handle)
{
CoglTexture *tex;
-
+
if (!cogl_is_texture (handle))
return 0;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
return tex->mag_filter;
}
@@ -1704,20 +1704,20 @@ cogl_texture_set_filters (CoglHandle handle,
CoglTexture *tex;
GLuint gl_handle;
int i;
-
+
if (!cogl_is_texture (handle))
return;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
/* Store new values */
tex->min_filter = min_filter;
tex->mag_filter = mag_filter;
-
+
/* Make sure slices were created */
if (tex->slice_gl_handles == NULL)
return;
-
+
/* Apply new filters to every slice */
for (i=0; islice_gl_handles->len; ++i)
{
@@ -1753,37 +1753,37 @@ cogl_texture_set_region (CoglHandle handle,
GLenum closest_gl_format;
GLenum closest_gl_type;
gboolean success;
-
+
/* Check if valid texture handle */
if (!cogl_is_texture (handle))
return FALSE;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
/* Check for valid format */
if (format == COGL_PIXEL_FORMAT_ANY)
return FALSE;
-
+
/* Shortcut out early if the image is empty */
if (width == 0 || height == 0)
return TRUE;
-
+
/* Init source bitmap */
source_bmp.width = width;
source_bmp.height = height;
source_bmp.format = format;
source_bmp.data = (guchar*)data;
-
+
/* Rowstride from width if none specified */
bpp = _cogl_get_format_bpp (format);
source_bmp.rowstride = (rowstride == 0) ? width * bpp : rowstride;
-
+
/* Find closest format to internal that's supported by GL */
closest_format = _cogl_pixel_format_to_gl (tex->bitmap.format,
NULL, /* don't need */
&closest_gl_format,
&closest_gl_type);
-
+
/* If no direct match, convert */
if (closest_format != format)
{
@@ -1791,13 +1791,13 @@ cogl_texture_set_region (CoglHandle handle,
success = _cogl_bitmap_convert_and_premult (&source_bmp,
&temp_bmp,
closest_format);
-
+
/* Swap bitmaps if succeeded */
if (!success) return FALSE;
source_bmp = temp_bmp;
source_bmp_owner = TRUE;
}
-
+
/* Send data to GL */
_cogl_texture_upload_subregion_to_gl (tex,
src_x, src_y,
@@ -1806,11 +1806,11 @@ cogl_texture_set_region (CoglHandle handle,
&source_bmp,
closest_gl_format,
closest_gl_type);
-
+
/* Free data if owner */
if (source_bmp_owner)
g_free (source_bmp.data);
-
+
return TRUE;
}
@@ -1833,33 +1833,33 @@ cogl_texture_get_data (CoglHandle handle,
guchar *src;
guchar *dst;
gint y;
-
+
/* Check if valid texture handle */
if (!cogl_is_texture (handle))
return 0;
-
+
tex = _cogl_texture_pointer_from_handle (handle);
-
+
/* Default to internal format if none specified */
if (format == COGL_PIXEL_FORMAT_ANY)
format = tex->bitmap.format;
-
+
/* Rowstride from texture width if none specified */
bpp = _cogl_get_format_bpp (format);
if (rowstride == 0) rowstride = tex->bitmap.width * bpp;
-
+
/* Return byte size if only that requested */
byte_size = tex->bitmap.height * rowstride;
if (data == NULL) return byte_size;
-
+
/* Find closest format that's supported by GL */
closest_format = _cogl_pixel_format_to_gl (format,
NULL, /* don't need */
&closest_gl_format,
&closest_gl_type);
-
+
closest_bpp = _cogl_get_format_bpp (closest_format);
-
+
/* Is the requested format supported? */
if (closest_format == format)
{
@@ -1878,12 +1878,12 @@ cogl_texture_get_data (CoglHandle handle,
target_bmp.data = (guchar*) g_malloc (target_bmp.height
* target_bmp.rowstride);
}
-
+
/* Retrieve data from slices */
_cogl_texture_download_from_gl (tex, &target_bmp,
closest_gl_format,
closest_gl_type);
-
+
/* Was intermediate used? */
if (closest_format != format)
{
@@ -1891,11 +1891,11 @@ cogl_texture_get_data (CoglHandle handle,
success = _cogl_bitmap_convert_and_premult (&target_bmp,
&new_bmp,
format);
-
+
/* Free intermediate data and return if failed */
g_free (target_bmp.data);
if (!success) return 0;
-
+
/* Copy to user buffer */
for (y = 0; y < new_bmp.height; ++y)
{
@@ -1903,14 +1903,103 @@ cogl_texture_get_data (CoglHandle handle,
dst = data + y * rowstride;
memcpy (dst, src, new_bmp.width);
}
-
+
/* Free converted data */
g_free (new_bmp.data);
}
-
+
return byte_size;
}
+static void
+_cogl_texture_flush_vertices (void)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ if (ctx->texture_vertices->len > 0)
+ {
+ int needed_indices;
+ CoglTextureGLVertex *p
+ = (CoglTextureGLVertex *) ctx->texture_vertices->data;
+
+ /* The indices are always the same sequence regardless of the
+ vertices so we only need to change it if there are more
+ vertices than ever before */
+ needed_indices = ctx->texture_vertices->len / 4 * 6;
+ if (needed_indices > ctx->texture_indices->len)
+ {
+ int old_len = ctx->texture_indices->len;
+ int vert_num = old_len / 6 * 4;
+ int i;
+ GLushort *q;
+
+ /* Add two triangles for each quad to the list of
+ indices. That makes six new indices but two of the
+ vertices in the triangles are shared. */
+ g_array_set_size (ctx->texture_indices, needed_indices);
+ q = &g_array_index (ctx->texture_indices, GLushort, old_len);
+
+ for (i = old_len;
+ i < ctx->texture_indices->len;
+ i += 6, vert_num += 4)
+ {
+ *(q++) = vert_num + 0;
+ *(q++) = vert_num + 1;
+ *(q++) = vert_num + 3;
+
+ *(q++) = vert_num + 1;
+ *(q++) = vert_num + 2;
+ *(q++) = vert_num + 3;
+ }
+ }
+
+ GE( glVertexPointer (2, GL_FLOAT,
+ sizeof (CoglTextureGLVertex), p->v ) );
+ GE( glTexCoordPointer (2, GL_FLOAT,
+ sizeof (CoglTextureGLVertex), p->t ) );
+
+ GE( glBindTexture (ctx->texture_target, ctx->texture_current) );
+ GE( ctx->pf_glDrawRangeElements (GL_TRIANGLES,
+ 0, ctx->texture_vertices->len - 1,
+ needed_indices,
+ GL_UNSIGNED_SHORT,
+ ctx->texture_indices->data) );
+
+ g_array_set_size (ctx->texture_vertices, 0);
+ }
+}
+
+static void
+_cogl_texture_add_quad_vertices (GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ GLfloat tx1, GLfloat ty1,
+ GLfloat tx2, GLfloat ty2)
+{
+ CoglTextureGLVertex *p;
+ GLushort first_vert;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ /* Add the four vertices of the quad to the list of queued
+ vertices */
+ first_vert = ctx->texture_vertices->len;
+ g_array_set_size (ctx->texture_vertices, first_vert + 4);
+ p = &g_array_index (ctx->texture_vertices, CoglTextureGLVertex, first_vert);
+
+ p->v[0] = x1; p->v[1] = y1;
+ p->t[0] = tx1; p->t[1] = ty1;
+ p++;
+ p->v[0] = x1; p->v[1] = y2;
+ p->t[0] = tx1; p->t[1] = ty2;
+ p++;
+ p->v[0] = x2; p->v[1] = y2;
+ p->t[0] = tx2; p->t[1] = ty2;
+ p++;
+ p->v[0] = x2; p->v[1] = y1;
+ p->t[0] = tx2; p->t[1] = ty1;
+ p++;
+}
+
static void
_cogl_texture_quad_sw (CoglTexture *tex,
CoglFixed x1,
@@ -1931,38 +2020,21 @@ _cogl_texture_quad_sw (CoglTexture *tex,
CoglFixed slice_tx2 , slice_ty2;
CoglFixed slice_qx1 , slice_qy1;
CoglFixed slice_qx2 , slice_qy2;
- GLfloat tex_coords[8];
- GLfloat quad_coords[8];
GLuint gl_handle;
- gulong enable_flags = (COGL_ENABLE_VERTEX_ARRAY
- | COGL_ENABLE_TEXCOORD_ARRAY);
-
+
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
#if COGL_DEBUG
printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n");
#endif
- /* Prepare GL state */
- if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
- enable_flags |= COGL_ENABLE_TEXTURE_RECT;
- else
- enable_flags |= COGL_ENABLE_TEXTURE_2D;
-
- if (ctx->color_alpha < 255
- || tex->bitmap.format & COGL_A_BIT)
- {
- enable_flags |= COGL_ENABLE_BLEND;
- }
-
- if (ctx->enable_backface_culling)
- enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
-
- cogl_enable (enable_flags);
-
/* We can't use hardware repeat so we need to set clamp to edge
otherwise it might pull in edge pixels from the other side */
+ if (ctx->texture_vertices->len > 0
+ && ctx->texture_wrap_mode != GL_CLAMP_TO_EDGE)
+ _cogl_texture_flush_vertices ();
_cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE);
+ ctx->texture_wrap_mode = GL_CLAMP_TO_EDGE;
/* If the texture coordinates are backwards then swap both the
geometry and texture coordinates so that the texture will be
@@ -1986,21 +2058,18 @@ _cogl_texture_quad_sw (CoglTexture *tex,
ty1 = ty2;
ty2 = temp;
}
-
- GE( glTexCoordPointer (2, GL_FLOAT, 0, tex_coords) );
- GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords) );
-
+
/* Scale ratio from texture to quad widths */
tw = COGL_FIXED_FROM_INT (tex->bitmap.width);
th = COGL_FIXED_FROM_INT (tex->bitmap.height);
-
+
tqx = COGL_FIXED_DIV (x2 - x1, COGL_FIXED_MUL (tw, (tx2 - tx1)));
tqy = COGL_FIXED_DIV (y2 - y1, COGL_FIXED_MUL (th, (ty2 - ty1)));
/* Integral texture coordinate for first tile */
first_tx = COGL_FIXED_FROM_INT (COGL_FIXED_FLOOR (tx1));
first_ty = COGL_FIXED_FROM_INT (COGL_FIXED_FLOOR (ty1));
-
+
/* Denormalize texture coordinates */
first_tx = COGL_FIXED_MUL (first_tx, tw);
first_ty = COGL_FIXED_MUL (first_ty, th);
@@ -2012,21 +2081,21 @@ _cogl_texture_quad_sw (CoglTexture *tex,
/* Quad coordinate of the first tile */
first_qx = x1 - COGL_FIXED_MUL (tx1 - first_tx, tqx);
first_qy = y1 - COGL_FIXED_MUL (ty1 - first_ty, tqy);
-
-
+
+
/* Iterate until whole quad height covered */
for (_cogl_span_iter_begin (&iter_y, tex->slice_y_spans,
first_ty, ty1, ty2) ;
!_cogl_span_iter_end (&iter_y) ;
_cogl_span_iter_next (&iter_y) )
- {
+ {
/* Discard slices out of quad early */
if (!iter_y.intersects) continue;
-
+
/* Span-quad intersection in quad coordinates */
slice_qy1 = first_qy +
COGL_FIXED_MUL (iter_y.intersect_start - first_ty, tqy);
-
+
slice_qy2 = first_qy +
COGL_FIXED_MUL (iter_y.intersect_end - first_ty, tqy);
@@ -2050,14 +2119,14 @@ _cogl_texture_quad_sw (CoglTexture *tex,
{
/* Discard slices out of quad early */
if (!iter_x.intersects) continue;
-
+
/* Span-quad intersection in quad coordinates */
slice_qx1 = first_qx +
COGL_FIXED_MUL (iter_x.intersect_start - first_tx, tqx);
-
+
slice_qx2 = first_qx +
COGL_FIXED_MUL (iter_x.intersect_end - first_tx, tqx);
-
+
/* Localize slice texture coordinates */
slice_tx1 = iter_x.intersect_start - iter_x.pos;
slice_tx2 = iter_x.intersect_end - iter_x.pos;
@@ -2081,30 +2150,28 @@ _cogl_texture_quad_sw (CoglTexture *tex,
printf("tx2: %f\n", COGL_FIXED_TO_FLOAT (slice_tx2));
printf("ty2: %f\n", COGL_FIXED_TO_FLOAT (slice_ty2));
#endif
-
+
/* Pick and bind opengl texture object */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
iter_y.index * iter_x.array->len +
iter_x.index);
-
- GE( glBindTexture (tex->gl_target, gl_handle) );
-#define CFX_F COGL_FIXED_TO_FLOAT
-
- /* Draw textured quad */
- tex_coords[0] = CFX_F(slice_tx1); tex_coords[1] = CFX_F(slice_ty2);
- tex_coords[2] = CFX_F(slice_tx2); tex_coords[3] = CFX_F(slice_ty2);
- tex_coords[4] = CFX_F(slice_tx1); tex_coords[5] = CFX_F(slice_ty1);
- tex_coords[6] = CFX_F(slice_tx2); tex_coords[7] = CFX_F(slice_ty1);
+ /* If we're using a different texture from the one already queued
+ then flush the vertices */
+ if (ctx->texture_vertices->len > 0
+ && gl_handle != ctx->texture_current)
+ _cogl_texture_flush_vertices ();
+ ctx->texture_target = tex->gl_target;
+ ctx->texture_current = gl_handle;
- quad_coords[0] = CFX_F(slice_qx1); quad_coords[1] = CFX_F(slice_qy2);
- quad_coords[2] = CFX_F(slice_qx2); quad_coords[3] = CFX_F(slice_qy2);
- quad_coords[4] = CFX_F(slice_qx1); quad_coords[5] = CFX_F(slice_qy1);
- quad_coords[6] = CFX_F(slice_qx2); quad_coords[7] = CFX_F(slice_qy1);
-
- GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) );
-
-#undef CFX_F
+ _cogl_texture_add_quad_vertices (COGL_FIXED_TO_FLOAT (slice_qx1),
+ COGL_FIXED_TO_FLOAT (slice_qy1),
+ COGL_FIXED_TO_FLOAT (slice_qx2),
+ COGL_FIXED_TO_FLOAT (slice_qy2),
+ COGL_FIXED_TO_FLOAT (slice_tx1),
+ COGL_FIXED_TO_FLOAT (slice_ty1),
+ COGL_FIXED_TO_FLOAT (slice_tx2),
+ COGL_FIXED_TO_FLOAT (slice_ty2));
}
}
}
@@ -2120,37 +2187,16 @@ _cogl_texture_quad_hw (CoglTexture *tex,
CoglFixed tx2,
CoglFixed ty2)
{
- GLfloat tex_coords[8];
- GLfloat quad_coords[8];
GLuint gl_handle;
CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span;
- gulong enable_flags = (COGL_ENABLE_VERTEX_ARRAY
- | COGL_ENABLE_TEXCOORD_ARRAY);
+ GLenum wrap_mode;
#if COGL_DEBUG
printf("=== Drawing Tex Quad (Hardware Tiling Mode) ===\n");
#endif
-
+
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- /* Prepare GL state */
- if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
- enable_flags |= COGL_ENABLE_TEXTURE_RECT;
- else
- enable_flags |= COGL_ENABLE_TEXTURE_2D;
-
- if (ctx->color_alpha < 255
- || tex->bitmap.format & COGL_A_BIT)
- {
- enable_flags |= COGL_ENABLE_BLEND;
- }
-
- if (ctx->enable_backface_culling)
- enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
-
- cogl_enable (enable_flags);
-
/* If the texture coords are all in the range [0,1] then we want to
clamp the coords to the edge otherwise it can pull in edge pixels
@@ -2159,17 +2205,25 @@ _cogl_texture_quad_hw (CoglTexture *tex,
&& tx2 >= 0 && tx2 <= COGL_FIXED_1
&& ty1 >= 0 && ty1 <= COGL_FIXED_1
&& ty2 >= 0 && ty2 <= COGL_FIXED_1)
- _cogl_texture_set_wrap_mode_parameter (tex, GL_CLAMP_TO_EDGE);
+ wrap_mode = GL_CLAMP_TO_EDGE;
else
- _cogl_texture_set_wrap_mode_parameter (tex, GL_REPEAT);
+ wrap_mode = GL_REPEAT;
- GE( glTexCoordPointer (2, GL_FLOAT, 0, tex_coords) );
- GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords) );
-
/* Pick and bind opengl texture object */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0);
- GE( glBindTexture (tex->gl_target, gl_handle) );
-
+
+ /* If we're using a different texture from the one already queued
+ then flush the vertices */
+ if (ctx->texture_vertices->len > 0
+ && (gl_handle != ctx->texture_current
+ || ctx->texture_wrap_mode != wrap_mode))
+ _cogl_texture_flush_vertices ();
+ ctx->texture_target = tex->gl_target;
+ ctx->texture_current = gl_handle;
+ ctx->texture_wrap_mode = wrap_mode;
+
+ _cogl_texture_set_wrap_mode_parameter (tex, wrap_mode);
+
/* Don't include the waste in the texture coordinates */
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
@@ -2189,22 +2243,84 @@ _cogl_texture_quad_hw (CoglTexture *tex,
ty2 *= y_span->size;
}
-#define CFX_F(x) COGL_FIXED_TO_FLOAT(x)
+ _cogl_texture_add_quad_vertices (COGL_FIXED_TO_FLOAT (x1),
+ COGL_FIXED_TO_FLOAT (y1),
+ COGL_FIXED_TO_FLOAT (x2),
+ COGL_FIXED_TO_FLOAT (y2),
+ COGL_FIXED_TO_FLOAT (tx1),
+ COGL_FIXED_TO_FLOAT (ty1),
+ COGL_FIXED_TO_FLOAT (tx2),
+ COGL_FIXED_TO_FLOAT (ty2));
+}
- /* Draw textured quad */
- tex_coords[0] = CFX_F(tx1); tex_coords[1] = CFX_F(ty2);
- tex_coords[2] = CFX_F(tx2); tex_coords[3] = CFX_F(ty2);
- tex_coords[4] = CFX_F(tx1); tex_coords[5] = CFX_F(ty1);
- tex_coords[6] = CFX_F(tx2); tex_coords[7] = CFX_F(ty1);
+void
+cogl_texture_multiple_rectangles (CoglHandle handle,
+ const CoglFixed *verts,
+ guint n_rects)
+{
+ CoglTexture *tex;
+ gulong enable_flags = (COGL_ENABLE_VERTEX_ARRAY
+ | COGL_ENABLE_TEXCOORD_ARRAY);
- quad_coords[0] = CFX_F(x1); quad_coords[1] = CFX_F(y2);
- quad_coords[2] = CFX_F(x2); quad_coords[3] = CFX_F(y2);
- quad_coords[4] = CFX_F(x1); quad_coords[5] = CFX_F(y1);
- quad_coords[6] = CFX_F(x2); quad_coords[7] = CFX_F(y1);
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
- GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) );
+ /* Check if valid texture */
+ if (!cogl_is_texture (handle))
+ return;
-#undef CFX_F
+ cogl_clip_ensure ();
+
+ tex = _cogl_texture_pointer_from_handle (handle);
+
+ /* Make sure we got stuff to draw */
+ if (tex->slice_gl_handles == NULL)
+ return;
+
+ if (tex->slice_gl_handles->len == 0)
+ return;
+
+ /* Prepare GL state */
+ if (tex->gl_target == CGL_TEXTURE_RECTANGLE_ARB)
+ enable_flags |= COGL_ENABLE_TEXTURE_RECT;
+ else
+ enable_flags |= COGL_ENABLE_TEXTURE_2D;
+
+ if (ctx->color_alpha < 255
+ || tex->bitmap.format & COGL_A_BIT)
+ enable_flags |= COGL_ENABLE_BLEND;
+
+ if (ctx->enable_backface_culling)
+ enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
+
+ cogl_enable (enable_flags);
+
+ g_array_set_size (ctx->texture_vertices, 0);
+
+ while (n_rects-- > 0)
+ {
+ if (verts[4] != verts[6] && verts[5] != verts[7])
+ {
+ /* If there is only one GL texture and either the texture is
+ NPOT (no waste) or all of the coordinates are in the
+ range [0,1] then we can use hardware tiling */
+ if (tex->slice_gl_handles->len == 1
+ && ((cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
+ && tex->gl_target == GL_TEXTURE_2D)
+ || (verts[4] >= 0 && verts[4] <= COGL_FIXED_1
+ && verts[6] >= 0 && verts[6] <= COGL_FIXED_1
+ && verts[5] >= 0 && verts[5] <= COGL_FIXED_1
+ && verts[7] >= 0 && verts[7] <= COGL_FIXED_1)))
+ _cogl_texture_quad_hw (tex, verts[0],verts[1], verts[2],verts[3],
+ verts[4],verts[5], verts[6],verts[7]);
+ else
+ _cogl_texture_quad_sw (tex, verts[0],verts[1], verts[2],verts[3],
+ verts[4],verts[5], verts[6],verts[7]);
+ }
+
+ verts += 8;
+ }
+
+ _cogl_texture_flush_vertices ();
}
void
@@ -2218,39 +2334,18 @@ cogl_texture_rectangle (CoglHandle handle,
CoglFixed tx2,
CoglFixed ty2)
{
- CoglTexture *tex;
-
- /* Check if valid texture */
- if (!cogl_is_texture (handle))
- return;
-
- cogl_clip_ensure ();
+ CoglFixed verts[8];
- tex = _cogl_texture_pointer_from_handle (handle);
-
- /* Make sure we got stuff to draw */
- if (tex->slice_gl_handles == NULL)
- return;
-
- if (tex->slice_gl_handles->len == 0)
- return;
-
- if (tx1 == tx2 || ty1 == ty2)
- return;
+ verts[0] = x1;
+ verts[1] = y1;
+ verts[2] = x2;
+ verts[3] = y2;
+ verts[4] = tx1;
+ verts[5] = ty1;
+ verts[6] = tx2;
+ verts[7] = ty2;
- /* If there is only one GL texture and either the texture is NPOT
- (no waste) or all of the coordinates are in the range [0,1] then
- we can use hardware tiling */
- if (tex->slice_gl_handles->len == 1
- && ((cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
- && tex->gl_target == GL_TEXTURE_2D)
- || (tx1 >= 0 && tx1 <= COGL_FIXED_1
- && tx2 >= 0 && tx2 <= COGL_FIXED_1
- && ty1 >= 0 && ty1 <= COGL_FIXED_1
- && ty2 >= 0 && ty2 <= COGL_FIXED_1)))
- _cogl_texture_quad_hw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2);
- else
- _cogl_texture_quad_sw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2);
+ cogl_texture_multiple_rectangles (handle, verts, 1);
}
void
@@ -2299,23 +2394,9 @@ cogl_texture_polygon (CoglHandle handle,
/* Make sure there is enough space in the global texture vertex
array. This is used so we can render the polygon with a single
call to OpenGL but still support any number of vertices */
- if (ctx->texture_vertices_size < n_vertices)
- {
- guint nsize = ctx->texture_vertices_size;
-
- if (nsize == 0)
- nsize = 1;
- do
- nsize *= 2;
- while (nsize < n_vertices);
-
- ctx->texture_vertices_size = nsize;
+ g_array_set_size (ctx->texture_vertices, n_vertices);
+ p = (CoglTextureGLVertex *) ctx->texture_vertices->data;
- ctx->texture_vertices = g_realloc (ctx->texture_vertices,
- nsize
- * sizeof (CoglTextureGLVertex));
- }
-
/* Prepare GL state */
enable_flags = (COGL_ENABLE_VERTEX_ARRAY
| COGL_ENABLE_TEXCOORD_ARRAY
@@ -2332,14 +2413,12 @@ cogl_texture_polygon (CoglHandle handle,
if (use_color)
{
enable_flags |= COGL_ENABLE_COLOR_ARRAY;
- GE( glColorPointer (4, GL_UNSIGNED_BYTE, sizeof (CoglTextureGLVertex),
- ctx->texture_vertices[0].c) );
+ GE( glColorPointer (4, GL_UNSIGNED_BYTE,
+ sizeof (CoglTextureGLVertex), p->c) );
}
- GE( glVertexPointer (3, GL_FLOAT, sizeof (CoglTextureGLVertex),
- ctx->texture_vertices[0].v) );
- GE( glTexCoordPointer (2, GL_FLOAT, sizeof (CoglTextureGLVertex),
- ctx->texture_vertices[0].t) );
+ GE( glVertexPointer (3, GL_FLOAT, sizeof (CoglTextureGLVertex), p->v ) );
+ GE( glTexCoordPointer (2, GL_FLOAT, sizeof (CoglTextureGLVertex), p->t ) );
cogl_enable (enable_flags);
@@ -2362,9 +2441,11 @@ cogl_texture_polygon (CoglHandle handle,
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, tex_num++);
+ p = (CoglTextureGLVertex *) ctx->texture_vertices->data;
+
/* Convert the vertices into an array of GLfloats ready to pass to
OpenGL */
- for (i = 0, p = ctx->texture_vertices; i < n_vertices; i++, p++)
+ for (i = 0; i < n_vertices; i++, p++)
{
CoglFixed tx, ty;
diff --git a/clutter/cogl/gles/cogl-context.c b/clutter/cogl/gles/cogl-context.c
index c7c768dec..b09568de4 100644
--- a/clutter/cogl/gles/cogl-context.c
+++ b/clutter/cogl/gles/cogl-context.c
@@ -59,9 +59,11 @@ cogl_create_context ()
_context->last_path = 0;
_context->texture_handles = NULL;
- _context->texture_vertices_size = 0;
- _context->texture_vertices = NULL;
-
+ _context->texture_vertices = g_array_new (FALSE, FALSE,
+ sizeof (CoglTextureGLVertex));
+ _context->texture_indices = g_array_new (FALSE, FALSE,
+ sizeof (GLushort));
+
_context->fbo_handles = NULL;
_context->program_handles = NULL;
_context->shader_handles = NULL;
@@ -104,8 +106,10 @@ cogl_destroy_context ()
#endif
if (_context->texture_vertices)
- g_free (_context->texture_vertices);
-
+ g_array_free (_context->texture_vertices, TRUE);
+ if (_context->texture_indices)
+ g_array_free (_context->texture_indices, TRUE);
+
if (_context->texture_handles)
g_array_free (_context->texture_handles, TRUE);
if (_context->fbo_handles)
diff --git a/clutter/cogl/gles/cogl-context.h b/clutter/cogl/gles/cogl-context.h
index b62903efc..5d835712a 100644
--- a/clutter/cogl/gles/cogl-context.h
+++ b/clutter/cogl/gles/cogl-context.h
@@ -65,9 +65,14 @@ typedef struct
/* Textures */
GArray *texture_handles;
- CoglTextureGLVertex *texture_vertices;
- gulong texture_vertices_size;
-
+ GArray *texture_vertices;
+ GArray *texture_indices;
+ /* The gl texture number that the above vertices apply to. This to
+ detect when a different slice is encountered so that the vertices
+ can be flushed */
+ GLuint texture_current;
+ GLenum texture_target;
+
/* Framebuffer objects */
GArray *fbo_handles;
CoglBufferTarget draw_buffer;
diff --git a/clutter/cogl/gles/cogl-texture.c b/clutter/cogl/gles/cogl-texture.c
index 5a75eb389..915e82b23 100644
--- a/clutter/cogl/gles/cogl-texture.c
+++ b/clutter/cogl/gles/cogl-texture.c
@@ -2047,6 +2047,94 @@ cogl_texture_get_data (CoglHandle handle,
return byte_size;
}
+static void
+_cogl_texture_flush_vertices (void)
+{
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ if (ctx->texture_vertices->len > 0)
+ {
+ int needed_indices;
+ CoglTextureGLVertex *p
+ = (CoglTextureGLVertex *) ctx->texture_vertices->data;
+
+ /* The indices are always the same sequence regardless of the
+ vertices so we only need to change it if there are more
+ vertices than ever before */
+ needed_indices = ctx->texture_vertices->len / 4 * 6;
+ if (needed_indices > ctx->texture_indices->len)
+ {
+ int old_len = ctx->texture_indices->len;
+ int vert_num = old_len / 6 * 4;
+ int i;
+ GLushort *q;
+
+ /* Add two triangles for each quad to the list of
+ indices. That makes six new indices but two of the
+ vertices in the triangles are shared. */
+ g_array_set_size (ctx->texture_indices, needed_indices);
+ q = &g_array_index (ctx->texture_indices, GLushort, old_len);
+
+ for (i = old_len;
+ i < ctx->texture_indices->len;
+ i += 6, vert_num += 4)
+ {
+ *(q++) = vert_num + 0;
+ *(q++) = vert_num + 1;
+ *(q++) = vert_num + 3;
+
+ *(q++) = vert_num + 1;
+ *(q++) = vert_num + 2;
+ *(q++) = vert_num + 3;
+ }
+ }
+
+ GE( glVertexPointer (2, GL_FLOAT,
+ sizeof (CoglTextureGLVertex), p->v ) );
+ GE( glTexCoordPointer (2, GL_FLOAT,
+ sizeof (CoglTextureGLVertex), p->t ) );
+
+ GE( glBindTexture (ctx->texture_target, ctx->texture_current) );
+ GE( glDrawElements (GL_TRIANGLES,
+ needed_indices,
+ GL_UNSIGNED_SHORT,
+ ctx->texture_indices->data) );
+
+ g_array_set_size (ctx->texture_vertices, 0);
+ }
+}
+
+static void
+_cogl_texture_add_quad_vertices (GLfloat x1, GLfloat y1,
+ GLfloat x2, GLfloat y2,
+ GLfloat tx1, GLfloat ty1,
+ GLfloat tx2, GLfloat ty2)
+{
+ CoglTextureGLVertex *p;
+ GLushort first_vert;
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ /* Add the four vertices of the quad to the list of queued
+ vertices */
+ first_vert = ctx->texture_vertices->len;
+ g_array_set_size (ctx->texture_vertices, first_vert + 4);
+ p = &g_array_index (ctx->texture_vertices, CoglTextureGLVertex, first_vert);
+
+ p->v[0] = x1; p->v[1] = y1;
+ p->t[0] = tx1; p->t[1] = ty1;
+ p++;
+ p->v[0] = x1; p->v[1] = y2;
+ p->t[0] = tx1; p->t[1] = ty2;
+ p++;
+ p->v[0] = x2; p->v[1] = y2;
+ p->t[0] = tx2; p->t[1] = ty2;
+ p++;
+ p->v[0] = x2; p->v[1] = y1;
+ p->t[0] = tx2; p->t[1] = ty1;
+ p++;
+}
+
static void
_cogl_texture_quad_sw (CoglTexture *tex,
CoglFixed x1,
@@ -2067,31 +2155,13 @@ _cogl_texture_quad_sw (CoglTexture *tex,
CoglFixed slice_tx2 , slice_ty2;
CoglFixed slice_qx1 , slice_qy1;
CoglFixed slice_qx2 , slice_qy2;
- GLfloat tex_coords[8];
- GLfloat quad_coords[8];
GLuint gl_handle;
- gulong enable_flags = (COGL_ENABLE_TEXTURE_2D
- | COGL_ENABLE_VERTEX_ARRAY
- | COGL_ENABLE_TEXCOORD_ARRAY);
-
+
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
#if COGL_DEBUG
printf("=== Drawing Tex Quad (Software Tiling Mode) ===\n");
#endif
-
-
- /* Prepare GL state */
- if (ctx->color_alpha < 255
- || tex->bitmap.format & COGL_A_BIT)
- {
- enable_flags |= COGL_ENABLE_BLEND;
- }
-
- if (ctx->enable_backface_culling)
- enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
-
- cogl_enable (enable_flags);
/* If the texture coordinates are backwards then swap both the
geometry and texture coordinates so that the texture will be
@@ -2115,10 +2185,7 @@ _cogl_texture_quad_sw (CoglTexture *tex,
ty1 = ty2;
ty2 = temp;
}
-
- GE( glTexCoordPointer (2, GL_FLOAT, 0, tex_coords) );
- GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords) );
-
+
/* Scale ratio from texture to quad widths */
tw = COGL_FIXED_FROM_INT (tex->bitmap.width);
th = COGL_FIXED_FROM_INT (tex->bitmap.height);
@@ -2158,17 +2225,16 @@ _cogl_texture_quad_sw (CoglTexture *tex,
slice_qy2 = first_qy +
COGL_FIXED_MUL (iter_y.intersect_end - first_ty, tqy);
-
+
/* Localize slice texture coordinates */
slice_ty1 = iter_y.intersect_start - iter_y.pos;
slice_ty2 = iter_y.intersect_end - iter_y.pos;
-
+
/* Normalize texture coordinates to current slice
(rectangle texture targets take denormalized) */
slice_ty1 /= iter_y.span->size;
slice_ty2 /= iter_y.span->size;
-
-
+
/* Iterate until whole quad width covered */
for (_cogl_span_iter_begin (&iter_x, tex->slice_x_spans,
first_tx, tx1, tx2) ;
@@ -2188,12 +2254,12 @@ _cogl_texture_quad_sw (CoglTexture *tex,
/* Localize slice texture coordinates */
slice_tx1 = iter_x.intersect_start - iter_x.pos;
slice_tx2 = iter_x.intersect_end - iter_x.pos;
-
+
/* Normalize texture coordinates to current slice
(rectangle texture targets take denormalized) */
slice_tx1 /= iter_x.span->size;
slice_tx2 /= iter_x.span->size;
-
+
#if COGL_DEBUG
printf("~~~~~ slice (%d,%d)\n", iter_x.index, iter_y.index);
printf("qx1: %f\n", COGL_FIXED_TO_FLOAT (slice_qx1));
@@ -2210,26 +2276,23 @@ _cogl_texture_quad_sw (CoglTexture *tex,
gl_handle = g_array_index (tex->slice_gl_handles, GLuint,
iter_y.index * iter_x.array->len +
iter_x.index);
-
- GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
- tex->gl_intformat) );
-#define CFX_F COGL_FIXED_TO_FLOAT
-
- /* Draw textured quad */
- tex_coords[0] = CFX_F(slice_tx1); tex_coords[1] = CFX_F(slice_ty2);
- tex_coords[2] = CFX_F(slice_tx2); tex_coords[3] = CFX_F(slice_ty2);
- tex_coords[4] = CFX_F(slice_tx1); tex_coords[5] = CFX_F(slice_ty1);
- tex_coords[6] = CFX_F(slice_tx2); tex_coords[7] = CFX_F(slice_ty1);
+ /* If we're using a different texture from the one already queued
+ then flush the vertices */
+ if (ctx->texture_vertices->len > 0
+ && gl_handle != ctx->texture_current)
+ _cogl_texture_flush_vertices ();
+ ctx->texture_target = tex->gl_target;
+ ctx->texture_current = gl_handle;
- quad_coords[0] = CFX_F(slice_qx1); quad_coords[1] = CFX_F(slice_qy2);
- quad_coords[2] = CFX_F(slice_qx2); quad_coords[3] = CFX_F(slice_qy2);
- quad_coords[4] = CFX_F(slice_qx1); quad_coords[5] = CFX_F(slice_qy1);
- quad_coords[6] = CFX_F(slice_qx2); quad_coords[7] = CFX_F(slice_qy1);
-
- GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) );
-
-#undef CFX_F
+ _cogl_texture_add_quad_vertices (COGL_FIXED_TO_FLOAT (slice_qx1),
+ COGL_FIXED_TO_FLOAT (slice_qy1),
+ COGL_FIXED_TO_FLOAT (slice_qx2),
+ COGL_FIXED_TO_FLOAT (slice_qy2),
+ COGL_FIXED_TO_FLOAT (slice_tx1),
+ COGL_FIXED_TO_FLOAT (slice_ty1),
+ COGL_FIXED_TO_FLOAT (slice_tx2),
+ COGL_FIXED_TO_FLOAT (slice_ty2));
}
}
}
@@ -2245,41 +2308,27 @@ _cogl_texture_quad_hw (CoglTexture *tex,
CoglFixed tx2,
CoglFixed ty2)
{
- GLfloat tex_coords[8];
- GLfloat quad_coords[8];
GLuint gl_handle;
CoglTexSliceSpan *x_span;
CoglTexSliceSpan *y_span;
- gulong enable_flags = (COGL_ENABLE_TEXTURE_2D
- | COGL_ENABLE_VERTEX_ARRAY
- | COGL_ENABLE_TEXCOORD_ARRAY);
#if COGL_DEBUG
printf("=== Drawing Tex Quad (Hardware Tiling Mode) ===\n");
#endif
-
- _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
- /* Prepare GL state */
- if (ctx->color_alpha < 255
- || tex->bitmap.format & COGL_A_BIT)
- {
- enable_flags |= COGL_ENABLE_BLEND;
- }
-
- if (ctx->enable_backface_culling)
- enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
- cogl_enable (enable_flags);
-
- GE( glTexCoordPointer (2, GL_FLOAT, 0, tex_coords) );
- GE( glVertexPointer (2, GL_FLOAT, 0, quad_coords) );
-
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
/* Pick and bind opengl texture object */
gl_handle = g_array_index (tex->slice_gl_handles, GLuint, 0);
- GE( cogl_gles2_wrapper_bind_texture (tex->gl_target, gl_handle,
- tex->gl_intformat) );
-
+
+ /* If we're using a different texture from the one already queued
+ then flush the vertices */
+ if (ctx->texture_vertices->len > 0
+ && gl_handle != ctx->texture_current)
+ _cogl_texture_flush_vertices ();
+ ctx->texture_target = tex->gl_target;
+ ctx->texture_current = gl_handle;
+
/* Don't include the waste in the texture coordinates */
x_span = &g_array_index (tex->slice_x_spans, CoglTexSliceSpan, 0);
y_span = &g_array_index (tex->slice_y_spans, CoglTexSliceSpan, 0);
@@ -2290,22 +2339,80 @@ _cogl_texture_quad_hw (CoglTexture *tex,
ty1 = ty1 * (y_span->size - y_span->waste) / y_span->size;
ty2 = ty2 * (y_span->size - y_span->waste) / y_span->size;
-#define CFX_F(x) COGL_FIXED_TO_FLOAT(x)
+ _cogl_texture_add_quad_vertices (COGL_FIXED_TO_FLOAT (x1),
+ COGL_FIXED_TO_FLOAT (y1),
+ COGL_FIXED_TO_FLOAT (x2),
+ COGL_FIXED_TO_FLOAT (y2),
+ COGL_FIXED_TO_FLOAT (tx1),
+ COGL_FIXED_TO_FLOAT (ty1),
+ COGL_FIXED_TO_FLOAT (tx2),
+ COGL_FIXED_TO_FLOAT (ty2));
+}
+
+void
+cogl_texture_multiple_rectangles (CoglHandle handle,
+ const CoglFixed *verts,
+ guint n_rects)
+{
+ CoglTexture *tex;
+ gulong enable_flags = (COGL_ENABLE_VERTEX_ARRAY
+ | COGL_ENABLE_TEXCOORD_ARRAY
+ | COGL_ENABLE_TEXTURE_2D);
+
+ _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+ /* Check if valid texture */
+ if (!cogl_is_texture (handle))
+ return;
- /* Draw textured quad */
- tex_coords[0] = CFX_F(tx1); tex_coords[1] = CFX_F(ty2);
- tex_coords[2] = CFX_F(tx2); tex_coords[3] = CFX_F(ty2);
- tex_coords[4] = CFX_F(tx1); tex_coords[5] = CFX_F(ty1);
- tex_coords[6] = CFX_F(tx2); tex_coords[7] = CFX_F(ty1);
+ cogl_clip_ensure ();
- quad_coords[0] = CFX_F(x1); quad_coords[1] = CFX_F(y2);
- quad_coords[2] = CFX_F(x2); quad_coords[3] = CFX_F(y2);
- quad_coords[4] = CFX_F(x1); quad_coords[5] = CFX_F(y1);
- quad_coords[6] = CFX_F(x2); quad_coords[7] = CFX_F(y1);
+ tex = _cogl_texture_pointer_from_handle (handle);
+
+ /* Make sure we got stuff to draw */
+ if (tex->slice_gl_handles == NULL)
+ return;
+
+ if (tex->slice_gl_handles->len == 0)
+ return;
- GE (glDrawArrays (GL_TRIANGLE_STRIP, 0, 4) );
+ /* Prepare GL state */
+ if (ctx->color_alpha < 255
+ || tex->bitmap.format & COGL_A_BIT)
+ enable_flags |= COGL_ENABLE_BLEND;
-#undef CFX_F
+ if (ctx->enable_backface_culling)
+ enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
+
+ cogl_enable (enable_flags);
+
+ g_array_set_size (ctx->texture_vertices, 0);
+
+ while (n_rects-- > 0)
+ {
+ if (verts[4] != verts[6] && verts[5] != verts[7])
+ {
+ /* If there is only one GL texture and either the texture is
+ NPOT (no waste) or all of the coordinates are in the
+ range [0,1] then we can use hardware tiling */
+ if (tex->slice_gl_handles->len == 1
+ && ((cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
+ && tex->gl_target == GL_TEXTURE_2D)
+ || (verts[4] >= 0 && verts[4] <= COGL_FIXED_1
+ && verts[6] >= 0 && verts[6] <= COGL_FIXED_1
+ && verts[5] >= 0 && verts[5] <= COGL_FIXED_1
+ && verts[7] >= 0 && verts[7] <= COGL_FIXED_1)))
+ _cogl_texture_quad_hw (tex, verts[0],verts[1], verts[2],verts[3],
+ verts[4],verts[5], verts[6],verts[7]);
+ else
+ _cogl_texture_quad_sw (tex, verts[0],verts[1], verts[2],verts[3],
+ verts[4],verts[5], verts[6],verts[7]);
+ }
+
+ verts += 8;
+ }
+
+ _cogl_texture_flush_vertices ();
}
void
@@ -2319,47 +2426,18 @@ cogl_texture_rectangle (CoglHandle handle,
CoglFixed tx2,
CoglFixed ty2)
{
- CoglTexture *tex;
-
- /* Check if valid texture */
- if (!cogl_is_texture (handle))
- return;
+ CoglFixed verts[8];
- cogl_clip_ensure ();
-
- tex = _cogl_texture_pointer_from_handle (handle);
-
- /* Make sure we got stuff to draw */
- if (tex->slice_gl_handles == NULL)
- return;
-
- if (tex->slice_gl_handles->len == 0)
- return;
-
- if (tx1 == tx2 || ty1 == ty2)
- return;
-
- /* Pick tiling mode according to hw support */
- if (cogl_features_available (COGL_FEATURE_TEXTURE_NPOT)
- && tex->slice_gl_handles->len == 1)
- {
- _cogl_texture_quad_hw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2);
- }
- else
- {
- if (tex->slice_gl_handles->len == 1
- && tx1 >= -COGL_FIXED_1
- && tx2 <= COGL_FIXED_1
- && ty1 >= -COGL_FIXED_1
- && ty2 <= COGL_FIXED_1)
- {
- _cogl_texture_quad_hw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2);
- }
- else
- {
- _cogl_texture_quad_sw (tex, x1,y1, x2,y2, tx1,ty1, tx2,ty2);
- }
- }
+ verts[0] = x1;
+ verts[1] = y1;
+ verts[2] = x2;
+ verts[3] = y2;
+ verts[4] = tx1;
+ verts[5] = ty1;
+ verts[6] = tx2;
+ verts[7] = ty2;
+
+ cogl_texture_multiple_rectangles (handle, verts, 1);
}
void
@@ -2405,23 +2483,9 @@ cogl_texture_polygon (CoglHandle handle,
/* Make sure there is enough space in the global texture vertex
array. This is used so we can render the polygon with a single
call to OpenGL but still support any number of vertices */
- if (ctx->texture_vertices_size < n_vertices)
- {
- guint nsize = ctx->texture_vertices_size;
-
- if (nsize == 0)
- nsize = 1;
- do
- nsize *= 2;
- while (nsize < n_vertices);
-
- ctx->texture_vertices_size = nsize;
+ g_array_set_size (ctx->texture_vertices, n_vertices);
+ p = (CoglTextureGLVertex *) ctx->texture_vertices->data;
- ctx->texture_vertices = g_realloc (ctx->texture_vertices,
- nsize
- * sizeof (CoglTextureGLVertex));
- }
-
/* Prepare GL state */
enable_flags = (COGL_ENABLE_TEXTURE_2D
| COGL_ENABLE_VERTEX_ARRAY
@@ -2447,14 +2511,12 @@ cogl_texture_polygon (CoglHandle handle,
if (use_color)
{
enable_flags |= COGL_ENABLE_COLOR_ARRAY;
- GE( glColorPointer (4, GL_UNSIGNED_BYTE, sizeof (CoglTextureGLVertex),
- ctx->texture_vertices[0].c) );
- }
+ GE( glColorPointer (4, GL_UNSIGNED_BYTE,
+ sizeof (CoglTextureGLVertex), p->c) );
+ }
- GE( glVertexPointer (3, GL_FLOAT, sizeof (CoglTextureGLVertex),
- ctx->texture_vertices[0].v) );
- GE( glTexCoordPointer (2, GL_FLOAT, sizeof (CoglTextureGLVertex),
- ctx->texture_vertices[0].t) );
+ GE( glVertexPointer (3, GL_FLOAT, sizeof (CoglTextureGLVertex), p->v ) );
+ GE( glTexCoordPointer (2, GL_FLOAT, sizeof (CoglTextureGLVertex), p->t ) );
cogl_enable (enable_flags);
@@ -2464,7 +2526,7 @@ cogl_texture_polygon (CoglHandle handle,
/* Convert the vertices into an array of GLfloats ready to pass to
OpenGL */
- for (i = 0, p = ctx->texture_vertices; i < n_vertices; i++, p++)
+ for (i = 0; i < n_vertices; i++, p++)
{
#define CFX_F COGL_FIXED_TO_FLOAT
diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c
index 9f4f47b4a..71276d161 100644
--- a/clutter/glx/clutter-backend-glx.c
+++ b/clutter/glx/clutter-backend-glx.c
@@ -29,6 +29,8 @@
#include
#endif
+#include
+
#include
#include
#include
@@ -150,7 +152,7 @@ static const GOptionEntry entries[] =
{ "vblank", 0,
0,
G_OPTION_ARG_STRING, &clutter_vblank_name,
- "VBlank method to be used (none, dri or glx)", "METHOD"
+ N_("VBlank method to be used (none, dri or glx)"), "METHOD"
},
{ NULL }
};
diff --git a/clutter/pango/cogl-pango-render.c b/clutter/pango/cogl-pango-render.c
index bcf3b11fc..e69c412ac 100644
--- a/clutter/pango/cogl-pango-render.c
+++ b/clutter/pango/cogl-pango-render.c
@@ -51,6 +51,10 @@ struct _CoglPangoRenderer
CoglPangoGlyphCache *mipmapped_glyph_cache;
gboolean use_mipmapping;
+
+ /* Array of rectangles to draw from the current texture */
+ GArray *glyph_rectangles;
+ CoglHandle glyph_texture;
};
struct _CoglPangoRendererClass
@@ -58,6 +62,46 @@ struct _CoglPangoRendererClass
PangoRendererClass class_instance;
};
+static void
+cogl_pango_renderer_glyphs_end (CoglPangoRenderer *priv)
+{
+ if (priv->glyph_rectangles->len > 0)
+ {
+ CoglFixed *rectangles = (CoglFixed *) priv->glyph_rectangles->data;
+ cogl_texture_multiple_rectangles (priv->glyph_texture, rectangles,
+ priv->glyph_rectangles->len / 8);
+ g_array_set_size (priv->glyph_rectangles, 0);
+ }
+}
+
+static void
+cogl_pango_renderer_draw_glyph (CoglPangoRenderer *priv,
+ CoglPangoGlyphCacheValue *cache_value,
+ CoglFixed x1,
+ CoglFixed y1)
+{
+ CoglFixed x2, y2;
+ CoglFixed *p;
+
+ if (priv->glyph_rectangles->len > 0
+ && priv->glyph_texture != cache_value->texture)
+ cogl_pango_renderer_glyphs_end (priv);
+
+ priv->glyph_texture = cache_value->texture;
+
+ x2 = x1 + CLUTTER_INT_TO_FIXED (cache_value->draw_width);
+ y2 = y1 + CLUTTER_INT_TO_FIXED (cache_value->draw_height);
+
+ g_array_set_size (priv->glyph_rectangles, priv->glyph_rectangles->len + 8);
+ p = &g_array_index (priv->glyph_rectangles, CoglFixed,
+ priv->glyph_rectangles->len - 8);
+
+ *(p++) = x1; *(p++) = y1;
+ *(p++) = x2; *(p++) = y2;
+ *(p++) = cache_value->tx1; *(p++) = cache_value->ty1;
+ *(p++) = cache_value->tx2; *(p++) = cache_value->ty2;
+}
+
#define COGL_PANGO_UNIT_TO_FIXED(x) ((x) << (COGL_FIXED_Q - 10))
static void cogl_pango_renderer_finalize (GObject *object);
@@ -89,6 +133,7 @@ cogl_pango_renderer_init (CoglPangoRenderer *priv)
priv->glyph_cache = cogl_pango_glyph_cache_new (FALSE);
priv->mipmapped_glyph_cache = cogl_pango_glyph_cache_new (TRUE);
priv->use_mipmapping = FALSE;
+ priv->glyph_rectangles = g_array_new (FALSE, FALSE, sizeof (CoglFixed));
}
static void
@@ -111,6 +156,7 @@ cogl_pango_renderer_finalize (GObject *object)
cogl_pango_glyph_cache_free (priv->mipmapped_glyph_cache);
cogl_pango_glyph_cache_free (priv->glyph_cache);
+ g_array_free (priv->glyph_rectangles, TRUE);
G_OBJECT_CLASS (cogl_pango_renderer_parent_class)->finalize (object);
}
@@ -376,10 +422,10 @@ cogl_pango_renderer_draw_box (int x, int y,
static void
cogl_pango_renderer_get_device_units (PangoRenderer *renderer,
- int xin,
- int yin,
- CoglFixed *xout,
- CoglFixed *yout)
+ int xin,
+ int yin,
+ CoglFixed *xout,
+ CoglFixed *yout)
{
const PangoMatrix *matrix;
@@ -454,6 +500,7 @@ cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer,
int xi,
int yi)
{
+ CoglPangoRenderer *priv = (CoglPangoRenderer *) renderer;
CoglPangoGlyphCacheValue *cache_value;
int i;
@@ -474,6 +521,8 @@ cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer,
{
PangoFontMetrics *metrics;
+ cogl_pango_renderer_glyphs_end (priv);
+
if (font == NULL ||
(metrics = pango_font_get_metrics (font, NULL)) == NULL)
{
@@ -503,10 +552,14 @@ cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer,
gi->glyph);
if (cache_value == NULL)
- cogl_pango_renderer_draw_box (COGL_FIXED_TO_INT (x),
- COGL_FIXED_TO_INT (y),
- PANGO_UNKNOWN_GLYPH_WIDTH,
- PANGO_UNKNOWN_GLYPH_HEIGHT);
+ {
+ cogl_pango_renderer_glyphs_end (priv);
+
+ cogl_pango_renderer_draw_box (COGL_FIXED_TO_INT (x),
+ COGL_FIXED_TO_INT (y),
+ PANGO_UNKNOWN_GLYPH_WIDTH,
+ PANGO_UNKNOWN_GLYPH_HEIGHT);
+ }
else
{
CoglFixed width, height;
@@ -517,15 +570,12 @@ cogl_pango_renderer_draw_glyphs (PangoRenderer *renderer,
width = x + COGL_FIXED_FROM_INT (cache_value->draw_width);
height = y + COGL_FIXED_FROM_INT (cache_value->draw_height);
- /* Render the glyph from the texture */
- cogl_texture_rectangle (cache_value->texture,
- x, y,
- width, height,
- cache_value->tx1, cache_value->ty1,
- cache_value->tx2, cache_value->ty2);
+ cogl_pango_renderer_draw_glyph (priv, cache_value, x, y);
}
}
xi += gi->geometry.width;
}
+
+ cogl_pango_renderer_glyphs_end (priv);
}
diff --git a/clutter/x11/clutter-backend-x11.c b/clutter/x11/clutter-backend-x11.c
index f05589b9f..412bb77da 100644
--- a/clutter/x11/clutter-backend-x11.c
+++ b/clutter/x11/clutter-backend-x11.c
@@ -23,6 +23,8 @@
#include "config.h"
#endif
+#include
+
#include
#include
#ifdef HAVE_UNISTD_H
@@ -235,18 +237,18 @@ static const GOptionEntry entries[] =
"display", 0,
G_OPTION_FLAG_IN_MAIN,
G_OPTION_ARG_STRING, &clutter_display_name,
- "X display to use", "DISPLAY"
+ N_("X display to use"), "DISPLAY"
},
{
"screen", 0,
G_OPTION_FLAG_IN_MAIN,
G_OPTION_ARG_INT, &clutter_screen,
- "X screen to use", "SCREEN"
+ N_("X screen to use"), "SCREEN"
},
{ "synch", 0,
0,
G_OPTION_ARG_NONE, &clutter_synchronise,
- "Make X calls synchronous", NULL,
+ N_("Make X calls synchronous"), NULL,
},
{ NULL }
};
diff --git a/configure.ac b/configure.ac
index 0df692407..ccfc2e0f5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -580,7 +580,7 @@ AC_ARG_ENABLE([maintainer-flags],
enable_maintainer_flags=maintainer_flags_default)
if test "x$enable_maintainer_flags" = "xyes"; then
- CPPFLAGS="$CPPFLAGS -Werror -Wall -Wshadow -Wcast-align -Wno-uninitialized"
+ CPPFLAGS="$CPPFLAGS -Werror -Wall -Wshadow -Wcast-align -Wno-uninitialized -Wempty-body -Wformat-security -Winit-self"
fi
@@ -637,6 +637,7 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
ALL_LINGUAS=""
AM_GLIB_GNU_GETTEXT
+GLIB_DEFINE_LOCALEDIR(LOCALEDIR)
AC_CONFIG_FILES([
Makefile
diff --git a/doc/reference/clutter/Makefile.am b/doc/reference/clutter/Makefile.am
index ca941565f..d03a283d0 100644
--- a/doc/reference/clutter/Makefile.am
+++ b/doc/reference/clutter/Makefile.am
@@ -55,6 +55,7 @@ CFILE_GLOB=$(top_srcdir)/clutter/*.c
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
IGNORE_HFILES=\
clutter.h \
+ clutter-bezier.h \
clutter-debug.h \
clutter-deprecated.h \
clutter-enum-types.h \
diff --git a/doc/reference/clutter/clutter-docs.xml b/doc/reference/clutter/clutter-docs.xml
index ffd06a561..e29317036 100644
--- a/doc/reference/clutter/clutter-docs.xml
+++ b/doc/reference/clutter/clutter-docs.xml
@@ -58,8 +58,7 @@
-
-
+
diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt
index 5948dd14a..7c9ed607b 100644
--- a/doc/reference/clutter/clutter-sections.txt
+++ b/doc/reference/clutter/clutter-sections.txt
@@ -66,48 +66,6 @@ clutter_unit_get_type
clutter_param_unit_get_type
-
-clutter-label
-ClutterLabel
-ClutterLabel
-ClutterLabelClass
-clutter_label_new
-clutter_label_new_with_text
-clutter_label_new_full
-clutter_label_set_text
-clutter_label_get_text
-clutter_label_set_font_name
-clutter_label_get_font_name
-clutter_label_set_color
-clutter_label_get_color
-clutter_label_set_ellipsize
-clutter_label_get_ellipsize
-clutter_label_set_line_wrap
-clutter_label_get_line_wrap
-clutter_label_set_line_wrap_mode
-clutter_label_get_line_wrap_mode
-clutter_label_get_layout
-clutter_label_set_attributes
-clutter_label_get_attributes
-clutter_label_set_use_markup
-clutter_label_get_use_markup
-clutter_label_set_alignment
-clutter_label_get_alignment
-clutter_label_get_justify
-clutter_label_set_justify
-
-
-CLUTTER_LABEL
-CLUTTER_IS_LABEL
-CLUTTER_TYPE_LABEL
-CLUTTER_LABEL_CLASS
-CLUTTER_IS_LABEL_CLASS
-CLUTTER_LABEL_GET_CLASS
-
-ClutterLabelPrivate
-clutter_label_get_type
-
-
clutter-behaviour
ClutterBehaviour
@@ -476,6 +434,11 @@ clutter_actor_get_scalex
clutter_actor_set_rotationx
clutter_actor_get_rotationx
+
+clutter_actor_grab_key_focus
+clutter_actor_get_pango_context
+clutter_actor_create_pango_context
+
CLUTTER_TYPE_GEOMETRY
CLUTTER_TYPE_ACTOR_BOX
@@ -698,6 +661,8 @@ ClutterPathCallback
ClutterPathNodeType
clutter_path_new
clutter_path_new_with_description
+
+
clutter_path_add_move_to
clutter_path_add_rel_move_to
clutter_path_add_line_to
@@ -708,6 +673,8 @@ clutter_path_add_close
clutter_path_add_string
clutter_path_add_node
clutter_path_add_cairo_path
+
+
clutter_path_get_n_nodes
clutter_path_get_node
clutter_path_get_nodes
@@ -736,11 +703,9 @@ CLUTTER_PATH_CLASS
CLUTTER_IS_PATH
CLUTTER_IS_PATH_CLASS
CLUTTER_PATH_GET_CLASS
-CLUTTER_BEZIER_MAX_LENGTH
CLUTTER_PATH_RELATIVE
-ClutterBezier
ClutterPathPrivate
clutter_path_get_type
clutter_path_node_get_type
@@ -869,14 +834,16 @@ clutter_behaviour_ellipse_get_type
clutter-backend
ClutterBackend
clutter_get_default_backend
-clutter_backend_get_resolution
clutter_backend_set_resolution
-clutter_backend_get_double_click_time
+clutter_backend_get_resolution
clutter_backend_set_double_click_time
-clutter_backend_get_double_click_distance
+clutter_backend_get_double_click_time
clutter_backend_set_double_click_distance
+clutter_backend_get_double_click_distance
clutter_backend_set_font_options
clutter_backend_get_font_options
+clutter_backend_set_font_name
+clutter_backend_get_font_name
CLUTTER_BACKEND
CLUTTER_IS_BACKEND
@@ -1219,50 +1186,6 @@ CLUTTER_COGL
CLUTTER_NO_FPU
-
-clutter-entry
-ClutterEntry
-ClutterEntry
-ClutterEntryClass
-clutter_entry_new
-clutter_entry_new_with_text
-clutter_entry_new_full
-clutter_entry_set_text
-clutter_entry_get_text
-clutter_entry_set_font_name
-clutter_entry_get_font_name
-clutter_entry_set_color
-clutter_entry_get_color
-clutter_entry_get_layout
-clutter_entry_set_alignment
-clutter_entry_get_alignment
-clutter_entry_set_cursor_position
-clutter_entry_get_cursor_position
-clutter_entry_handle_key_event
-clutter_entry_insert_unichar
-clutter_entry_delete_chars
-clutter_entry_insert_text
-clutter_entry_delete_text
-clutter_entry_set_visible_cursor
-clutter_entry_get_visible_cursor
-clutter_entry_set_visibility
-clutter_entry_get_visibility
-clutter_entry_set_invisible_char
-clutter_entry_get_invisible_char
-clutter_entry_set_max_length
-clutter_entry_get_max_length
-
-CLUTTER_ENTRY
-CLUTTER_IS_ENTRY
-CLUTTER_TYPE_ENTRY
-CLUTTER_ENTRY_CLASS
-CLUTTER_IS_ENTRY_CLASS
-CLUTTER_ENTRY_GET_CLASS
-
-ClutterEntryPrivate
-clutter_entry_get_type
-
-
clutter-effect
Clutter Effects
@@ -1533,23 +1456,25 @@ clutter_shader_release
clutter_shader_is_compiled
clutter_shader_set_is_enabled
clutter_shader_get_is_enabled
-clutter_shader_set_uniform_1f
+
+
clutter_shader_set_uniform
clutter_shader_get_cogl_program
clutter_shader_get_cogl_fragment_shader
clutter_shader_get_cogl_vertex_shader
+clutter_shader_set_uniform_1f
-CLUTTER_VALUE_HOLDS_SHADER_FLOAT
ClutterShaderFloat
+CLUTTER_VALUE_HOLDS_SHADER_FLOAT
clutter_value_set_shader_float
clutter_value_get_shader_float
-CLUTTER_VALUE_HOLDS_SHADER_INT
ClutterShaderInt
+CLUTTER_VALUE_HOLDS_SHADER_INT
clutter_value_set_shader_int
clutter_value_get_shader_int
-CLUTTER_VALUE_HOLDS_SHADER_MATRIX
ClutterShaderMatrix
+CLUTTER_VALUE_HOLDS_SHADER_MATRIX
clutter_value_set_shader_matrix
clutter_value_get_shader_matrix
@@ -1572,6 +1497,9 @@ clutter_shader_float_get_type
clutter_shader_int_get_type
clutter_shader_matrix_get_type
clutter_shader_error_quark
+clutter_shader_float_get_type
+clutter_shader_int_get_type
+clutter_shader_matrix_get_type
@@ -1638,8 +1566,8 @@ clutter_interval_set_interval
clutter_interval_get_interval
-clutter_interval_validate
clutter_interval_compute_value
+clutter_interval_validate
CLUTTER_TYPE_INTERVAL
@@ -1668,7 +1596,8 @@ clutter_binding_pool_find
clutter_binding_pool_install_action
clutter_binding_pool_install_closure
-clutter_binding_pool_list_actions
+clutter_binding_pool_override_action
+clutter_binding_pool_override_closure
clutter_binding_pool_find_action
clutter_binding_pool_remove_action
clutter_binding_pool_block_action
@@ -1679,8 +1608,8 @@ clutter_binding_pool_activate
-ClutterCairoTexture
clutter-cairo-texture
+ClutterCairoTexture
ClutterCairoTexture
ClutterCairoTextureClass
clutter_cairo_texture_new
@@ -1705,4 +1634,82 @@ CLUTTER_CAIRO_TEXTURE_GET_CLASS
ClutterCairoTexturePrivate
clutter_cairo_texture_get_type
+
+
+ClutterText
+clutter-text
+ClutterText
+ClutterTextClass
+clutter_text_new
+clutter_text_new_full
+clutter_text_new_with_text
+
+
+clutter_text_set_text
+clutter_text_get_text
+clutter_text_set_activatable
+clutter_text_get_activatable
+clutter_text_set_alignment
+clutter_text_get_alignment
+clutter_text_set_attributes
+clutter_text_get_attributes
+clutter_text_set_color
+clutter_text_get_color
+clutter_text_set_ellipsize
+clutter_text_get_ellipsize
+clutter_text_set_font_name
+clutter_text_get_font_name
+clutter_text_set_password_char
+clutter_text_get_password_char
+clutter_text_set_justify
+clutter_text_get_justify
+clutter_text_get_layout
+clutter_text_set_line_wrap
+clutter_text_get_line_wrap
+clutter_text_set_line_wrap_mode
+clutter_text_get_line_wrap_mode
+clutter_text_set_max_length
+clutter_text_get_max_length
+clutter_text_set_selectable
+clutter_text_get_selectable
+clutter_text_set_selection
+clutter_text_get_selection
+clutter_text_set_selection_bound
+clutter_text_get_selection_bound
+clutter_text_set_single_line_mode
+clutter_text_get_single_line_mode
+clutter_text_set_use_markup
+clutter_text_get_use_markup
+
+
+clutter_text_set_editable
+clutter_text_get_editable
+clutter_text_insert_text
+clutter_text_insert_unichar
+clutter_text_delete_chars
+clutter_text_delete_text
+clutter_text_get_chars
+clutter_text_set_cursor_color
+clutter_text_get_cursor_color
+clutter_text_set_cursor_position
+clutter_text_get_cursor_position
+clutter_text_set_cursor_visible
+clutter_text_get_cursor_visible
+clutter_text_set_cursor_size
+clutter_text_get_cursor_size
+
+
+clutter_text_activate
+
+
+CLUTTER_IS_TEXT
+CLUTTER_IS_TEXT_CLASS
+CLUTTER_TEXT
+CLUTTER_TEXT_CLASS
+CLUTTER_TEXT_GET_CLASS
+CLUTTER_TYPE_TEXT
+
+
+ClutterTextPrivate
+clutter_text_get_type
diff --git a/doc/reference/clutter/clutter.types b/doc/reference/clutter/clutter.types
index 2bac85c6e..f59698f02 100644
--- a/doc/reference/clutter/clutter.types
+++ b/doc/reference/clutter/clutter.types
@@ -6,7 +6,6 @@ clutter_stage_get_type
clutter_rectangle_get_type
clutter_texture_get_type
clutter_clone_texture_get_type
-clutter_label_get_type
clutter_timeline_get_type
clutter_media_get_type
clutter_behaviour_get_type
@@ -19,7 +18,6 @@ clutter_path_get_type
clutter_behaviour_rotate_get_type
clutter_behaviour_scale_get_type
clutter_backend_get_type
-clutter_entry_get_type
clutter_script_get_type
clutter_scriptable_get_type
clutter_model_get_type
@@ -29,3 +27,4 @@ clutter_score_get_type
clutter_shader_get_type
clutter_child_meta_get_type
clutter_cairo_texture_get_type
+clutter_text_get_type
diff --git a/doc/reference/cogl/cogl-sections.txt b/doc/reference/cogl/cogl-sections.txt
index 03247ff3c..dcd7c933f 100644
--- a/doc/reference/cogl/cogl-sections.txt
+++ b/doc/reference/cogl/cogl-sections.txt
@@ -120,6 +120,7 @@ cogl_texture_set_region
cogl_texture_ref
cogl_texture_unref
cogl_texture_rectangle
+cogl_texture_multiple_rectangles
cogl_texture_polygon
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e69de29bb..76922d195 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -0,0 +1,14 @@
+clutter/clutter-actor.c
+clutter/clutter-behaviour.c
+clutter/clutter-color.c
+clutter/clutter-container.c
+clutter/clutter-event.c
+clutter/clutter-fixed.c
+clutter/clutter-fixed.h
+clutter/clutter-main.c
+clutter/clutter-stage-window.c
+clutter/clutter-stage.c
+clutter/clutter-texture.c
+clutter/clutter-units.c
+clutter/glx/clutter-backend-glx.c
+clutter/x11/clutter-backend-x11.c
diff --git a/po/clutter-0.8.pot b/po/clutter-0.8.pot
deleted file mode 100644
index e69de29bb..000000000
diff --git a/tests/conform/Makefile.am b/tests/conform/Makefile.am
index ec6899c0c..e3c36a873 100644
--- a/tests/conform/Makefile.am
+++ b/tests/conform/Makefile.am
@@ -17,15 +17,15 @@ test_conformance_SOURCES = \
test-mesh-mutability.c \
test-path.c \
test-pick.c \
- test-label-cache.c \
- test-clutter-entry.c \
test-clutter-rectangle.c \
test-clutter-fixed.c \
test-actor-invariants.c \
test-paint-opacity.c \
test-backface-culling.c \
test-binding-pool.c \
- $(NULL)
+ test-clutter-text.c \
+ test-text-cache.c \
+ $(NULL)
# For convenience, this provides a way to easily run individual unit tests:
.PHONY: wrappers clean-wrappers
diff --git a/tests/conform/test-binding-pool.c b/tests/conform/test-binding-pool.c
index 4a6f4ebaa..9f7f24486 100644
--- a/tests/conform/test-binding-pool.c
+++ b/tests/conform/test-binding-pool.c
@@ -260,9 +260,9 @@ on_activate (KeyGroup *key_group,
ClutterActor *child,
gpointer data)
{
- gint index = GPOINTER_TO_INT (data);
+ gint _index = GPOINTER_TO_INT (data);
- g_assert_cmpint (key_group->selected_index, ==, index);
+ g_assert_cmpint (key_group->selected_index, ==, _index);
}
void
diff --git a/tests/conform/test-clutter-entry.c b/tests/conform/test-clutter-entry.c
deleted file mode 100644
index 6562836b1..000000000
--- a/tests/conform/test-clutter-entry.c
+++ /dev/null
@@ -1,370 +0,0 @@
-#include
-#include
-#include
-
-#include "test-conform-common.h"
-
-typedef struct {
- gunichar unichar;
- const char bytes[6];
- gint nbytes;
-} TestData;
-
-const TestData
-test_data[] = {
- { 0xe4, "\xc3\xa4", 2 }, /* LATIN SMALL LETTER A WITH DIAERESIS */
- { 0x2665, "\xe2\x99\xa5", 3 } /* BLACK HEART SUIT */
-};
-
-void
-test_entry_utf8_validation (TestConformSimpleFixture *fixture,
- gconstpointer data)
-{
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (test_data); i++)
- {
- const TestData *t = &test_data[i];
- gunichar unichar;
- char bytes[6];
- int nbytes;
-
- g_assert (g_unichar_validate (t->unichar));
-
- nbytes = g_unichar_to_utf8 (t->unichar, bytes);
- bytes[nbytes] = '\0';
- g_assert (nbytes == t->nbytes);
- g_assert (memcmp (t->bytes, bytes, nbytes) == 0);
-
- unichar = g_utf8_get_char_validated (bytes, nbytes);
- g_assert (unichar == t->unichar);
- }
-}
-
-static int
-get_nbytes (ClutterEntry *entry)
-{
- const char *s = clutter_entry_get_text (entry);
- return strlen (s);
-}
-
-static int
-get_nchars (ClutterEntry *entry)
-{
- const char *s = clutter_entry_get_text (entry);
- g_assert (g_utf8_validate (s, -1, NULL));
- return g_utf8_strlen (s, -1);
-}
-
-#define DONT_MOVE_CURSOR (-2)
-
-static void
-insert_unichar (ClutterEntry *entry, gunichar unichar, int position)
-{
- if (position > DONT_MOVE_CURSOR)
- {
- clutter_entry_set_cursor_position (entry, position);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, position);
- }
-
- clutter_entry_insert_unichar (entry, unichar);
-}
-
-void
-test_entry_empty (TestConformSimpleFixture *fixture,
- gconstpointer data)
-{
- ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
-
- g_assert (clutter_entry_get_text (entry) == NULL);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
-
- clutter_actor_destroy (CLUTTER_ACTOR (entry));
-}
-
-void
-test_entry_set_empty (TestConformSimpleFixture *fixture,
- gconstpointer data)
-{
- ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
-
- /* annoyingly slightly different from initially empty */
- clutter_entry_set_text (entry, "");
- g_assert_cmpint (get_nchars (entry), ==, 0);
- g_assert_cmpint (get_nbytes (entry), ==, 0);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
-
- clutter_actor_destroy (CLUTTER_ACTOR (entry));
-}
-
-void
-test_entry_set_text (TestConformSimpleFixture *fixture,
- gconstpointer data)
-{
- ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
-
- clutter_entry_set_text (entry, "abcdef");
- g_assert_cmpint (get_nchars (entry), ==, 6);
- g_assert_cmpint (get_nbytes (entry), ==, 6);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
-
- clutter_entry_set_cursor_position (entry, 5);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 5);
-
- clutter_entry_set_text (entry, "");
- /* FIXME: cursor position should be -1?
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
- */
-
- clutter_actor_destroy (CLUTTER_ACTOR (entry));
-}
-
-void
-test_entry_append_some (TestConformSimpleFixture *fixture,
- gconstpointer data)
-{
- ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (test_data); i++)
- {
- const TestData *t = &test_data[i];
- int j;
-
- for (j = 1; j <= 4; j++)
- {
- insert_unichar (entry, t->unichar, DONT_MOVE_CURSOR);
- g_assert_cmpint (get_nchars (entry), ==, j);
- g_assert_cmpint (get_nbytes (entry), ==, j * t->nbytes);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
- }
-
- clutter_entry_set_text (entry, "");
- }
-
- clutter_actor_destroy (CLUTTER_ACTOR (entry));
-}
-
-void
-test_entry_prepend_some (TestConformSimpleFixture *fixture,
- gconstpointer data)
-{
- ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (test_data); i++)
- {
- const TestData *t = &test_data[i];
- int j;
-
- clutter_entry_insert_unichar (entry, t->unichar);
- g_assert_cmpint (get_nchars (entry), ==, 1);
- g_assert_cmpint (get_nbytes (entry), ==, 1 * t->nbytes);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
-
- for (j = 2; j <= 4; j++)
- {
- insert_unichar (entry, t->unichar, 0);
- g_assert_cmpint (get_nchars (entry), ==, j);
- g_assert_cmpint (get_nbytes (entry), ==, j * t->nbytes);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 1);
- }
-
- clutter_entry_set_text (entry, "");
- }
-
- clutter_actor_destroy (CLUTTER_ACTOR (entry));
-}
-
-void
-test_entry_insert (TestConformSimpleFixture *fixture,
- gconstpointer data)
-{
- ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (test_data); i++)
- {
- const TestData *t = &test_data[i];
-
- clutter_entry_insert_unichar (entry, t->unichar);
- clutter_entry_insert_unichar (entry, t->unichar);
-
- insert_unichar (entry, t->unichar, 1);
- g_assert_cmpint (get_nchars (entry), ==, 3);
- g_assert_cmpint (get_nbytes (entry), ==, 3 * t->nbytes);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 2);
-
- clutter_entry_set_text (entry, "");
- }
-
- clutter_actor_destroy (CLUTTER_ACTOR (entry));
-}
-
-void
-test_entry_delete_chars (TestConformSimpleFixture *fixture,
- gconstpointer data)
-{
- ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (test_data); i++)
- {
- const TestData *t = &test_data[i];
- int j;
-
- for (j = 0; j < 4; j++)
- clutter_entry_insert_unichar (entry, t->unichar);
-
- clutter_entry_set_cursor_position (entry, 2);
- clutter_entry_delete_chars (entry, 1);
- g_assert_cmpint (get_nchars (entry), ==, 3);
- g_assert_cmpint (get_nbytes (entry), ==, 3 * t->nbytes);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 1);
-
- clutter_entry_set_cursor_position (entry, 2);
- clutter_entry_delete_chars (entry, 1);
- g_assert_cmpint (get_nchars (entry), ==, 2);
- g_assert_cmpint (get_nbytes (entry), ==, 2 * t->nbytes);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 1);
-
- clutter_entry_set_text (entry, "");
- }
-
- clutter_actor_destroy (CLUTTER_ACTOR (entry));
-}
-
-void
-test_entry_delete_text (TestConformSimpleFixture *fixture,
- gconstpointer data)
-{
- ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (test_data); i++)
- {
- const TestData *t = &test_data[i];
- int j;
-
- for (j = 0; j < 4; j++)
- clutter_entry_insert_unichar (entry, t->unichar);
-
- clutter_entry_set_cursor_position (entry, 3);
- clutter_entry_delete_text (entry, 2, 4);
-
- g_assert_cmpint (get_nchars (entry), ==, 2);
- g_assert_cmpint (get_nbytes (entry), ==, 2 * t->nbytes);
-
- /* FIXME: cursor position should be -1?
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
- */
-
- clutter_entry_set_text (entry, "");
- }
-
- clutter_actor_destroy (CLUTTER_ACTOR (entry));
-}
-
-static void
-init_event (ClutterKeyEvent *event)
-{
- event->type = CLUTTER_KEY_PRESS;
- event->time = 0; /* not needed */
- event->flags = CLUTTER_EVENT_FLAG_SYNTHETIC;
- event->stage = NULL; /* not needed */
- event->source = NULL; /* not needed */
- event->modifier_state = 0;
- event->hardware_keycode = 0; /* not needed */
-}
-
-static void
-send_keyval (ClutterEntry *entry, int keyval)
-{
- ClutterKeyEvent event;
-
- init_event (&event);
- event.keyval = keyval;
- event.unicode_value = 0; /* should be ignored for cursor keys etc. */
-
- clutter_entry_handle_key_event (entry, &event);
-}
-
-static inline void
-send_unichar (ClutterEntry *entry, gunichar unichar)
-{
- ClutterKeyEvent event;
-
- init_event (&event);
- event.keyval = 0; /* should be ignored for printable characters */
- event.unicode_value = unichar;
-
- clutter_entry_handle_key_event (entry, &event);
-}
-
-void
-test_entry_cursor (TestConformSimpleFixture *fixture,
- gconstpointer data)
-{
- ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (test_data); i++)
- {
- const TestData *t = &test_data[i];
- int j;
-
- for (j = 0; j < 4; ++j)
- clutter_entry_insert_unichar (entry, t->unichar);
-
- clutter_entry_set_cursor_position (entry, 2);
-
- /* test cursor moves and is clamped */
- send_keyval (entry, CLUTTER_Left);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 1);
-
- send_keyval (entry, CLUTTER_Left);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 0);
-
- send_keyval (entry, CLUTTER_Left);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 0);
-
- /* delete text containing the cursor */
- clutter_entry_set_cursor_position (entry, 3);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, 3);
-
- clutter_entry_delete_text (entry, 2, 4);
- send_keyval (entry, CLUTTER_Left);
-
- /* FIXME: cursor position should be -1?
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
- */
-
- clutter_entry_set_text (entry, "");
- }
-
- clutter_actor_destroy (CLUTTER_ACTOR (entry));
-}
-
-void
-test_entry_event (TestConformSimpleFixture *fixture,
- gconstpointer data)
-{
- ClutterEntry *entry = CLUTTER_ENTRY (clutter_entry_new ());
- int i;
-
- for (i = 0; i < G_N_ELEMENTS (test_data); i++)
- {
- const TestData *t = &test_data[i];
-
- send_unichar (entry, t->unichar);
-
- g_assert_cmpint (get_nchars (entry), ==, 1);
- g_assert_cmpint (get_nbytes (entry), ==, 1 * t->nbytes);
- g_assert_cmpint (clutter_entry_get_cursor_position (entry), ==, -1);
-
- clutter_entry_set_text (entry, "");
- }
-
- clutter_actor_destroy (CLUTTER_ACTOR (entry));
-}
-
diff --git a/tests/conform/test-clutter-text.c b/tests/conform/test-clutter-text.c
new file mode 100644
index 000000000..6814013a8
--- /dev/null
+++ b/tests/conform/test-clutter-text.c
@@ -0,0 +1,431 @@
+#include
+#include
+#include
+
+#include "test-conform-common.h"
+
+typedef struct {
+ gunichar unichar;
+ const char bytes[6];
+ gint nbytes;
+} TestData;
+
+static const TestData
+test_text_data[] = {
+ { 0xe4, "\xc3\xa4", 2 }, /* LATIN SMALL LETTER A WITH DIAERESIS */
+ { 0x2665, "\xe2\x99\xa5", 3 } /* BLACK HEART SUIT */
+};
+
+void
+test_text_utf8_validation (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
+ {
+ const TestData *t = &test_text_data[i];
+ gunichar unichar;
+ char bytes[6];
+ int nbytes;
+
+ g_assert (g_unichar_validate (t->unichar));
+
+ nbytes = g_unichar_to_utf8 (t->unichar, bytes);
+ bytes[nbytes] = '\0';
+ g_assert (nbytes == t->nbytes);
+ g_assert (memcmp (t->bytes, bytes, nbytes) == 0);
+
+ unichar = g_utf8_get_char_validated (bytes, nbytes);
+ g_assert (unichar == t->unichar);
+ }
+}
+
+static int
+get_nbytes (ClutterText *text)
+{
+ const char *s = clutter_text_get_text (text);
+ return strlen (s);
+}
+
+static int
+get_nchars (ClutterText *text)
+{
+ const char *s = clutter_text_get_text (text);
+ g_assert (g_utf8_validate (s, -1, NULL));
+ return g_utf8_strlen (s, -1);
+}
+
+#define DONT_MOVE_CURSOR (-2)
+
+static void
+insert_unichar (ClutterText *text, gunichar unichar, int position)
+{
+ if (position > DONT_MOVE_CURSOR)
+ {
+ clutter_text_set_cursor_position (text, position);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, position);
+ }
+
+ clutter_text_insert_unichar (text, unichar);
+}
+
+void
+test_text_empty (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+
+ g_assert_cmpstr (clutter_text_get_text (text), ==, "");
+ g_assert_cmpint (*clutter_text_get_text (text), ==, '\0');
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
+void
+test_text_set_empty (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+
+ /* annoyingly slightly different from initially empty */
+ clutter_text_set_text (text, "");
+ g_assert_cmpint (get_nchars (text), ==, 0);
+ g_assert_cmpint (get_nbytes (text), ==, 0);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
+void
+test_text_set_text (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+
+ clutter_text_set_text (text, "abcdef");
+ g_assert_cmpint (get_nchars (text), ==, 6);
+ g_assert_cmpint (get_nbytes (text), ==, 6);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
+
+ clutter_text_set_cursor_position (text, 5);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 5);
+
+ /* FIXME: cursor position should be -1?
+ clutter_text_set_text (text, "");
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
+ */
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
+void
+test_text_append_some (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
+ {
+ const TestData *t = &test_text_data[i];
+ int j;
+
+ for (j = 1; j <= 4; j++)
+ {
+ insert_unichar (text, t->unichar, DONT_MOVE_CURSOR);
+
+ g_assert_cmpint (get_nchars (text), ==, j);
+ g_assert_cmpint (get_nbytes (text), ==, j * t->nbytes);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
+ }
+
+ clutter_text_set_text (text, "");
+ }
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
+void
+test_text_prepend_some (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
+ {
+ const TestData *t = &test_text_data[i];
+ int j;
+
+ clutter_text_insert_unichar (text, t->unichar);
+
+ g_assert_cmpint (get_nchars (text), ==, 1);
+ g_assert_cmpint (get_nbytes (text), ==, 1 * t->nbytes);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
+
+ for (j = 2; j <= 4; j++)
+ {
+ insert_unichar (text, t->unichar, 0);
+
+ g_assert_cmpint (get_nchars (text), ==, j);
+ g_assert_cmpint (get_nbytes (text), ==, j * t->nbytes);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1);
+ }
+
+ clutter_text_set_text (text, "");
+ }
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
+void
+test_text_insert (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
+ {
+ const TestData *t = &test_text_data[i];
+
+ clutter_text_insert_unichar (text, t->unichar);
+ clutter_text_insert_unichar (text, t->unichar);
+
+ insert_unichar (text, t->unichar, 1);
+
+ g_assert_cmpint (get_nchars (text), ==, 3);
+ g_assert_cmpint (get_nbytes (text), ==, 3 * t->nbytes);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 2);
+
+ clutter_text_set_text (text, "");
+ }
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
+void
+test_text_delete_chars (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
+ {
+ const TestData *t = &test_text_data[i];
+ int j;
+
+ for (j = 0; j < 4; j++)
+ clutter_text_insert_unichar (text, t->unichar);
+
+ clutter_text_set_cursor_position (text, 2);
+ clutter_text_delete_chars (text, 1);
+ g_assert_cmpint (get_nchars (text), ==, 3);
+ g_assert_cmpint (get_nbytes (text), ==, 3 * t->nbytes);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1);
+
+ clutter_text_set_cursor_position (text, 2);
+ clutter_text_delete_chars (text, 1);
+ g_assert_cmpint (get_nchars (text), ==, 2);
+ g_assert_cmpint (get_nbytes (text), ==, 2 * t->nbytes);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1);
+
+ clutter_text_set_text (text, "");
+ }
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
+void
+test_text_get_chars (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+ gchar *chars;
+
+ clutter_text_set_text (text, "00abcdef11");
+ g_assert_cmpint (get_nchars (text), ==, 10);
+ g_assert_cmpint (get_nbytes (text), ==, 10);
+ g_assert_cmpstr (clutter_text_get_text (text), ==, "00abcdef11");
+
+ chars = clutter_text_get_chars (text, 2, -1);
+ g_assert_cmpstr (chars, ==, "abcdef11");
+ g_free (chars);
+
+ chars = clutter_text_get_chars (text, 0, 8);
+ g_assert_cmpstr (chars, ==, "00abcdef");
+ g_free (chars);
+
+ chars = clutter_text_get_chars (text, 2, 8);
+ g_assert_cmpstr (chars, ==, "abcdef");
+ g_free (chars);
+
+ chars = clutter_text_get_chars (text, 8, 12);
+ g_assert_cmpstr (chars, ==, "11");
+ g_free (chars);
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
+void
+test_text_delete_text (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
+ {
+ const TestData *t = &test_text_data[i];
+ int j;
+
+ for (j = 0; j < 4; j++)
+ clutter_text_insert_unichar (text, t->unichar);
+
+ clutter_text_set_cursor_position (text, 3);
+ clutter_text_delete_text (text, 2, 4);
+
+ g_assert_cmpint (get_nchars (text), ==, 2);
+ g_assert_cmpint (get_nbytes (text), ==, 2 * t->nbytes);
+
+ /* FIXME: cursor position should be -1?
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
+ */
+
+ clutter_text_set_text (text, "");
+ }
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
+void
+test_text_password_char (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+
+ g_assert_cmpint (clutter_text_get_password_char (text), ==, 0);
+
+ clutter_text_set_text (text, "hello");
+ g_assert_cmpstr (clutter_text_get_text (text), ==, "hello");
+
+ clutter_text_set_password_char (text, '*');
+ g_assert_cmpint (clutter_text_get_password_char (text), ==, '*');
+
+ g_assert_cmpstr (clutter_text_get_text (text), ==, "hello");
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
+static void
+init_event (ClutterKeyEvent *event)
+{
+ event->type = CLUTTER_KEY_PRESS;
+ event->time = 0; /* not needed */
+ event->flags = CLUTTER_EVENT_FLAG_SYNTHETIC;
+ event->stage = NULL; /* not needed */
+ event->source = NULL; /* not needed */
+ event->modifier_state = 0;
+ event->hardware_keycode = 0; /* not needed */
+}
+
+static void
+send_keyval (ClutterText *text, int keyval)
+{
+ ClutterKeyEvent event;
+
+ init_event (&event);
+ event.keyval = keyval;
+ event.unicode_value = 0; /* should be ignored for cursor keys etc. */
+
+ clutter_actor_event (CLUTTER_ACTOR (text), (ClutterEvent *) &event, FALSE);
+}
+
+static void
+send_unichar (ClutterText *text, gunichar unichar)
+{
+ ClutterKeyEvent event;
+
+ init_event (&event);
+ event.keyval = 0; /* should be ignored for printable characters */
+ event.unicode_value = unichar;
+
+ clutter_actor_event (CLUTTER_ACTOR (text), (ClutterEvent *) &event, FALSE);
+}
+
+void
+test_text_cursor (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+ int i;
+
+ /* only editable entries listen to events */
+ clutter_text_set_editable (text, TRUE);
+
+ for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
+ {
+ const TestData *t = &test_text_data[i];
+ int j;
+
+ for (j = 0; j < 4; ++j)
+ clutter_text_insert_unichar (text, t->unichar);
+
+ clutter_text_set_cursor_position (text, 2);
+
+ /* test cursor moves and is clamped */
+ send_keyval (text, CLUTTER_Left);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 1);
+
+ send_keyval (text, CLUTTER_Left);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 0);
+
+ send_keyval (text, CLUTTER_Left);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 0);
+
+ /* delete text containing the cursor */
+ clutter_text_set_cursor_position (text, 3);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, 3);
+
+ clutter_text_delete_text (text, 2, 4);
+ send_keyval (text, CLUTTER_Left);
+
+ /* FIXME: cursor position should be -1?
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
+ */
+
+ clutter_text_set_text (text, "");
+ }
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
+void
+test_text_event (TestConformSimpleFixture *fixture,
+ gconstpointer data)
+{
+ ClutterText *text = CLUTTER_TEXT (clutter_text_new ());
+ int i;
+
+ /* only editable entries listen to events */
+ clutter_text_set_editable (text, TRUE);
+
+ for (i = 0; i < G_N_ELEMENTS (test_text_data); i++)
+ {
+ const TestData *t = &test_text_data[i];
+
+ send_unichar (text, t->unichar);
+
+ g_assert_cmpint (get_nchars (text), ==, 1);
+ g_assert_cmpint (get_nbytes (text), ==, 1 * t->nbytes);
+ g_assert_cmpint (clutter_text_get_cursor_position (text), ==, -1);
+
+ clutter_text_set_text (text, "");
+ }
+
+ clutter_actor_destroy (CLUTTER_ACTOR (text));
+}
+
diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c
index ff9535baf..1b8d54c0f 100644
--- a/tests/conform/test-conform-main.c
+++ b/tests/conform/test-conform-main.c
@@ -68,22 +68,21 @@ main (int argc, char **argv)
TEST_CONFORM_SIMPLE ("/picking", test_pick);
- TEST_CONFORM_SIMPLE ("/label", test_label_cache);
-
- TEST_CONFORM_SIMPLE ("/entry", test_entry_utf8_validation);
- TEST_CONFORM_SIMPLE ("/entry", test_entry_empty);
- TEST_CONFORM_SIMPLE ("/entry", test_entry_set_empty);
- TEST_CONFORM_SIMPLE ("/entry", test_entry_set_text);
-
- TEST_CONFORM_SIMPLE ("/entry", test_entry_append_some);
- TEST_CONFORM_SIMPLE ("/entry", test_entry_prepend_some);
- TEST_CONFORM_SIMPLE ("/entry", test_entry_insert);
-
- TEST_CONFORM_SIMPLE ("/entry", test_entry_delete_chars);
- TEST_CONFORM_SIMPLE ("/entry", test_entry_delete_text);
-
- TEST_CONFORM_SIMPLE ("/entry", test_entry_cursor);
- TEST_CONFORM_SIMPLE ("/entry", test_entry_event);
+ /* ClutterText */
+ TEST_CONFORM_SIMPLE ("/text", test_text_utf8_validation);
+ TEST_CONFORM_SIMPLE ("/text", test_text_empty);
+ TEST_CONFORM_SIMPLE ("/text", test_text_set_empty);
+ TEST_CONFORM_SIMPLE ("/text", test_text_set_text);
+ TEST_CONFORM_SIMPLE ("/text", test_text_append_some);
+ TEST_CONFORM_SIMPLE ("/text", test_text_prepend_some);
+ TEST_CONFORM_SIMPLE ("/text", test_text_insert);
+ TEST_CONFORM_SIMPLE ("/text", test_text_delete_chars);
+ TEST_CONFORM_SIMPLE ("/text", test_text_delete_text);
+ TEST_CONFORM_SIMPLE ("/text", test_text_cursor);
+ TEST_CONFORM_SIMPLE ("/text", test_text_event);
+ TEST_CONFORM_SIMPLE ("/text", test_text_get_chars);
+ TEST_CONFORM_SIMPLE ("/text", test_text_cache);
+ TEST_CONFORM_SIMPLE ("/text", test_text_password_char);
TEST_CONFORM_SIMPLE ("/rectangle", test_rect_set_size);
TEST_CONFORM_SIMPLE ("/rectangle", test_rect_set_color);
diff --git a/tests/conform/test-paint-opacity.c b/tests/conform/test-paint-opacity.c
index 77618a98e..3dd48e912 100644
--- a/tests/conform/test-paint-opacity.c
+++ b/tests/conform/test-paint-opacity.c
@@ -14,12 +14,12 @@ test_label_opacity (TestConformSimpleFixture *fixture,
stage = clutter_stage_get_default ();
- label = clutter_label_new_with_text ("Sans 18px", "Label, 50% opacity");
- clutter_label_set_color (CLUTTER_LABEL (label), &label_color);
+ label = clutter_text_new_with_text ("Sans 18px", "Label, 50% opacity");
+ clutter_text_set_color (CLUTTER_TEXT (label), &label_color);
if (g_test_verbose ())
g_print ("label 50%%.get_color()/1\n");
- clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
+ clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
clutter_container_add (CLUTTER_CONTAINER (stage), label, NULL);
@@ -27,12 +27,16 @@ test_label_opacity (TestConformSimpleFixture *fixture,
if (g_test_verbose ())
g_print ("label 50%%.get_color()/2\n");
- clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
+ clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
if (g_test_verbose ())
- g_print ("label 50%%.get_paint_opacity() = %d\n",
- clutter_actor_get_paint_opacity (label));
+ g_print ("label 50%%.get_paint_opacity()/1\n");
+ g_assert (clutter_actor_get_paint_opacity (label) == 255);
+
+ if (g_test_verbose ())
+ g_print ("label 50%%.get_paint_opacity()/2\n");
+ clutter_actor_set_opacity (label, 128);
g_assert (clutter_actor_get_paint_opacity (label) == 128);
clutter_actor_destroy (label);
@@ -66,8 +70,7 @@ test_rectangle_opacity (TestConformSimpleFixture *fixture,
g_assert (color_check.alpha == rect_color.alpha);
if (g_test_verbose ())
- g_print ("rect 100%%.get_paint_opacity() = %d\n",
- clutter_actor_get_paint_opacity (rect));
+ g_print ("rect 100%%.get_paint_opacity()\n");
g_assert (clutter_actor_get_paint_opacity (rect) == 255);
clutter_actor_destroy (rect);
@@ -91,25 +94,24 @@ test_paint_opacity (TestConformSimpleFixture *fixture,
clutter_actor_set_position (group1, 10, 30);
clutter_actor_show (group1);
- label = clutter_label_new_with_text ("Sans 18px", "Label+Group, 25% opacity");
- clutter_label_set_color (CLUTTER_LABEL (label), &label_color);
+ label = clutter_text_new_with_text ("Sans 18px", "Label+Group, 25% opacity");
+ clutter_text_set_color (CLUTTER_TEXT (label), &label_color);
if (g_test_verbose ())
g_print ("label 50%% + group 50%%.get_color()/1\n");
- clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
+ clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
clutter_container_add (CLUTTER_CONTAINER (group1), label, NULL);
if (g_test_verbose ())
g_print ("label 50%% + group 50%%.get_color()/2\n");
- clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
+ clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
if (g_test_verbose ())
- g_print ("label 50%% + group 50%%.get_paint_opacity() = %d\n",
- clutter_actor_get_paint_opacity (label));
- g_assert (clutter_actor_get_paint_opacity (label) == 64);
+ g_print ("label 50%% + group 50%%.get_paint_opacity() = 128\n");
+ g_assert (clutter_actor_get_paint_opacity (label) == 128);
clutter_actor_destroy (label);
@@ -133,9 +135,7 @@ test_paint_opacity (TestConformSimpleFixture *fixture,
g_assert (color_check.alpha == rect_color.alpha);
if (g_test_verbose ())
- g_print ("rect 100%%.get_paint_opacity() = %d\n",
- clutter_actor_get_paint_opacity (rect));
-
+ g_print ("rect 100%%.get_paint_opacity()\n");
g_assert (clutter_actor_get_paint_opacity (rect) == 128);
clutter_actor_destroy (rect);
diff --git a/tests/conform/test-label-cache.c b/tests/conform/test-text-cache.c
similarity index 70%
rename from tests/conform/test-label-cache.c
rename to tests/conform/test-text-cache.c
index e9298f8fd..d3a2cf5ec 100644
--- a/tests/conform/test-label-cache.c
+++ b/tests/conform/test-text-cache.c
@@ -34,7 +34,7 @@ on_paint (ClutterActor *label, CallbackData *data)
/* Check whether the layout used for this paint is different from
the layout used for the last paint */
- new_layout = clutter_label_get_layout (CLUTTER_LABEL (data->label));
+ new_layout = clutter_text_get_layout (CLUTTER_TEXT (data->label));
data->layout_changed = data->old_layout != new_layout;
if (data->old_layout)
@@ -71,7 +71,17 @@ check_result (CallbackData *data, const char *note,
if (memcmp (&test_extents, &data->label_extents, sizeof (PangoRectangle)))
{
if (g_test_verbose ())
- g_print ("extents are different, ");
+ g_print ("extents are different: expected: %d, %d, %d, %d "
+ "-> text: %d, %d, %d, %d\n",
+ test_extents.x / 1024,
+ test_extents.y / 1024,
+ test_extents.width / 1024,
+ test_extents.height / 1024,
+ data->label_extents.x / 1024,
+ data->label_extents.y / 1024,
+ data->label_extents.width / 1024,
+ data->label_extents.height / 1024);
+
fail = TRUE;
}
else
@@ -119,29 +129,29 @@ do_tests (CallbackData *data)
PangoAttribute *attr;
/* TEST 1: change the text */
- clutter_label_set_text (CLUTTER_LABEL (data->label), "Counter 0");
+ clutter_text_set_text (CLUTTER_TEXT (data->label), "Counter 0");
pango_layout_set_text (data->test_layout, "Counter 0", -1);
- check_result (data, "Change text", TRUE);
+ g_assert (check_result (data, "Change text", TRUE) == FALSE);
/* TEST 2: change a single character */
- clutter_label_set_text (CLUTTER_LABEL (data->label), "Counter 1");
+ clutter_text_set_text (CLUTTER_TEXT (data->label), "Counter 1");
pango_layout_set_text (data->test_layout, "Counter 1", -1);
- check_result (data, "Change a single character", TRUE);
+ g_assert (check_result (data, "Change a single character", TRUE) == FALSE);
/* TEST 3: move the label */
clutter_actor_set_position (data->label, 10, 0);
- check_result (data, "Move the label", FALSE);
+ g_assert (check_result (data, "Move the label", FALSE) == FALSE);
/* TEST 4: change the font */
- clutter_label_set_font_name (CLUTTER_LABEL (data->label), "Serif 15");
+ clutter_text_set_font_name (CLUTTER_TEXT (data->label), "Serif 15");
fd = pango_font_description_from_string ("Serif 15");
pango_layout_set_font_description (data->test_layout, fd);
pango_font_description_free (fd);
- check_result (data, "Change the font", TRUE);
+ g_assert (check_result (data, "Change the font", TRUE) == FALSE);
/* TEST 5: change the color */
- clutter_label_set_color (CLUTTER_LABEL (data->label), &red);
- check_result (data, "Change the color", FALSE);
+ clutter_text_set_color (CLUTTER_TEXT (data->label), &red);
+ g_assert (check_result (data, "Change the color", FALSE) == FALSE);
/* TEST 6: change the attributes */
attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
@@ -150,23 +160,23 @@ do_tests (CallbackData *data)
attr_list = pango_attr_list_new ();
pango_attr_list_insert (attr_list, attr);
attr_list_copy = pango_attr_list_copy (attr_list);
- clutter_label_set_attributes (CLUTTER_LABEL (data->label), attr_list);
+ clutter_text_set_attributes (CLUTTER_TEXT (data->label), attr_list);
pango_layout_set_attributes (data->test_layout, attr_list_copy);
pango_attr_list_unref (attr_list_copy);
pango_attr_list_unref (attr_list);
- check_result (data, "Change the attributes", TRUE);
+ g_assert (check_result (data, "Change the attributes", TRUE) == FALSE);
/* TEST 7: change the text again */
- clutter_label_set_attributes (CLUTTER_LABEL (data->label), NULL);
- clutter_label_set_text (CLUTTER_LABEL (data->label), long_text);
+ clutter_text_set_attributes (CLUTTER_TEXT (data->label), NULL);
+ clutter_text_set_text (CLUTTER_TEXT (data->label), long_text);
pango_layout_set_attributes (data->test_layout, NULL);
pango_layout_set_text (data->test_layout, long_text, -1);
- check_result (data, "Change the text again", TRUE);
+ g_assert (check_result (data, "Change the text again", TRUE) == FALSE);
/* TEST 8: enable markup */
- clutter_label_set_use_markup (CLUTTER_LABEL (data->label), TRUE);
+ clutter_text_set_use_markup (CLUTTER_TEXT (data->label), TRUE);
pango_layout_set_markup (data->test_layout, long_text, -1);
- check_result (data, "Enable markup", TRUE);
+ g_assert (check_result (data, "Enable markup", TRUE) == FALSE);
/* This part can't be a test because Clutter won't restrict the
width if wrapping and ellipsizing is disabled so the extents will
@@ -178,39 +188,39 @@ do_tests (CallbackData *data)
force_redraw (data);
/* TEST 9: enable ellipsize */
- clutter_label_set_ellipsize (CLUTTER_LABEL (data->label),
+ clutter_text_set_ellipsize (CLUTTER_TEXT (data->label),
PANGO_ELLIPSIZE_END);
pango_layout_set_ellipsize (data->test_layout, PANGO_ELLIPSIZE_END);
- check_result (data, "Enable ellipsize", TRUE);
- clutter_label_set_ellipsize (CLUTTER_LABEL (data->label),
+ g_assert (check_result (data, "Enable ellipsize", TRUE) == FALSE);
+ clutter_text_set_ellipsize (CLUTTER_TEXT (data->label),
PANGO_ELLIPSIZE_NONE);
pango_layout_set_ellipsize (data->test_layout, PANGO_ELLIPSIZE_NONE);
force_redraw (data);
/* TEST 10: enable line wrap */
- clutter_label_set_line_wrap (CLUTTER_LABEL (data->label), TRUE);
+ clutter_text_set_line_wrap (CLUTTER_TEXT (data->label), TRUE);
pango_layout_set_wrap (data->test_layout, PANGO_WRAP_WORD);
- check_result (data, "Enable line wrap", TRUE);
+ g_assert (check_result (data, "Enable line wrap", TRUE) == FALSE);
/* TEST 11: change wrap mode */
- clutter_label_set_line_wrap_mode (CLUTTER_LABEL (data->label),
+ clutter_text_set_line_wrap_mode (CLUTTER_TEXT (data->label),
PANGO_WRAP_CHAR);
pango_layout_set_wrap (data->test_layout, PANGO_WRAP_CHAR);
- check_result (data, "Change wrap mode", TRUE);
+ g_assert (check_result (data, "Change wrap mode", TRUE) == FALSE);
/* TEST 12: enable justify */
- clutter_label_set_justify (CLUTTER_LABEL (data->label), TRUE);
+ clutter_text_set_justify (CLUTTER_TEXT (data->label), TRUE);
pango_layout_set_justify (data->test_layout, TRUE);
/* Pango appears to have a bug which means that you can't change the
justification after setting the text but this fixes it.
See http://bugzilla.gnome.org/show_bug.cgi?id=551865 */
pango_layout_context_changed (data->test_layout);
- check_result (data, "Enable justify", TRUE);
+ g_assert (check_result (data, "Enable justify", TRUE) == FALSE);
/* TEST 13: change alignment */
- clutter_label_set_alignment (CLUTTER_LABEL (data->label), PANGO_ALIGN_RIGHT);
+ clutter_text_set_alignment (CLUTTER_TEXT (data->label), PANGO_ALIGN_RIGHT);
pango_layout_set_alignment (data->test_layout, PANGO_ALIGN_RIGHT);
- check_result (data, "Change alignment", TRUE);
+ g_assert (check_result (data, "Change alignment", TRUE) == FALSE);
clutter_main_quit ();
@@ -218,7 +228,7 @@ do_tests (CallbackData *data)
}
static PangoLayout *
-make_layout_like_label (ClutterLabel *label)
+make_layout_like_label (ClutterText *label)
{
PangoLayout *label_layout, *new_layout;
PangoContext *context;
@@ -226,7 +236,7 @@ make_layout_like_label (ClutterLabel *label)
/* Make another layout using the same context as the layout from the
label */
- label_layout = clutter_label_get_layout (label);
+ label_layout = clutter_text_get_layout (label);
context = pango_layout_get_context (label_layout);
new_layout = pango_layout_new (context);
fd = pango_font_description_from_string (TEST_FONT);
@@ -237,8 +247,8 @@ make_layout_like_label (ClutterLabel *label)
}
void
-test_label_cache (TestConformSimpleFixture *fixture,
- gconstpointer _data)
+test_text_cache (TestConformSimpleFixture *fixture,
+ gconstpointer _data)
{
CallbackData data;
@@ -246,9 +256,9 @@ test_label_cache (TestConformSimpleFixture *fixture,
data.stage = clutter_stage_get_default ();
- data.label = clutter_label_new_with_text (TEST_FONT, "");
+ data.label = clutter_text_new_with_text (TEST_FONT, "");
- data.test_layout = make_layout_like_label (CLUTTER_LABEL (data.label));
+ data.test_layout = make_layout_like_label (CLUTTER_TEXT (data.label));
g_signal_connect (data.label, "paint", G_CALLBACK (on_paint), &data);
diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am
index 6f98be0ea..33b371437 100644
--- a/tests/interactive/Makefile.am
+++ b/tests/interactive/Makefile.am
@@ -6,7 +6,6 @@ UNIT_TESTS = \
test-scale.c \
test-actors.c \
test-behave.c \
- test-entry.c \
test-project.c \
test-perspective.c \
test-rotate.c \
@@ -22,7 +21,6 @@ UNIT_TESTS = \
test-unproject.c \
test-viewport.c \
test-fbo.c \
- test-opacity.c \
test-multistage.c \
test-cogl-primitives.c \
test-cogl-tex-tile.c \
@@ -39,7 +37,9 @@ UNIT_TESTS = \
test-layout.c \
test-animation.c \
test-easing.c \
- test-binding-pool.c
+ test-binding-pool.c \
+ test-text.c \
+ test-text-field.c
if X11_TESTS
UNIT_TESTS += test-pixmap.c
diff --git a/tests/interactive/test-clip.c b/tests/interactive/test-clip.c
index 3b52fdb81..5ccddfbcc 100644
--- a/tests/interactive/test-clip.c
+++ b/tests/interactive/test-clip.c
@@ -15,7 +15,7 @@ typedef enum
struct _Clip
{
ClipType type;
- gint x1, y1, x2, y2;
+ gint x1, y1, x2, y2;
};
struct _CallbackData
@@ -24,7 +24,7 @@ struct _CallbackData
CoglHandle hand;
Clip current_clip;
-
+
GSList *clips;
};
@@ -122,7 +122,7 @@ on_paint (ClutterActor *actor, CallbackData *data)
{
int i;
ClutterGeometry stage_size;
- guint hand_width, hand_height;
+ gint hand_width, hand_height;
GSList *node;
clutter_actor_get_allocation_geometry (data->stage, &stage_size);
@@ -242,7 +242,7 @@ on_motion (ClutterActor *stage, ClutterMotionEvent *event,
{
data->current_clip.x2 = event->x;
data->current_clip.y2 = event->y;
-
+
clutter_actor_queue_redraw (stage);
}
@@ -305,8 +305,8 @@ test_clip_main (int argc, char **argv)
data.hand = cogl_texture_new_from_file ("redhand.png", 64, FALSE,
COGL_PIXEL_FORMAT_ANY, NULL);
- label = clutter_label_new_with_text ("Sans 12px", instructions);
- clutter_label_set_line_wrap (CLUTTER_LABEL (label), TRUE);
+ label = clutter_text_new_with_text ("Sans 12px", instructions);
+ clutter_text_set_line_wrap (CLUTTER_TEXT (label), TRUE);
clutter_actor_set_width (label, clutter_actor_get_width (data.stage) - 310);
clutter_actor_set_y (label,
clutter_actor_get_height (data.stage)
diff --git a/tests/interactive/test-cogl-tex-polygon.c b/tests/interactive/test-cogl-tex-polygon.c
index 5e237eda7..1e9d38b18 100644
--- a/tests/interactive/test-cogl-tex-polygon.c
+++ b/tests/interactive/test-cogl-tex-polygon.c
@@ -297,16 +297,16 @@ frame_cb (ClutterTimeline *timeline,
}
static void
-update_toggle_text (ClutterLabel *button, gboolean val)
+update_toggle_text (ClutterText *button, gboolean val)
{
- clutter_label_set_text (button, val ? "Enabled" : "Disabled");
+ clutter_text_set_text (button, val ? "Enabled" : "Disabled");
}
static gboolean
on_toggle_click (ClutterActor *button, ClutterEvent *event,
gboolean *toggle_val)
{
- update_toggle_text (CLUTTER_LABEL (button), *toggle_val = !*toggle_val);
+ update_toggle_text (CLUTTER_TEXT (button), *toggle_val = !*toggle_val);
return TRUE;
}
@@ -315,12 +315,12 @@ static ClutterActor *
make_toggle (const char *label_text, gboolean *toggle_val)
{
ClutterActor *group = clutter_group_new ();
- ClutterActor *label = clutter_label_new_with_text ("Sans 14", label_text);
- ClutterActor *button = clutter_label_new_with_text ("Sans 14", "");
+ ClutterActor *label = clutter_text_new_with_text ("Sans 14", label_text);
+ ClutterActor *button = clutter_text_new_with_text ("Sans 14", "");
clutter_actor_set_reactive (button, TRUE);
- update_toggle_text (CLUTTER_LABEL (button), *toggle_val);
+ update_toggle_text (CLUTTER_TEXT (button), *toggle_val);
clutter_actor_set_position (button, clutter_actor_get_width (label) + 10, 0);
clutter_container_add (CLUTTER_CONTAINER (group), label, button, NULL);
@@ -373,7 +373,7 @@ test_cogl_tex_polygon_main (int argc, char *argv[])
clutter_actor_set_position (filtering_toggle, 0,
clutter_actor_get_y (slicing_toggle)
- clutter_actor_get_height (filtering_toggle));
- note = clutter_label_new_with_text ("Sans 10", "<- Click to change");
+ note = clutter_text_new_with_text ("Sans 10", "<- Click to change");
clutter_actor_set_position (note,
clutter_actor_get_width (filtering_toggle) + 10,
(clutter_actor_get_height (stage)
diff --git a/tests/interactive/test-depth.c b/tests/interactive/test-depth.c
index a07eff234..34c024ede 100644
--- a/tests/interactive/test-depth.c
+++ b/tests/interactive/test-depth.c
@@ -26,7 +26,7 @@ raise_top (gpointer ignored)
static ClutterActor *
clone_box (ClutterTexture *original)
{
- guint width, height;
+ gint width, height;
ClutterActor *group;
ClutterActor *clone;
@@ -83,10 +83,10 @@ janus_group (const gchar *front_text,
group = clutter_group_new ();
rectangle = clutter_rectangle_new_with_color (&slide_color);
- front = clutter_label_new_with_text ("Sans 50px", front_text);
- back = clutter_label_new_with_text ("Sans 50px", back_text);
- clutter_label_set_color (CLUTTER_LABEL (front), &red);
- clutter_label_set_color (CLUTTER_LABEL (back), &green);
+ front = clutter_text_new_with_text ("Sans 50px", front_text);
+ back = clutter_text_new_with_text ("Sans 50px", back_text);
+ clutter_text_set_color (CLUTTER_TEXT (front), &red);
+ clutter_text_set_color (CLUTTER_TEXT (back), &green);
clutter_actor_get_size (front, &width, &height);
clutter_actor_get_size (back, &width2, &height2);
@@ -134,7 +134,7 @@ test_depth_main (int argc, char *argv[])
clutter_stage_add (stage, group);
clutter_actor_show (group);
- label = clutter_label_new_with_text ("Mono 26", "Clutter");
+ label = clutter_text_new_with_text ("Mono 26", "Clutter");
clutter_actor_set_position (label, 120, 200);
clutter_actor_show (label);
diff --git a/tests/interactive/test-easing.c b/tests/interactive/test-easing.c
index 555aa3c3a..22048ad4e 100644
--- a/tests/interactive/test-easing.c
+++ b/tests/interactive/test-easing.c
@@ -41,7 +41,7 @@ on_button_press (ClutterActor *actor,
current_mode + 1,
n_easing_modes);
- clutter_label_set_text (CLUTTER_LABEL (easing_mode_label), text);
+ clutter_text_set_text (CLUTTER_TEXT (easing_mode_label), text);
g_free (text);
clutter_actor_get_size (main_stage, &stage_width, &stage_height);
@@ -97,10 +97,10 @@ test_easing_main (int argc, char *argv[])
current_mode + 1,
n_easing_modes);
- label = clutter_label_new ();
+ label = clutter_text_new ();
clutter_container_add_actor (CLUTTER_CONTAINER (stage), label);
- clutter_label_set_font_name (CLUTTER_LABEL (label), "Sans 18px");
- clutter_label_set_text (CLUTTER_LABEL (label), text);
+ clutter_text_set_font_name (CLUTTER_TEXT (label), "Sans 18px");
+ clutter_text_set_text (CLUTTER_TEXT (label), text);
clutter_actor_get_size (label, &label_width, &label_height);
clutter_actor_set_position (label,
stage_width - label_width - 10,
diff --git a/tests/interactive/test-fbo.c b/tests/interactive/test-fbo.c
index bdf99f1cb..f30cbf049 100644
--- a/tests/interactive/test-fbo.c
+++ b/tests/interactive/test-fbo.c
@@ -43,9 +43,9 @@ make_source(void)
clutter_group_add (source, actor);
- actor = clutter_label_new_with_text ("Sans Bold 50px", "Clutter");
+ actor = clutter_text_new_with_text ("Sans Bold 50px", "Clutter");
- clutter_label_set_color (CLUTTER_LABEL (actor), &yellow);
+ clutter_text_set_color (CLUTTER_TEXT (actor), &yellow);
clutter_actor_set_y (actor, clutter_actor_get_height(source) + 5);
clutter_group_add (source, actor);
diff --git a/tests/interactive/test-layout.c b/tests/interactive/test-layout.c
index 9fe17222e..c11900f10 100644
--- a/tests/interactive/test-layout.c
+++ b/tests/interactive/test-layout.c
@@ -787,7 +787,7 @@ test_layout_main (int argc, char *argv[])
clutter_container_add_actor (CLUTTER_CONTAINER (stage), box);
- instructions = clutter_label_new_with_text ("Sans 14",
+ instructions = clutter_text_new_with_text ("Sans 14",
"Instructions:\n"
"a - add a new item\n"
"d - remove last item\n"
@@ -799,7 +799,7 @@ test_layout_main (int argc, char *argv[])
"s - use transformed box\n"
"q - quit");
- clutter_label_set_use_markup (CLUTTER_LABEL (instructions), TRUE);
+ clutter_text_set_use_markup (CLUTTER_TEXT (instructions), TRUE);
clutter_actor_set_position (instructions, 450, 10);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), instructions);
diff --git a/tests/interactive/test-multistage.c b/tests/interactive/test-multistage.c
index 19b9c750f..1021f8b90 100644
--- a/tests/interactive/test-multistage.c
+++ b/tests/interactive/test-multistage.c
@@ -50,10 +50,10 @@ on_button_press (ClutterActor *actor,
clutter_container_add_actor (CLUTTER_CONTAINER (new_stage), tex);
stage_label = g_strdup_printf ("Stage: %d", ++n_stages);
- label = clutter_label_new_with_text ("Mono 12", stage_label);
+ label = clutter_text_new_with_text ("Mono 12", stage_label);
- clutter_label_set_color (CLUTTER_LABEL (label), &white);
- clutter_label_set_use_markup (CLUTTER_LABEL (label), TRUE);
+ clutter_text_set_color (CLUTTER_TEXT (label), &white);
+ clutter_text_set_use_markup (CLUTTER_TEXT (label), TRUE);
width = (clutter_actor_get_width (new_stage)
- clutter_actor_get_width (label)) / 2;
height = (clutter_actor_get_height (new_stage)
@@ -110,7 +110,7 @@ test_multistage_main (int argc, char *argv[])
G_CALLBACK (on_button_press),
NULL);
- label = clutter_label_new_with_text ("Mono 16", "Default stage");
+ label = clutter_text_new_with_text ("Mono 16", "Default stage");
width = (clutter_actor_get_width (stage_default)
- clutter_actor_get_width (label))
/ 2;
diff --git a/tests/interactive/test-opacity.c b/tests/interactive/test-opacity.c
deleted file mode 100644
index cef053446..000000000
--- a/tests/interactive/test-opacity.c
+++ /dev/null
@@ -1,116 +0,0 @@
-#include
-#include
-
-#include
-#include
-
-#include
-
-G_MODULE_EXPORT int
-test_opacity_main (int argc, char *argv[])
-{
- ClutterActor *stage, *group1, *group2, *label, *rect;
- ClutterColor label_color = { 255, 0, 0, 128 };
- ClutterColor rect_color = { 0, 0, 255, 255 };
- ClutterColor color_check = { 0, };
-
- clutter_init (&argc, &argv);
-
- stage = clutter_stage_get_default ();
-
- label = clutter_label_new_with_text ("Sans 18px", "Label, 50% opacity");
- clutter_label_set_color (CLUTTER_LABEL (label), &label_color);
-
- g_print ("label 50%%.get_color()/1\n");
- clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
- g_assert (color_check.alpha == label_color.alpha);
-
- clutter_container_add (CLUTTER_CONTAINER (stage), label, NULL);
- clutter_actor_set_position (label, 10, 10);
-
- g_print ("label 50%%.get_color()/2\n");
- clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
- g_assert (color_check.alpha == label_color.alpha);
-
- g_print ("label 50%%.get_paint_opacity() = %d\n",
- clutter_actor_get_paint_opacity (label));
- g_assert (clutter_actor_get_paint_opacity (label) == 128);
-
- clutter_actor_show (label);
-
- group1 = clutter_group_new ();
- clutter_actor_set_opacity (group1, 128);
- clutter_container_add (CLUTTER_CONTAINER (stage), group1, NULL);
- clutter_actor_set_position (group1, 10, 30);
- clutter_actor_show (group1);
-
- label = clutter_label_new_with_text ("Sans 18px", "Label+Group, 25% opacity");
-
- clutter_label_set_color (CLUTTER_LABEL (label), &label_color);
-
- g_print ("label 50%% + group 50%%.get_color()/1\n");
- clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
- g_assert (color_check.alpha == label_color.alpha);
-
- clutter_container_add (CLUTTER_CONTAINER (group1), label, NULL);
-
- g_print ("label 50%% + group 50%%.get_color()/2\n");
- clutter_label_get_color (CLUTTER_LABEL (label), &color_check);
- g_assert (color_check.alpha == label_color.alpha);
-
- g_print ("label 50%% + group 50%%.get_paint_opacity() = %d\n",
- clutter_actor_get_paint_opacity (label));
- g_assert (clutter_actor_get_paint_opacity (label) == 64);
-
- clutter_actor_show (label);
-
- group2 = clutter_group_new ();
- clutter_container_add (CLUTTER_CONTAINER (group1), group2, NULL);
- clutter_actor_set_position (group2, 10, 60);
- clutter_actor_show (group2);
-
- rect = clutter_rectangle_new_with_color (&rect_color);
- clutter_actor_set_size (rect, 128, 128);
-
- g_print ("rect 100%% + group 100%% + group 50%%.get_color()/1\n");
- clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
- g_assert (color_check.alpha == rect_color.alpha);
-
- clutter_container_add (CLUTTER_CONTAINER (group2), rect, NULL);
-
- g_print ("rect 100%% + group 100%% + group 50%%.get_color()/2\n");
- clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
- g_assert (color_check.alpha == rect_color.alpha);
-
- g_print ("rect 100%%.get_paint_opacity() = %d\n",
- clutter_actor_get_paint_opacity (rect));
- g_assert (clutter_actor_get_paint_opacity (rect) == 128);
-
- clutter_actor_show (rect);
-
- rect = clutter_rectangle_new_with_color (&rect_color);
- clutter_actor_set_size (rect, 128, 128);
- clutter_actor_set_position (rect, 150, 90);
-
- g_print ("rect 100%%.get_color()/1\n");
- clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
- g_assert (color_check.alpha == rect_color.alpha);
-
- clutter_container_add (CLUTTER_CONTAINER (stage), rect, NULL);
-
- g_print ("rect 100%%.get_color()/2\n");
- clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
- g_assert (color_check.alpha == rect_color.alpha);
-
- g_print ("rect 100%%.get_paint_opacity() = %d\n",
- clutter_actor_get_paint_opacity (rect));
- g_assert (clutter_actor_get_paint_opacity (rect) == 255);
-
- clutter_actor_show (rect);
-
- clutter_actor_show_all (stage);
-
- clutter_main ();
-
- return EXIT_SUCCESS;
-}
diff --git a/tests/interactive/test-project.c b/tests/interactive/test-project.c
index 1ac2176b7..33560df0b 100644
--- a/tests/interactive/test-project.c
+++ b/tests/interactive/test-project.c
@@ -224,8 +224,8 @@ test_project_main (int argc, char *argv[])
clutter_actor_set_rotation (rect, CLUTTER_Y_AXIS, 60, 0, 0, 0);
clutter_group_add (CLUTTER_GROUP (main_stage), rect);
- label = clutter_label_new_with_text ("Mono 8pt", "Drag the blue rectangles");
- clutter_label_set_color (CLUTTER_LABEL (label), &white);
+ label = clutter_text_new_with_text ("Mono 8pt", "Drag the blue rectangles");
+ clutter_text_set_color (CLUTTER_TEXT (label), &white);
clutter_actor_set_position (label, 10, 10);
clutter_group_add (CLUTTER_GROUP (main_stage), label);
diff --git a/tests/interactive/test-random-text.c b/tests/interactive/test-random-text.c
index 18ebefff0..b73ec4b4f 100644
--- a/tests/interactive/test-random-text.c
+++ b/tests/interactive/test-random-text.c
@@ -45,7 +45,7 @@ on_idle (gpointer data)
font_names[rand () % FONT_NAME_COUNT],
rand () % (MAX_FONT_SIZE - MIN_FONT_SIZE) + MIN_FONT_SIZE);
- label = clutter_label_new_with_text (font_name, text);
+ label = clutter_text_new_with_text (font_name, text);
if (clutter_actor_get_height (label) > line_height)
line_height = clutter_actor_get_height (label);
diff --git a/tests/interactive/test-rotate.c b/tests/interactive/test-rotate.c
index 377a309db..b147a7d24 100644
--- a/tests/interactive/test-rotate.c
+++ b/tests/interactive/test-rotate.c
@@ -33,8 +33,8 @@ test_rotate_main (int argc, char *argv[])
clutter_actor_show (hand);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), hand);
- label = clutter_label_new_with_text ("Mono 16", "The Wonder of the Spinning Hand");
- clutter_label_set_alignment (CLUTTER_LABEL (label), PANGO_ALIGN_CENTER);
+ label = clutter_text_new_with_text ("Mono 16", "The Wonder of the Spinning Hand");
+ clutter_text_set_alignment (CLUTTER_TEXT (label), PANGO_ALIGN_CENTER);
clutter_actor_set_position (label, 150, 150);
clutter_actor_set_size (label, 500, 100);
clutter_actor_show (label);
diff --git a/tests/interactive/test-scale.c b/tests/interactive/test-scale.c
index 549fa298b..587cf2016 100644
--- a/tests/interactive/test-scale.c
+++ b/tests/interactive/test-scale.c
@@ -29,7 +29,7 @@ set_next_gravity (ClutterActor *actor)
eclass = g_type_class_ref (CLUTTER_TYPE_GRAVITY);
evalue = g_enum_get_value (eclass, gravity);
- clutter_label_set_text (CLUTTER_LABEL (label), evalue->value_nick);
+ clutter_text_set_text (CLUTTER_TEXT (label), evalue->value_nick);
g_type_class_unref (eclass);
if (++gindex >= G_N_ELEMENTS (gravities))
@@ -59,8 +59,8 @@ test_scale_main (int argc, char *argv[])
clutter_group_add (CLUTTER_GROUP (stage), rect);
- label = clutter_label_new_with_text ("Sans 20px", "");
- clutter_label_set_color (CLUTTER_LABEL (label),
+ label = clutter_text_new_with_text ("Sans 20px", "");
+ clutter_text_set_color (CLUTTER_TEXT (label),
&(ClutterColor) { 0xff, 0xff, 0xff, 0xff });
clutter_actor_set_position (label,
clutter_actor_get_x (rect),
diff --git a/tests/interactive/test-shader.c b/tests/interactive/test-shader.c
index 4880a704a..1101d8246 100644
--- a/tests/interactive/test-shader.c
+++ b/tests/interactive/test-shader.c
@@ -354,7 +354,7 @@ test_shader_main (gint argc, gchar *argv[])
if (!child2)
g_error("pixbuf load failed: %s", error ? error->message : "Unknown");
child3 = clutter_rectangle_new ();
- child4 = clutter_label_new_with_text ("Sans 20px", "Shady stuff");
+ child4 = clutter_text_new_with_text ("Sans 20px", "Shady stuff");
clutter_rectangle_set_color (child3, &color);
clutter_actor_set_size (child3, 50, 50);
diff --git a/tests/interactive/test-stage-read-pixels.c b/tests/interactive/test-stage-read-pixels.c
index f13b7ebe7..b0d813970 100644
--- a/tests/interactive/test-stage-read-pixels.c
+++ b/tests/interactive/test-stage-read-pixels.c
@@ -23,14 +23,14 @@ make_label (void)
gchar *text;
gchar *argv[] = { "ls", "--help", NULL };
- label = clutter_label_new ();
- clutter_label_set_font_name (CLUTTER_LABEL (label), "Sans 10");
+ label = clutter_text_new ();
+ clutter_text_set_font_name (CLUTTER_TEXT (label), "Sans 10");
if (g_spawn_sync (NULL, argv, NULL,
G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH,
NULL, NULL, &text, NULL, NULL, NULL))
{
- clutter_label_set_text (CLUTTER_LABEL (label), text);
+ clutter_text_set_text (CLUTTER_TEXT (label), text);
g_free (text);
}
diff --git a/tests/interactive/test-text-field.c b/tests/interactive/test-text-field.c
new file mode 100644
index 000000000..ca582731d
--- /dev/null
+++ b/tests/interactive/test-text-field.c
@@ -0,0 +1,117 @@
+#include
+#include
+#include
+
+#define FONT "Mono Bold 14px"
+
+static void
+on_entry_paint (ClutterActor *actor,
+ gpointer data)
+{
+ ClutterActorBox allocation = { 0, };
+ ClutterUnit width, height;
+
+ clutter_actor_get_allocation_box (actor, &allocation);
+ width = allocation.x2 - allocation.x1;
+ height = allocation.y2 - allocation.y1;
+
+ cogl_set_source_color4ub (255, 255, 255, 255);
+ cogl_path_round_rectangle (0, 0,
+ CLUTTER_UNITS_TO_FIXED (width),
+ CLUTTER_UNITS_TO_FIXED (height),
+ COGL_FIXED_FROM_INT (4),
+ COGL_ANGLE_FROM_DEG (1.0));
+ cogl_path_stroke ();
+}
+
+static void
+on_entry_activate (ClutterText *text,
+ gpointer data)
+{
+ g_print ("Text activated: %s\n", clutter_text_get_text (text));
+}
+
+static ClutterActor *
+create_label (const ClutterColor *color,
+ const gchar *text)
+{
+ ClutterActor *retval = clutter_text_new_full (FONT, text, color);
+
+ clutter_text_set_editable (CLUTTER_TEXT (retval), FALSE);
+ clutter_text_set_selectable (CLUTTER_TEXT (retval), FALSE);
+
+ return retval;
+}
+
+static ClutterActor *
+create_entry (const ClutterColor *color,
+ const gchar *text,
+ gunichar password_char,
+ gint max_length)
+{
+ ClutterActor *retval = clutter_text_new_full (FONT, text, color);
+ ClutterColor selection = { 0, };
+
+ clutter_actor_set_width (retval, 200);
+ clutter_actor_set_reactive (retval, TRUE);
+
+ clutter_color_darken (color, &selection);
+
+ clutter_text_set_editable (CLUTTER_TEXT (retval), TRUE);
+ clutter_text_set_selectable (CLUTTER_TEXT (retval), TRUE);
+ clutter_text_set_activatable (CLUTTER_TEXT (retval), TRUE);
+ clutter_text_set_single_line_mode (CLUTTER_TEXT (retval), TRUE);
+ clutter_text_set_password_char (CLUTTER_TEXT (retval), password_char);
+ clutter_text_set_cursor_color (CLUTTER_TEXT (retval), &selection);
+ clutter_text_set_max_length (CLUTTER_TEXT (retval), max_length);
+
+ g_signal_connect (retval, "activate",
+ G_CALLBACK (on_entry_activate),
+ NULL);
+ g_signal_connect (retval, "paint",
+ G_CALLBACK (on_entry_paint),
+ NULL);
+
+ return retval;
+}
+
+G_MODULE_EXPORT gint
+test_text_field_main (gint argc,
+ gchar **argv)
+{
+ ClutterActor *stage;
+ ClutterActor *text;
+ ClutterColor entry_color = {0x33, 0xff, 0x33, 0xff};
+ ClutterColor label_color = {0xff, 0xff, 0xff, 0xff};
+ ClutterColor background_color = {0x00, 0x00, 0x00, 0xff};
+ gint height;
+
+ clutter_init (&argc, &argv);
+
+ stage = clutter_stage_get_default ();
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &background_color);
+
+ text = create_label (&label_color, "Input field: ");
+ clutter_actor_set_position (text, 10, 10);
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), text);
+
+ height = clutter_actor_get_height (text);
+
+ text = create_entry (&entry_color, "some text", 0, 0);
+ clutter_actor_set_position (text, 200, 10);
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), text);
+
+ text = create_label (&label_color, "Password field: ");
+ clutter_actor_set_position (text, 10, height + 12);
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), text);
+
+ text = create_entry (&entry_color, "password", '*', 8);
+ clutter_actor_set_position (text, 200, height + 12);
+ clutter_container_add_actor (CLUTTER_CONTAINER (stage), text);
+
+ clutter_actor_show (stage);
+
+ clutter_main ();
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/interactive/test-text.c b/tests/interactive/test-text.c
new file mode 100644
index 000000000..d9bf879a7
--- /dev/null
+++ b/tests/interactive/test-text.c
@@ -0,0 +1,89 @@
+#include
+
+#include
+#include
+
+#define FONT "Mono Bold 22px"
+
+static gchar *runes =
+"ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ\n"
+"ᛋᚳᛖᚪᛚ᛫ᚦᛖᚪᚻ᛫ᛗᚪᚾᚾᚪ᛫ᚷᛖᚻᚹᛦᛚᚳ᛫ᛗᛁᚳᛚᚢᚾ᛫ᚻᛦᛏ᛫ᛞᚫᛚᚪᚾ\n"
+"ᚷᛁᚠ᛫ᚻᛖ᛫ᚹᛁᛚᛖ᛫ᚠᚩᚱ᛫ᛞᚱᛁᚻᛏᚾᛖ᛫ᛞᚩᛗᛖᛋ᛫ᚻᛚᛇᛏᚪᚾ᛬\n";
+
+
+static void
+cursor_event (ClutterText *text,
+ ClutterGeometry *geometry)
+{
+ gint y;
+
+ y = clutter_actor_get_y (CLUTTER_ACTOR (text));
+
+ if (y + geometry->y < 50)
+ {
+ clutter_actor_set_y (CLUTTER_ACTOR (text), y + 100);
+ }
+ else if (y + geometry->y > 720)
+ {
+ clutter_actor_set_y (CLUTTER_ACTOR (text), y - 100);
+ }
+
+}
+
+G_MODULE_EXPORT gint
+test_text_main (gint argc,
+ gchar **argv)
+{
+ ClutterActor *stage;
+ ClutterActor *text;
+ ClutterColor text_color = { 0x33, 0xff, 0x33, 0xff };
+ ClutterColor cursor_color = { 0xff, 0x33, 0x33, 0xff };
+ ClutterColor background_color = { 0x00, 0x00, 0x00, 0xff };
+
+ clutter_init (&argc, &argv);
+
+ stage = clutter_stage_get_default ();
+ clutter_stage_set_color (CLUTTER_STAGE (stage), &background_color);
+
+ text = clutter_text_new_full (FONT, "·", &text_color);
+
+ clutter_container_add (CLUTTER_CONTAINER (stage), text, NULL);
+ clutter_actor_set_position (text, 40, 30);
+ clutter_actor_set_width (text, 1024);
+ clutter_text_set_line_wrap (CLUTTER_TEXT (text), TRUE);
+
+ clutter_actor_set_reactive (text, TRUE);
+ clutter_stage_set_key_focus (CLUTTER_STAGE (stage), text);
+
+ clutter_text_set_editable (CLUTTER_TEXT (text), TRUE);
+ clutter_text_set_selectable (CLUTTER_TEXT (text), TRUE);
+ clutter_text_set_cursor_color (CLUTTER_TEXT (text), &cursor_color);
+
+ if (argv[1])
+ {
+ GError *error = NULL;
+ gchar *utf8;
+
+ g_file_get_contents (argv[1], &utf8, NULL, &error);
+ if (error)
+ {
+ utf8 = g_strconcat ("Unable to open '", argv[1], "':\n",
+ error->message,
+ NULL);
+ g_error_free (error);
+ }
+
+ clutter_text_set_text (CLUTTER_TEXT (text), utf8);
+ }
+ else
+ clutter_text_set_text (CLUTTER_TEXT (text), runes);
+
+ g_signal_connect (text, "cursor-event", G_CALLBACK (cursor_event), NULL);
+
+ clutter_actor_set_size (stage, 1024, 768);
+ clutter_actor_show (stage);
+
+ clutter_main ();
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/interactive/test-threads.c b/tests/interactive/test-threads.c
index 86eb6cfe3..5f946b653 100644
--- a/tests/interactive/test-threads.c
+++ b/tests/interactive/test-threads.c
@@ -42,7 +42,7 @@ test_thread_done_idle (gpointer user_data)
g_print ("Thread completed\n");
- clutter_label_set_text (CLUTTER_LABEL (data->label), "Completed");
+ clutter_text_set_text (CLUTTER_TEXT (data->label), "Completed");
clutter_timeline_stop (data->timeline);
test_thread_data_free (data);
@@ -67,7 +67,7 @@ update_label_idle (gpointer data)
text = g_strdup_printf ("Count to %d", update->count);
- clutter_label_set_text (CLUTTER_LABEL (update->thread_data->label), text);
+ clutter_text_set_text (CLUTTER_TEXT (update->thread_data->label), text);
clutter_actor_set_width (update->thread_data->label, -1);
if (update->count == 0)
@@ -151,7 +151,7 @@ on_key_press_event (ClutterStage *stage,
switch (clutter_key_event_symbol (event))
{
case CLUTTER_s:
- clutter_label_set_text (CLUTTER_LABEL (help_label), "Press 'q' to quit");
+ clutter_text_set_text (CLUTTER_TEXT (help_label), "Press 'q' to quit");
clutter_timeline_start (timeline);
@@ -191,10 +191,10 @@ test_threads_main (int argc, char *argv[])
clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
clutter_actor_set_size (stage, 600, 300);
- count_label = clutter_label_new_with_text ("Mono 12", "Counter");
+ count_label = clutter_text_new_with_text ("Mono 12", "Counter");
clutter_actor_set_position (count_label, 350, 50);
- help_label = clutter_label_new_with_text ("Mono 12", "Press 's' to start");
+ help_label = clutter_text_new_with_text ("Mono 12", "Press 's' to start");
clutter_actor_set_position (help_label, 50, 50);
rect = clutter_rectangle_new_with_color (&rect_color);
diff --git a/tests/interactive/test-unproject.c b/tests/interactive/test-unproject.c
index 422647e84..95a83cfde 100644
--- a/tests/interactive/test-unproject.c
+++ b/tests/interactive/test-unproject.c
@@ -5,13 +5,15 @@
#include
#include
-ClutterActor *label;
-
#define RECT_L 200
#define RECT_T 150
#define RECT_W 320
#define RECT_H 240
+static ClutterActor *test_rectangle = NULL;
+static ClutterActor *label = NULL;
+
+
static gboolean
on_event (ClutterStage *stage,
ClutterEvent *event,
@@ -29,15 +31,14 @@ on_event (ClutterStage *stage,
actor = clutter_stage_get_actor_at_pos (stage, x, y);
-
if (clutter_actor_transform_stage_point (actor,
- CLUTTER_UNITS_FROM_DEVICE (x),
- CLUTTER_UNITS_FROM_DEVICE (y),
- &xu2, &yu2))
+ CLUTTER_UNITS_FROM_DEVICE (x),
+ CLUTTER_UNITS_FROM_DEVICE (y),
+ &xu2, &yu2))
{
gchar *txt;
- if (actor != CLUTTER_ACTOR (stage))
+ if (actor == test_rectangle)
txt = g_strdup_printf ("Click on rectangle\n"
"Screen coords: [%d, %d]\n"
"Local coords : [%d, %d]",
@@ -52,12 +53,11 @@ on_event (ClutterStage *stage,
CLUTTER_UNITS_TO_DEVICE (xu2),
CLUTTER_UNITS_TO_DEVICE (yu2));
- clutter_label_set_text (CLUTTER_LABEL (label), txt);
+ clutter_text_set_text (CLUTTER_TEXT (label), txt);
g_free (txt);
}
else
- clutter_label_set_text (CLUTTER_LABEL (label),
- "Unprojection failed.");
+ clutter_text_set_text (CLUTTER_TEXT (label), "Unprojection failed.");
}
break;
@@ -75,9 +75,9 @@ test_unproject_main (int argc, char *argv[])
gchar *txt;
ClutterActor *rect, *stage, *label0;
int i, rotate_x = 0, rotate_y = 60, rotate_z = 0;
- ClutterColor stage_clr = { 0x0, 0x0, 0x0, 0xff },
+ ClutterColor stage_clr = { 0x0, 0x0, 0x0, 0xff },
white = { 0xff, 0xff, 0xff, 0xff },
- blue = { 0, 0xff, 0xff, 0xff };
+ blue = { 0x0, 0xff, 0xff, 0xff };
for (i = 0; i < argc; ++i)
{
@@ -95,11 +95,12 @@ test_unproject_main (int argc, char *argv[])
}
else if (!strncmp (argv[i], "--help", 6))
{
- printf ("%s [--rotage-x=degrees] [--rotage-y=degrees] "
- "[--rotage-z=degrees]\n",
- argv[0]);
+ g_print ("%s [--rotage-x=degrees] "
+ "[--rotage-y=degrees] "
+ "[--rotage-z=degrees]\n",
+ argv[0]);
- exit (0);
+ return EXIT_FAILURE;
}
}
@@ -117,6 +118,7 @@ test_unproject_main (int argc, char *argv[])
clutter_actor_set_rotation (rect, CLUTTER_Y_AXIS, rotate_y, 0, 0, 0);
clutter_actor_set_rotation (rect, CLUTTER_Z_AXIS, rotate_z, 0, 0, 0);
clutter_group_add (CLUTTER_GROUP (stage), rect);
+ test_rectangle = rect;
txt = g_strdup_printf ("Rectangle: L %d, R %d, T %d, B %d\n"
"Rotation : x %d, y %d, z %d",
@@ -124,8 +126,8 @@ test_unproject_main (int argc, char *argv[])
RECT_T, RECT_T + RECT_H,
rotate_x, rotate_y, rotate_z);
- label0 = clutter_label_new_with_text ("Mono 8pt", txt);
- clutter_label_set_color (CLUTTER_LABEL (label0), &white);
+ label0 = clutter_text_new_with_text ("Mono 8pt", txt);
+ clutter_text_set_color (CLUTTER_TEXT (label0), &white);
clutter_actor_set_position (label0, 10, 10);
clutter_group_add (CLUTTER_GROUP (stage), label0);
@@ -133,9 +135,9 @@ test_unproject_main (int argc, char *argv[])
g_free (txt);
label =
- clutter_label_new_with_text ("Mono 8pt", "Click around!");
+ clutter_text_new_with_text ("Mono 8pt", "Click around!");
- clutter_label_set_color (CLUTTER_LABEL (label), &blue);
+ clutter_text_set_color (CLUTTER_TEXT (label), &blue);
clutter_actor_set_position (label, 10, 50);
clutter_group_add (CLUTTER_GROUP (stage), label);
@@ -146,5 +148,8 @@ test_unproject_main (int argc, char *argv[])
clutter_main();
+ test_rectangle = NULL;
+ label = NULL;
+
return EXIT_SUCCESS;
}
diff --git a/tests/micro-bench/test-text.c b/tests/micro-bench/test-text.c
index a44f39d4e..afbb8b47b 100644
--- a/tests/micro-bench/test-text.c
+++ b/tests/micro-bench/test-text.c
@@ -80,14 +80,14 @@ main (int argc, char *argv[])
scale = 1.0;
}
- label = clutter_label_new_with_text (font_name, text);
- clutter_label_set_color (CLUTTER_LABEL (label), &label_color);
+ label = clutter_text_new_with_text (font_name, text);
+ clutter_text_set_color (CLUTTER_TEXT (label), &label_color);
clutter_actor_set_position (label, (1.0*STAGE_WIDTH/COLS)*col,
(1.0*STAGE_HEIGHT/ROWS)*row);
/*clutter_actor_set_clip (label, 0,0, (1.0*STAGE_WIDTH/COLS),
(1.0*STAGE_HEIGHT/ROWS));*/
clutter_actor_set_scale (label, scale, scale);
- clutter_label_set_line_wrap (CLUTTER_LABEL (label), FALSE);
+ clutter_text_set_line_wrap (CLUTTER_TEXT (label), FALSE);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), label);
}
}
diff --git a/tests/tools/Makefile.am b/tests/tools/Makefile.am
index af5efce4d..43fd46ca6 100644
--- a/tests/tools/Makefile.am
+++ b/tests/tools/Makefile.am
@@ -10,6 +10,12 @@ libdisable_npots_la_SOURCES = disable-npots.c
libdisable_npots_la_LIBADD = -ldl
+INCLUDES = \
+ -I$(top_srcdir)/clutter \
+ -I$(top_builddir)/clutter \
+ $(CLUTTER_CFLAGS) \
+ -D_GNU_SOURCE
+
all-local : disable-npots.sh
clean-local :
diff --git a/tests/tools/disable-npots.c b/tests/tools/disable-npots.c
index baa1f5778..2a942d2af 100644
--- a/tests/tools/disable-npots.c
+++ b/tests/tools/disable-npots.c
@@ -4,13 +4,22 @@
* overrides glGetString and removes the extension strings.
*/
-#include
+/* This is just included to get the right GL header */
+#include
+
#include
#include
#include
#include
#include
+/* If RTLD_NEXT isn't available then try just using NULL */
+#ifdef RTLD_NEXT
+#define LIB_HANDLE RTLD_NEXT
+#else
+#define LIB_HANDLE NULL
+#endif
+
typedef const GLubyte * (* GetStringFunc) (GLenum name);
static const char * const bad_strings[]
@@ -23,16 +32,14 @@ const GLubyte *
glGetString (GLenum name)
{
const GLubyte *ret = NULL;
- static void *gl_lib = NULL;
static GetStringFunc func = NULL;
static GLubyte *extensions = NULL;
- if (gl_lib == NULL
- && (gl_lib = dlopen ("libGL.so", RTLD_LAZY)) == NULL)
- fprintf (stderr, "dlopen: %s\n", dlerror ());
- else if (func == NULL
- && (func = (GetStringFunc) dlsym (gl_lib, "glGetString")) == NULL)
+ if (func == NULL
+ && (func = (GetStringFunc) dlsym (LIB_HANDLE, "glGetString")) == NULL)
fprintf (stderr, "dlsym: %s\n", dlerror ());
+ else if (func == glGetString)
+ fprintf (stderr, "dlsym returned the wrapper of glGetString\n");
else
{
ret = (* func) (name);