summaryrefslogtreecommitdiff
authorPekka Paalanen <ppaalanen@gmail.com>2012-09-18 10:29:13 (GMT)
committer Pekka Paalanen <ppaalanen@gmail.com>2012-09-18 10:29:13 (GMT)
commit57bb3c287ee36481d098b9aa1f5aab366eeaa4ed (patch) (side-by-side diff)
tree4433f6daecf3b277f5aa112339723baafd8deddb
parent744b9f8a4d5ccc98808cc9ccfcd6e9921d14e0a4 (diff)
parentd7f282b84e1729f4692488a8af7e696e4d6b69d7 (diff)
downloadweston-57bb3c287ee36481d098b9aa1f5aab366eeaa4ed.tar.gz
weston-57bb3c287ee36481d098b9aa1f5aab366eeaa4ed.tar.bz2
Merge branch 'master' of git://anongit.freedesktop.org/wayland/weston into ccumaster
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--clients/.gitignore24
-rw-r--r--clients/Makefile.am11
-rw-r--r--clients/cliptest.c907
-rw-r--r--clients/editor.c642
-rw-r--r--clients/keyboard.c306
-rw-r--r--clients/simple-egl.c13
-rw-r--r--man/weston.man40
-rw-r--r--protocol/Makefile.am1
-rw-r--r--protocol/input-method.xml98
-rw-r--r--protocol/text.xml135
-rw-r--r--src/.gitignore4
-rw-r--r--src/Makefile.am4
-rw-r--r--src/compositor-android.c4
-rw-r--r--src/compositor.c131
-rw-r--r--src/compositor.h21
-rw-r--r--src/gles2-renderer.c596
-rw-r--r--src/screenshooter.c15
-rw-r--r--src/shell.c16
-rw-r--r--src/tablet-shell.c13
-rw-r--r--src/text-backend.c245
-rw-r--r--src/xwayland/launcher.c2
-rw-r--r--tests/event-test.c2
-rw-r--r--tests/test-text-client.c19
-rw-r--r--tests/text-test.c4
-rw-r--r--tests/weston-test2
25 files changed, 2660 insertions, 595 deletions
diff --git a/clients/.gitignore b/clients/.gitignore
index 014c0fb..6ed849d 100644
--- a/clients/.gitignore
+++ b/clients/.gitignore
@@ -1,32 +1,36 @@
clickdot
+cliptest
desktop-shell-client-protocol.h
desktop-shell-protocol.c
dnd
+editor
eventdemo
flower
gears
image
+input-method-protocol.c
+input-method-client-protocol.h
+keyboard
libtoytoolkit.a
resizor
screenshooter-client-protocol.h
screenshooter-protocol.c
-text-cursor-position-client-protocol.h
-text-cursor-position-protocol.c
simple-egl
simple-shm
simple-touch
smoke
tablet-shell-client-protocol.h
tablet-shell-protocol.c
+text-client-protocol.h
+text-cursor-position-client-protocol.h
+text-cursor-position-protocol.c
+text-protocol.c
view
weston-desktop-shell
-weston-tablet-shell
+weston-info
+weston-screensaver
weston-screenshooter
+weston-tablet-shell
weston-terminal
-weston-screensaver
-wscreensaver
-editor
-text-protocol.c
-text-client-protocol.h
-keyboard
-weston-info
+workspaces-client-protocol.h
+workspaces-protocol.c
diff --git a/clients/Makefile.am b/clients/Makefile.am
index be8b2bc..49469f6 100644
--- a/clients/Makefile.am
+++ b/clients/Makefile.am
@@ -48,6 +48,7 @@ terminal = weston-terminal
clients_programs = \
flower \
image \
+ cliptest \
dnd \
smoke \
resizor \
@@ -88,6 +89,10 @@ weston_terminal_LDADD = $(toolkit_libs) -lutil
image_SOURCES = image.c
image_LDADD = $(toolkit_libs)
+cliptest_SOURCES = cliptest.c
+cliptest_CPPFLAGS = $(AM_CPPFLAGS) $(PIXMAN_CFLAGS)
+cliptest_LDADD = $(toolkit_libs) $(PIXMAN_LIBS)
+
dnd_SOURCES = dnd.c
dnd_LDADD = $(toolkit_libs)
@@ -113,8 +118,8 @@ keyboard_SOURCES = \
keyboard.c \
desktop-shell-client-protocol.h \
desktop-shell-protocol.c \
- text-client-protocol.h \
- text-protocol.c
+ input-method-protocol.c \
+ input-method-client-protocol.h
keyboard_LDADD = $(toolkit_libs)
weston_info_SOURCES = \
@@ -142,6 +147,8 @@ BUILT_SOURCES = \
text-cursor-position-protocol.c \
text-protocol.c \
text-client-protocol.h \
+ input-method-protocol.c \
+ input-method-client-protocol.h \
desktop-shell-client-protocol.h \
desktop-shell-protocol.c \
tablet-shell-client-protocol.h \
diff --git a/clients/cliptest.c b/clients/cliptest.c
new file mode 100644
index 0000000..4dd4380
--- a/dev/null
+++ b/clients/cliptest.c
@@ -0,0 +1,907 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ * Copyright © 2012 Rob Clark
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/* cliptest: for debugging calculate_edges() function, which is copied
+ * from compositor.c.
+ * controls:
+ * clip box position: mouse left drag, keys: w a s d
+ * clip box size: mouse right drag, keys: i j k l
+ * surface orientation: mouse wheel, keys: n m
+ * surface transform disable key: r
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <math.h>
+#include <time.h>
+#include <pixman.h>
+#include <cairo.h>
+#include <float.h>
+#include <assert.h>
+
+#include <linux/input.h>
+#include <wayland-client.h>
+
+#include "window.h"
+
+typedef float GLfloat;
+
+struct geometry {
+ pixman_box32_t clip;
+
+ pixman_box32_t surf;
+ float s; /* sin phi */
+ float c; /* cos phi */
+ float phi;
+};
+
+struct weston_surface {
+ struct {
+ int enabled;
+ } transform;
+
+ struct geometry *geometry;
+};
+
+static void
+weston_surface_to_global_float(struct weston_surface *surface,
+ GLfloat sx, GLfloat sy, GLfloat *x, GLfloat *y)
+{
+ struct geometry *g = surface->geometry;
+
+ /* pure rotation around origin by sine and cosine */
+ *x = g->c * sx + g->s * sy;
+ *y = -g->s * sx + g->c * sy;
+}
+
+/* ---------------------- copied begins -----------------------*/
+
+struct polygon8 {
+ GLfloat x[8];
+ GLfloat y[8];
+ int n;
+};
+
+struct clip_context {
+ struct {
+ GLfloat x;
+ GLfloat y;
+ } prev;
+
+ struct {
+ GLfloat x1, y1;
+ GLfloat x2, y2;
+ } clip;
+
+ struct {
+ GLfloat *x;
+ GLfloat *y;
+ } vertices;
+};
+
+static GLfloat
+float_difference(GLfloat a, GLfloat b)
+{
+ /* http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ */
+ static const GLfloat max_diff = 4.0f * FLT_MIN;
+ static const GLfloat max_rel_diff = 4.0e-5;
+ GLfloat diff = a - b;
+ GLfloat adiff = fabsf(diff);
+
+ if (adiff <= max_diff)
+ return 0.0f;
+
+ a = fabsf(a);
+ b = fabsf(b);
+ if (adiff <= (a > b ? a : b) * max_rel_diff)
+ return 0.0f;
+
+ return diff;
+}
+
+/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line x = x_arg.
+ * Compute the y coordinate of the intersection.
+ */
+static GLfloat
+clip_intersect_y(GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y,
+ GLfloat x_arg)
+{
+ GLfloat a;
+ GLfloat diff = float_difference(p1x, p2x);
+
+ /* Practically vertical line segment, yet the end points have already
+ * been determined to be on different sides of the line. Therefore
+ * the line segment is part of the line and intersects everywhere.
+ * Return the end point, so we use the whole line segment.
+ */
+ if (diff == 0.0f)
+ return p2y;
+
+ a = (x_arg - p2x) / diff;
+ return p2y + (p1y - p2y) * a;
+}
+
+/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line y = y_arg.
+ * Compute the x coordinate of the intersection.
+ */
+static GLfloat
+clip_intersect_x(GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y,
+ GLfloat y_arg)
+{
+ GLfloat a;
+ GLfloat diff = float_difference(p1y, p2y);
+
+ /* Practically horizontal line segment, yet the end points have already
+ * been determined to be on different sides of the line. Therefore
+ * the line segment is part of the line and intersects everywhere.
+ * Return the end point, so we use the whole line segment.
+ */
+ if (diff == 0.0f)
+ return p2x;
+
+ a = (y_arg - p2y) / diff;
+ return p2x + (p1x - p2x) * a;
+}
+
+enum path_transition {
+ PATH_TRANSITION_OUT_TO_OUT = 0,
+ PATH_TRANSITION_OUT_TO_IN = 1,
+ PATH_TRANSITION_IN_TO_OUT = 2,
+ PATH_TRANSITION_IN_TO_IN = 3,
+};
+
+static void
+clip_append_vertex(struct clip_context *ctx, GLfloat x, GLfloat y)
+{
+ *ctx->vertices.x++ = x;
+ *ctx->vertices.y++ = y;
+}
+
+static enum path_transition
+path_transition_left_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+{
+ return ((ctx->prev.x >= ctx->clip.x1) << 1) | (x >= ctx->clip.x1);
+}
+
+static enum path_transition
+path_transition_right_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+{
+ return ((ctx->prev.x < ctx->clip.x2) << 1) | (x < ctx->clip.x2);
+}
+
+static enum path_transition
+path_transition_top_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+{
+ return ((ctx->prev.y >= ctx->clip.y1) << 1) | (y >= ctx->clip.y1);
+}
+
+static enum path_transition
+path_transition_bottom_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+{
+ return ((ctx->prev.y < ctx->clip.y2) << 1) | (y < ctx->clip.y2);
+}
+
+static void
+clip_polygon_leftright(struct clip_context *ctx,
+ enum path_transition transition,
+ GLfloat x, GLfloat y, GLfloat clip_x)
+{
+ GLfloat yi;
+
+ switch (transition) {
+ case PATH_TRANSITION_IN_TO_IN:
+ clip_append_vertex(ctx, x, y);
+ break;
+ case PATH_TRANSITION_IN_TO_OUT:
+ yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
+ clip_append_vertex(ctx, clip_x, yi);
+ break;
+ case PATH_TRANSITION_OUT_TO_IN:
+ yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
+ clip_append_vertex(ctx, clip_x, yi);
+ clip_append_vertex(ctx, x, y);
+ break;
+ case PATH_TRANSITION_OUT_TO_OUT:
+ /* nothing */
+ break;
+ default:
+ assert(0 && "bad enum path_transition");
+ }
+
+ ctx->prev.x = x;
+ ctx->prev.y = y;
+}
+
+static void
+clip_polygon_topbottom(struct clip_context *ctx,
+ enum path_transition transition,
+ GLfloat x, GLfloat y, GLfloat clip_y)
+{
+ GLfloat xi;
+
+ switch (transition) {
+ case PATH_TRANSITION_IN_TO_IN:
+ clip_append_vertex(ctx, x, y);
+ break;
+ case PATH_TRANSITION_IN_TO_OUT:
+ xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
+ clip_append_vertex(ctx, xi, clip_y);
+ break;
+ case PATH_TRANSITION_OUT_TO_IN:
+ xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
+ clip_append_vertex(ctx, xi, clip_y);
+ clip_append_vertex(ctx, x, y);
+ break;
+ case PATH_TRANSITION_OUT_TO_OUT:
+ /* nothing */
+ break;
+ default:
+ assert(0 && "bad enum path_transition");
+ }
+
+ ctx->prev.x = x;
+ ctx->prev.y = y;
+}
+
+static void
+clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
+ GLfloat *dst_x, GLfloat *dst_y)
+{
+ ctx->prev.x = src->x[src->n - 1];
+ ctx->prev.y = src->y[src->n - 1];
+ ctx->vertices.x = dst_x;
+ ctx->vertices.y = dst_y;
+}
+
+static int
+clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
+ GLfloat *dst_x, GLfloat *dst_y)
+{
+ enum path_transition trans;
+ int i;
+
+ clip_context_prepare(ctx, src, dst_x, dst_y);
+ for (i = 0; i < src->n; i++) {
+ trans = path_transition_left_edge(ctx, src->x[i], src->y[i]);
+ clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
+ ctx->clip.x1);
+ }
+ return ctx->vertices.x - dst_x;
+}
+
+static int
+clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
+ GLfloat *dst_x, GLfloat *dst_y)
+{
+ enum path_transition trans;
+ int i;
+
+ clip_context_prepare(ctx, src, dst_x, dst_y);
+ for (i = 0; i < src->n; i++) {
+ trans = path_transition_right_edge(ctx, src->x[i], src->y[i]);
+ clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
+ ctx->clip.x2);
+ }
+ return ctx->vertices.x - dst_x;
+}
+
+static int
+clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
+ GLfloat *dst_x, GLfloat *dst_y)
+{
+ enum path_transition trans;
+ int i;
+
+ clip_context_prepare(ctx, src, dst_x, dst_y);
+ for (i = 0; i < src->n; i++) {
+ trans = path_transition_top_edge(ctx, src->x[i], src->y[i]);
+ clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
+ ctx->clip.y1);
+ }
+ return ctx->vertices.x - dst_x;
+}
+
+static int
+clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
+ GLfloat *dst_x, GLfloat *dst_y)
+{
+ enum path_transition trans;
+ int i;
+
+ clip_context_prepare(ctx, src, dst_x, dst_y);
+ for (i = 0; i < src->n; i++) {
+ trans = path_transition_bottom_edge(ctx, src->x[i], src->y[i]);
+ clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
+ ctx->clip.y2);
+ }
+ return ctx->vertices.x - dst_x;
+}
+
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+#define min(a, b) (((a) > (b)) ? (b) : (a))
+#define clip(x, a, b) min(max(x, a), b)
+
+/*
+ * Compute the boundary vertices of the intersection of the global coordinate
+ * aligned rectangle 'rect', and an arbitrary quadrilateral produced from
+ * 'surf_rect' when transformed from surface coordinates into global coordinates.
+ * The vertices are written to 'ex' and 'ey', and the return value is the
+ * number of vertices. Vertices are produced in clockwise winding order.
+ * Guarantees to produce either zero vertices, or 3-8 vertices with non-zero
+ * polygon area.
+ */
+static int
+calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
+ pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
+{
+ struct polygon8 polygon;
+ struct clip_context ctx;
+ int i, n;
+ GLfloat min_x, max_x, min_y, max_y;
+ struct polygon8 surf = {
+ { surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1 },
+ { surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2 },
+ 4
+ };
+
+ ctx.clip.x1 = rect->x1;
+ ctx.clip.y1 = rect->y1;
+ ctx.clip.x2 = rect->x2;
+ ctx.clip.y2 = rect->y2;
+
+ /* transform surface to screen space: */
+ for (i = 0; i < surf.n; i++)
+ weston_surface_to_global_float(es, surf.x[i], surf.y[i],
+ &surf.x[i], &surf.y[i]);
+
+ /* find bounding box: */
+ min_x = max_x = surf.x[0];
+ min_y = max_y = surf.y[0];
+
+ for (i = 1; i < surf.n; i++) {
+ min_x = min(min_x, surf.x[i]);
+ max_x = max(max_x, surf.x[i]);
+ min_y = min(min_y, surf.y[i]);
+ max_y = max(max_y, surf.y[i]);
+ }
+
+ /* First, simple bounding box check to discard early transformed
+ * surface rects that do not intersect with the clip region:
+ */
+ if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
+ (min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
+ return 0;
+
+ /* Simple case, bounding box edges are parallel to surface edges,
+ * there will be only four edges. We just need to clip the surface
+ * vertices to the clip rect bounds:
+ */
+ if (!es->transform.enabled) {
+ for (i = 0; i < surf.n; i++) {
+ ex[i] = clip(surf.x[i], ctx.clip.x1, ctx.clip.x2);
+ ey[i] = clip(surf.y[i], ctx.clip.y1, ctx.clip.y2);
+ }
+ return surf.n;
+ }
+
+ /* Transformed case: use a general polygon clipping algorithm to
+ * clip the surface rectangle with each side of 'rect'.
+ * The algorithm is Sutherland-Hodgman, as explained in
+ * http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
+ * but without looking at any of that code.
+ */
+ polygon.n = clip_polygon_left(&ctx, &surf, polygon.x, polygon.y);
+ surf.n = clip_polygon_right(&ctx, &polygon, surf.x, surf.y);
+ polygon.n = clip_polygon_top(&ctx, &surf, polygon.x, polygon.y);
+ surf.n = clip_polygon_bottom(&ctx, &polygon, surf.x, surf.y);
+
+ /* Get rid of duplicate vertices */
+ ex[0] = surf.x[0];
+ ey[0] = surf.y[0];
+ n = 1;
+ for (i = 1; i < surf.n; i++) {
+ if (float_difference(ex[n - 1], surf.x[i]) == 0.0f &&
+ float_difference(ey[n - 1], surf.y[i]) == 0.0f)
+ continue;
+ ex[n] = surf.x[i];
+ ey[n] = surf.y[i];
+ n++;
+ }
+ if (float_difference(ex[n - 1], surf.x[0]) == 0.0f &&
+ float_difference(ey[n - 1], surf.y[0]) == 0.0f)
+ n--;
+
+ if (n < 3)
+ return 0;
+
+ return n;
+}
+
+
+/* ---------------------- copied ends -----------------------*/
+
+static void
+geometry_set_phi(struct geometry *g, float phi)
+{
+ g->phi = phi;
+ g->s = sin(phi);
+ g->c = cos(phi);
+}
+
+static void
+geometry_init(struct geometry *g)
+{
+ g->clip.x1 = -50;
+ g->clip.y1 = -50;
+ g->clip.x2 = -10;
+ g->clip.y2 = -10;
+
+ g->surf.x1 = -20;
+ g->surf.y1 = -20;
+ g->surf.x2 = 20;
+ g->surf.y2 = 20;
+
+ geometry_set_phi(g, 0.0);
+}
+
+struct ui_state {
+ uint32_t button;
+ int down;
+
+ int down_pos[2];
+ struct geometry geometry;
+};
+
+struct cliptest {
+ struct window *window;
+ struct widget *widget;
+ struct display *display;
+ int fullscreen;
+
+ struct ui_state ui;
+
+ struct geometry geometry;
+ struct weston_surface surface;
+};
+
+static void
+draw_polygon_closed(cairo_t *cr, GLfloat *x, GLfloat *y, int n)
+{
+ int i;
+
+ cairo_move_to(cr, x[0], y[0]);
+ for (i = 1; i < n; i++)
+ cairo_line_to(cr, x[i], y[i]);
+ cairo_line_to(cr, x[0], y[0]);
+}
+
+static void
+draw_polygon_labels(cairo_t *cr, GLfloat *x, GLfloat *y, int n)
+{
+ char str[16];
+ int i;
+
+ for (i = 0; i < n; i++) {
+ snprintf(str, 16, "%d", i);
+ cairo_move_to(cr, x[i], y[i]);
+ cairo_show_text(cr, str);
+ }
+}
+
+static void
+draw_coordinates(cairo_t *cr, double ox, double oy, GLfloat *x, GLfloat *y, int n)
+{
+ char str[64];
+ int i;
+ cairo_font_extents_t ext;
+
+ cairo_font_extents(cr, &ext);
+ for (i = 0; i < n; i++) {
+ snprintf(str, 64, "%d: %14.9f, %14.9f", i, x[i], y[i]);
+ cairo_move_to(cr, ox, oy + ext.height * (i + 1));
+ cairo_show_text(cr, str);
+ }
+}
+
+static void
+draw_box(cairo_t *cr, pixman_box32_t *box, struct weston_surface *surface)
+{
+ GLfloat x[4], y[4];
+
+ if (surface) {
+ weston_surface_to_global_float(surface, box->x1, box->y1, &x[0], &y[0]);
+ weston_surface_to_global_float(surface, box->x2, box->y1, &x[1], &y[1]);
+ weston_surface_to_global_float(surface, box->x2, box->y2, &x[2], &y[2]);
+ weston_surface_to_global_float(surface, box->x1, box->y2, &x[3], &y[3]);
+ } else {
+ x[0] = box->x1; y[0] = box->y1;
+ x[1] = box->x2; y[1] = box->y1;
+ x[2] = box->x2; y[2] = box->y2;
+ x[3] = box->x1; y[3] = box->y2;
+ }
+
+ draw_polygon_closed(cr, x, y, 4);
+}
+
+static void
+draw_geometry(cairo_t *cr, struct weston_surface *surface,
+ GLfloat *ex, GLfloat *ey, int n)
+{
+ struct geometry *g = surface->geometry;
+ GLfloat cx, cy;
+
+ draw_box(cr, &g->surf, surface);
+ cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4);
+ cairo_fill(cr);
+ weston_surface_to_global_float(surface, g->surf.x1 - 4, g->surf.y1 - 4, &cx, &cy);
+ cairo_arc(cr, cx, cy, 1.5, 0.0, 2.0 * M_PI);
+ if (surface->transform.enabled == 0)
+ cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.8);
+ cairo_fill(cr);
+
+ draw_box(cr, &g->clip, NULL);
+ cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.4);
+ cairo_fill(cr);
+
+ draw_polygon_closed(cr, ex, ey, n);
+ cairo_set_source_rgb(cr, 0.0, 1.0, 0.0);
+ cairo_stroke(cr);
+
+ cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.5);
+ draw_polygon_labels(cr, ex, ey, n);
+}
+
+static void
+redraw_handler(struct widget *widget, void *data)
+{
+ struct cliptest *cliptest = data;
+ struct geometry *g = cliptest->surface.geometry;
+ struct rectangle allocation;
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ GLfloat ex[8];
+ GLfloat ey[8];
+ int n;
+
+ n = calculate_edges(&cliptest->surface, &g->clip, &g->surf, ex, ey);
+
+ widget_get_allocation(cliptest->widget, &allocation);
+
+ surface = window_get_surface(cliptest->window);
+ cr = cairo_create(surface);
+ widget_get_allocation(cliptest->widget, &allocation);
+ cairo_rectangle(cr, allocation.x, allocation.y,
+ allocation.width, allocation.height);
+ cairo_clip(cr);
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgba(cr, 0, 0, 0, 1);
+ cairo_paint(cr);
+
+ cairo_translate(cr, allocation.x, allocation.y);
+ cairo_set_line_width(cr, 1.0);
+ cairo_move_to(cr, allocation.width / 2.0, 0.0);
+ cairo_line_to(cr, allocation.width / 2.0, allocation.height);
+ cairo_move_to(cr, 0.0, allocation.height / 2.0);
+ cairo_line_to(cr, allocation.width, allocation.height / 2.0);
+ cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1.0);
+ cairo_stroke(cr);
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+ cairo_push_group(cr);
+ cairo_translate(cr, allocation.width / 2.0,
+ allocation.height / 2.0);
+ cairo_scale(cr, 4.0, 4.0);
+ cairo_set_line_width(cr, 0.5);
+ cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL);
+ cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_BOLD);
+ cairo_set_font_size(cr, 5.0);
+ draw_geometry(cr, &cliptest->surface, ex, ey, n);
+ cairo_pop_group_to_source(cr);
+ cairo_paint(cr);
+
+ cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 1.0);
+ cairo_select_font_face(cr, "monospace", CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_set_font_size(cr, 12.0);
+ draw_coordinates(cr, 10.0, 10.0, ex, ey, n);
+
+ cairo_destroy(cr);
+
+ cairo_surface_destroy(surface);
+}
+
+static int
+motion_handler(struct widget *widget, struct input *input,
+ uint32_t time, float x, float y, void *data)
+{
+ struct cliptest *cliptest = data;
+ struct ui_state *ui = &cliptest->ui;
+ struct geometry *ref = &ui->geometry;
+ struct geometry *geom = &cliptest->geometry;
+ float dx, dy;
+
+ if (!ui->down)
+ return CURSOR_LEFT_PTR;
+
+ dx = (x - ui->down_pos[0]) * 0.25;
+ dy = (y - ui->down_pos[1]) * 0.25;
+
+ switch (ui->button) {
+ case BTN_LEFT:
+ geom->clip.x1 = ref->clip.x1 + dx;
+ geom->clip.y1 = ref->clip.y1 + dy;
+ /* fall through */
+ case BTN_RIGHT:
+ geom->clip.x2 = ref->clip.x2 + dx;
+ geom->clip.y2 = ref->clip.y2 + dy;
+ break;
+ default:
+ return CURSOR_LEFT_PTR;
+ }
+
+ widget_schedule_redraw(cliptest->widget);
+ return CURSOR_BLANK;
+}
+
+static void
+button_handler(struct widget *widget, struct input *input,
+ uint32_t time, uint32_t button,
+ enum wl_pointer_button_state state, void *data)
+{
+ struct cliptest *cliptest = data;
+ struct ui_state *ui = &cliptest->ui;
+
+ ui->button = button;
+
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ ui->down = 1;
+ input_get_position(input, &ui->down_pos[0], &ui->down_pos[1]);
+ } else {
+ ui->down = 0;
+ ui->geometry = cliptest->geometry;
+ }
+}
+
+static void
+axis_handler(struct widget *widget, struct input *input, uint32_t time,
+ uint32_t axis, wl_fixed_t value, void *data)
+{
+ struct cliptest *cliptest = data;
+ struct geometry *geom = &cliptest->geometry;
+
+ if (axis != WL_POINTER_AXIS_VERTICAL_SCROLL)
+ return;
+
+ geometry_set_phi(geom, geom->phi +
+ (M_PI / 12.0) * wl_fixed_to_double(value));
+ cliptest->surface.transform.enabled = 1;
+
+ widget_schedule_redraw(cliptest->widget);
+}
+
+static void
+key_handler(struct window *window, struct input *input, uint32_t time,
+ uint32_t key, uint32_t sym,
+ enum wl_keyboard_key_state state, void *data)
+{
+ struct cliptest *cliptest = data;
+ struct geometry *g = &cliptest->geometry;
+
+ if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
+ return;
+
+ switch (sym) {
+ case XKB_KEY_Escape:
+ display_exit(cliptest->display);
+ return;
+ case XKB_KEY_w:
+ g->clip.y1 -= 1;
+ g->clip.y2 -= 1;
+ break;
+ case XKB_KEY_a:
+ g->clip.x1 -= 1;
+ g->clip.x2 -= 1;
+ break;
+ case XKB_KEY_s:
+ g->clip.y1 += 1;
+ g->clip.y2 += 1;
+ break;
+ case XKB_KEY_d:
+ g->clip.x1 += 1;
+ g->clip.x2 += 1;
+ break;
+ case XKB_KEY_i:
+ g->clip.y2 -= 1;
+ break;
+ case XKB_KEY_j:
+ g->clip.x2 -= 1;
+ break;
+ case XKB_KEY_k:
+ g->clip.y2 += 1;
+ break;
+ case XKB_KEY_l:
+ g->clip.x2 += 1;
+ break;
+ case XKB_KEY_n:
+ geometry_set_phi(g, g->phi + (M_PI / 24.0));
+ cliptest->surface.transform.enabled = 1;
+ break;
+ case XKB_KEY_m:
+ geometry_set_phi(g, g->phi - (M_PI / 24.0));
+ cliptest->surface.transform.enabled = 1;
+ break;
+ case XKB_KEY_r:
+ geometry_set_phi(g, 0.0);
+ cliptest->surface.transform.enabled = 0;
+ break;
+ default:
+ return;
+ }
+
+ widget_schedule_redraw(cliptest->widget);
+}
+
+static void
+keyboard_focus_handler(struct window *window,
+ struct input *device, void *data)
+{
+ struct cliptest *cliptest = data;
+
+ window_schedule_redraw(cliptest->window);
+}
+
+static void
+fullscreen_handler(struct window *window, void *data)
+{
+ struct cliptest *cliptest = data;
+
+ cliptest->fullscreen ^= 1;
+ window_set_fullscreen(window, cliptest->fullscreen);
+}
+
+static struct cliptest *
+cliptest_create(struct display *display)
+{
+ struct cliptest *cliptest;
+
+ cliptest = malloc(sizeof *cliptest);
+ if (cliptest == NULL)
+ return cliptest;
+ memset(cliptest, 0, sizeof *cliptest);
+
+ cliptest->surface.geometry = &cliptest->geometry;
+ cliptest->surface.transform.enabled = 0;
+ geometry_init(&cliptest->geometry);
+ geometry_init(&cliptest->ui.geometry);
+
+ cliptest->window = window_create(display);
+ cliptest->widget = frame_create(cliptest->window, cliptest);
+ window_set_title(cliptest->window, "cliptest");
+ cliptest->display = display;
+
+ window_set_user_data(cliptest->window, cliptest);
+ widget_set_redraw_handler(cliptest->widget, redraw_handler);
+ widget_set_button_handler(cliptest->widget, button_handler);
+ widget_set_motion_handler(cliptest->widget, motion_handler);
+ widget_set_axis_handler(cliptest->widget, axis_handler);
+
+ window_set_keyboard_focus_handler(cliptest->window,
+ keyboard_focus_handler);
+ window_set_key_handler(cliptest->window, key_handler);
+ window_set_fullscreen_handler(cliptest->window, fullscreen_handler);
+
+ /* set minimum size */
+ widget_schedule_resize(cliptest->widget, 200, 100);
+
+ /* set current size */
+ widget_schedule_resize(cliptest->widget, 500, 400);
+
+ return cliptest;
+}
+
+static struct timespec begin_time;
+
+static void
+reset_timer(void)
+{
+ clock_gettime(CLOCK_MONOTONIC, &begin_time);
+}
+
+static double
+read_timer(void)
+{
+ struct timespec t;
+
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return (double)(t.tv_sec - begin_time.tv_sec) +
+ 1e-9 * (t.tv_nsec - begin_time.tv_nsec);
+}
+
+static int
+benchmark(void)
+{
+ struct weston_surface surface;
+ struct geometry geom;
+ GLfloat ex[8], ey[8];
+ int i;
+ double t;
+ const int N = 1000000;
+
+ geom.clip.x1 = -19;
+ geom.clip.y1 = -19;
+ geom.clip.x2 = 19;
+ geom.clip.y2 = 19;
+
+ geom.surf.x1 = -20;
+ geom.surf.y1 = -20;
+ geom.surf.x2 = 20;
+ geom.surf.y2 = 20;
+
+ geometry_set_phi(&geom, 0.0);
+
+ surface.transform.enabled = 1;
+ surface.geometry = &geom;
+
+ reset_timer();
+ for (i = 0; i < N; i++) {
+ geometry_set_phi(&geom, (float)i / 360.0f);
+ calculate_edges(&surface, &geom.clip, &geom.surf, ex, ey);
+ }
+ t = read_timer();
+
+ printf("%d calls took %g s, average %g us/call\n", N, t, t / N * 1e6);
+
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct display *d;
+ struct cliptest *cliptest;
+
+ if (argc > 1)
+ return benchmark();
+
+ d = display_create(argc, argv);
+ if (d == NULL) {
+ fprintf(stderr, "failed to create display: %m\n");
+ return -1;
+ }
+
+ cliptest = cliptest_create(d);
+ display_run(d);
+
+ widget_destroy(cliptest->widget);
+ window_destroy(cliptest->window);
+ free(cliptest);
+
+ return 0;
+}
diff --git a/clients/editor.c b/clients/editor.c
index a5347fe..301cbe2 100644
--- a/clients/editor.c
+++ b/clients/editor.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2012 Openismus GmbH
+ * Copyright © 2012 Intel Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
@@ -31,13 +32,29 @@
#include "window.h"
#include "text-client-protocol.h"
+static const char *font_name = "sans-serif";
+static int font_size = 14;
+
+struct text_layout {
+ cairo_glyph_t *glyphs;
+ int num_glyphs;
+ cairo_text_cluster_t *clusters;
+ int num_clusters;
+ cairo_text_cluster_flags_t cluster_flags;
+ cairo_scaled_font_t *font;
+};
+
struct text_entry {
struct widget *widget;
struct window *window;
char *text;
int active;
- struct rectangle allocation;
+ uint32_t cursor;
+ uint32_t anchor;
+ char *preedit_text;
+ uint32_t preedit_cursor;
struct text_model *model;
+ struct text_layout *layout;
};
struct editor {
@@ -49,13 +66,154 @@ struct editor {
struct text_entry *editor;
};
+static struct text_layout *
+text_layout_create(void)
+{
+ struct text_layout *layout;
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ layout = malloc(sizeof *layout);
+ if (!layout)
+ return NULL;
+
+ layout->glyphs = NULL;
+ layout->num_glyphs = 0;
+
+ layout->clusters = NULL;
+ layout->num_clusters = 0;
+
+ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
+ cr = cairo_create(surface);
+ cairo_set_font_size(cr, font_size);
+ cairo_select_font_face(cr, font_name, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
+ layout->font = cairo_get_scaled_font(cr);
+ cairo_scaled_font_reference(layout->font);
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+
+ return layout;
+}
+
static void
-text_entry_append(struct text_entry *entry, const char *text)
+text_layout_destroy(struct text_layout *layout)
{
- entry->text = realloc(entry->text, strlen(entry->text) + strlen(text) + 1);
- strcat(entry->text, text);
+ if (layout->glyphs)
+ cairo_glyph_free(layout->glyphs);
+
+ if (layout->clusters)
+ cairo_text_cluster_free(layout->clusters);
+
+ cairo_scaled_font_destroy(layout->font);
+
+ free(layout);
}
+static void
+text_layout_set_text(struct text_layout *layout,
+ const char *text)
+{
+ if (layout->glyphs)
+ cairo_glyph_free(layout->glyphs);
+
+ if (layout->clusters)
+ cairo_text_cluster_free(layout->clusters);
+
+ layout->glyphs = NULL;
+ layout->num_glyphs = 0;
+ layout->clusters = NULL;
+ layout->num_clusters = 0;
+
+ cairo_scaled_font_text_to_glyphs(layout->font, 0, 0, text, -1,
+ &layout->glyphs, &layout->num_glyphs,
+ &layout->clusters, &layout->num_clusters,
+ &layout->cluster_flags);
+}
+
+static void
+text_layout_draw(struct text_layout *layout, cairo_t *cr)
+{
+ cairo_save(cr);
+ cairo_set_scaled_font(cr, layout->font);
+ cairo_show_glyphs(cr, layout->glyphs, layout->num_glyphs);
+ cairo_restore(cr);
+}
+
+static void
+text_layout_extents(struct text_layout *layout, cairo_text_extents_t *extents)
+{
+ cairo_scaled_font_glyph_extents(layout->font,
+ layout->glyphs, layout->num_glyphs,
+ extents);
+}
+
+static int
+text_layout_xy_to_index(struct text_layout *layout, double x, double y)
+{
+ cairo_text_extents_t extents;
+ int i;
+
+ cairo_scaled_font_glyph_extents(layout->font,
+ layout->glyphs, layout->num_glyphs,
+ &extents);
+
+ for (i = 1; i < layout->num_glyphs; i++) {
+ if (layout->glyphs[i].x >= x) {
+ return i - 1;
+ }
+ }
+
+ if (x >= layout->glyphs[layout->num_glyphs - 1].x && x < extents.width)
+ return layout->num_glyphs - 1;
+
+ return layout->num_glyphs;
+}
+
+static void
+text_layout_index_to_pos(struct text_layout *layout, uint32_t index, cairo_rectangle_t *pos)
+{
+ cairo_text_extents_t extents;
+
+ if (!pos)
+ return;
+
+ cairo_scaled_font_glyph_extents(layout->font,
+ layout->glyphs, layout->num_glyphs,
+ &extents);
+
+ if ((int)index >= layout->num_glyphs) {
+ pos->x = extents.x_advance;
+ pos->y = layout->num_glyphs ? layout->glyphs[layout->num_glyphs - 1].y : 0;
+ pos->width = 1;
+ pos->height = extents.height;
+ return;
+ }
+
+ pos->x = layout->glyphs[index].x;
+ pos->y = layout->glyphs[index].y;
+ pos->width = (int)index < layout->num_glyphs - 1 ? layout->glyphs[index + 1].x : extents.x_advance - pos->x;
+ pos->height = extents.height;
+}
+
+static void
+text_layout_get_cursor_pos(struct text_layout *layout, int index, cairo_rectangle_t *pos)
+{
+ text_layout_index_to_pos(layout, index, pos);
+ pos->width = 1;
+}
+
+static void text_entry_redraw_handler(struct widget *widget, void *data);
+static void text_entry_button_handler(struct widget *widget,
+ struct input *input, uint32_t time,
+ uint32_t button,
+ enum wl_pointer_button_state state, void *data);
+static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text);
+static void text_entry_set_preedit(struct text_entry *entry,
+ const char *preedit_text,
+ int preedit_cursor);
+static void text_entry_delete_text(struct text_entry *entry,
+ uint32_t index, uint32_t length);
static void
text_model_commit_string(void *data,
@@ -65,7 +223,12 @@ text_model_commit_string(void *data,
{
struct text_entry *entry = data;
- text_entry_append(entry, text);
+ if (index > strlen(text)) {
+ fprintf(stderr, "Invalid cursor index %d\n", index);
+ index = strlen(text);
+ }
+
+ text_entry_insert_at_cursor(entry, text);
widget_schedule_redraw(entry->widget);
}
@@ -76,6 +239,41 @@ text_model_preedit_string(void *data,
const char *text,
uint32_t index)
{
+ struct text_entry *entry = data;
+
+ if (index > strlen(text)) {
+ fprintf(stderr, "Invalid cursor index %d\n", index);
+ index = strlen(text);
+ }
+
+ text_entry_set_preedit(entry, text, index);
+
+ widget_schedule_redraw(entry->widget);
+}
+
+static void
+text_model_delete_surrounding_text(void *data,
+ struct text_model *text_model,
+ int32_t index,
+ uint32_t length)
+{
+ struct text_entry *entry = data;
+ uint32_t cursor_index = index + entry->cursor;
+
+ if (cursor_index > strlen(entry->text)) {
+ fprintf(stderr, "Invalid cursor index %d\n", index);
+ return;
+ }
+
+ if (cursor_index + length > strlen(entry->text)) {
+ fprintf(stderr, "Invalid length %d\n", length);
+ return;
+ }
+
+ if (length == 0)
+ return;
+
+ text_entry_delete_text(entry, cursor_index, length);
}
static void
@@ -86,8 +284,31 @@ text_model_preedit_styling(void *data,
static void
text_model_key(void *data,
- struct text_model *text_model)
+ struct text_model *text_model,
+ uint32_t key,
+ uint32_t state)
{
+ const char *state_label;
+ const char *key_label;
+
+ if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ state_label = "pressed";
+ } else {
+ state_label = "released";
+ }
+
+ switch (key) {
+ case XKB_KEY_Tab:
+ key_label = "Tab";
+ break;
+ case XKB_KEY_KP_Enter:
+ key_label = "Enter";
+ break;
+ default:
+ key_label = "Unknown";
+ }
+
+ fprintf(stderr, "%s key was %s.\n", key_label, state_label);
}
static void
@@ -133,6 +354,7 @@ text_model_deactivated(void *data,
static const struct text_model_listener text_model_listener = {
text_model_commit_string,
text_model_preedit_string,
+ text_model_delete_surrounding_text,
text_model_preedit_styling,
text_model_key,
text_model_selection_replacement,
@@ -146,62 +368,40 @@ static struct text_entry*
text_entry_create(struct editor *editor, const char *text)
{
struct text_entry *entry;
- struct wl_surface *surface;
entry = malloc(sizeof *entry);
- surface = window_get_wl_surface(editor->window);
-
- entry->widget = editor->widget;
+ entry->widget = widget_add_widget(editor->widget, entry);
entry->window = editor->window;
entry->text = strdup(text);
entry->active = 0;
- entry->model = text_model_factory_create_text_model(editor->text_model_factory, surface);
+ entry->cursor = strlen(text);
+ entry->anchor = entry->cursor;
+ entry->preedit_text = NULL;
+ entry->preedit_cursor = 0;
+ entry->model = text_model_factory_create_text_model(editor->text_model_factory);
text_model_add_listener(entry->model, &text_model_listener, entry);
+ entry->layout = text_layout_create();
+ text_layout_set_text(entry->layout, entry->text);
+
+ widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
+ widget_set_button_handler(entry->widget, text_entry_button_handler);
+
return entry;
}
static void
text_entry_destroy(struct text_entry *entry)
{
+ widget_destroy(entry->widget);
text_model_destroy(entry->model);
+ text_layout_destroy(entry->layout);
free(entry->text);
free(entry);
}
static void
-text_entry_draw(struct text_entry *entry, cairo_t *cr)
-{
- cairo_save(cr);
- cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-
- cairo_rectangle(cr, entry->allocation.x, entry->allocation.y, entry->allocation.width, entry->allocation.height);
- cairo_clip(cr);
-
- cairo_translate(cr, entry->allocation.x, entry->allocation.y);
- cairo_rectangle(cr, 0, 0, entry->allocation.width, entry->allocation.height);
- cairo_set_source_rgba(cr, 1, 1, 1, 0.5);
- cairo_fill(cr);
- if (entry->active) {
- cairo_rectangle(cr, 0, 0, entry->allocation.width, entry->allocation.height);
- cairo_set_source_rgba(cr, 0, 0, 1, 0.5);
- cairo_stroke(cr);
- }
-
- cairo_set_source_rgb(cr, 0, 0, 0);
- cairo_select_font_face(cr, "sans",
- CAIRO_FONT_SLANT_NORMAL,
- CAIRO_FONT_WEIGHT_BOLD);
- cairo_set_font_size(cr, 14);
-
- cairo_translate(cr, 10, entry->allocation.height / 2);
- cairo_show_text(cr, entry->text);
-
- cairo_restore(cr);
-}
-
-static void
redraw_handler(struct widget *widget, void *data)
{
struct editor *editor = data;
@@ -220,17 +420,11 @@ redraw_handler(struct widget *widget, void *data)
/* Draw background */
cairo_push_group(cr);
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 1, 1, 1, 1);
cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
cairo_fill(cr);
- /* Entry */
- text_entry_draw(editor->entry, cr);
-
- /* Editor */
- text_entry_draw(editor->editor, cr);
-
cairo_pop_group_to_source(cr);
cairo_paint(cr);
@@ -242,10 +436,7 @@ static void
text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
int32_t width, int32_t height)
{
- entry->allocation.x = x;
- entry->allocation.y = y;
- entry->allocation.width = width;
- entry->allocation.height = height;
+ widget_set_allocation(entry->widget, x, y, width, height);
}
static void
@@ -253,28 +444,21 @@ resize_handler(struct widget *widget,
int32_t width, int32_t height, void *data)
{
struct editor *editor = data;
+ struct rectangle allocation;
- text_entry_allocate(editor->entry, 20, 20, width - 40, height / 2 - 40);
- text_entry_allocate(editor->editor, 20, height / 2 + 20, width - 40, height / 2 - 40);
-}
-
-static int32_t
-rectangle_contains(struct rectangle *rectangle, int32_t x, int32_t y)
-{
- if (x < rectangle->x || x > rectangle->x + rectangle->width) {
- return 0;
- }
-
- if (y < rectangle->y || y > rectangle->y + rectangle->height) {
- return 0;
- }
+ widget_get_allocation(editor->widget, &allocation);
- return 1;
+ text_entry_allocate(editor->entry,
+ allocation.x + 20, allocation.y + 20,
+ width - 40, height / 2 - 40);
+ text_entry_allocate(editor->editor,
+ allocation.x + 20, allocation.y + height / 2 + 20,
+ width - 40, height / 2 - 40);
}
static void
text_entry_activate(struct text_entry *entry,
- struct wl_seat *seat)
+ struct wl_seat *seat)
{
struct wl_surface *surface = window_get_wl_surface(entry->window);
@@ -292,42 +476,315 @@ text_entry_deactivate(struct text_entry *entry,
}
static void
-button_handler(struct widget *widget,
- struct input *input, uint32_t time,
- uint32_t button,
- enum wl_pointer_button_state state, void *data)
+text_entry_update_layout(struct text_entry *entry)
{
- struct editor *editor = data;
+ char *text;
+
+ assert(((unsigned int)entry->cursor) <= strlen(entry->text));
+
+ if (!entry->preedit_text) {
+ text_layout_set_text(entry->layout, entry->text);
+ return;
+ }
+
+ text = malloc(strlen(entry->text) + strlen(entry->preedit_text) + 1);
+ strncpy(text, entry->text, entry->cursor);
+ strcpy(text + entry->cursor, entry->preedit_text);
+ strcpy(text + entry->cursor + strlen(entry->preedit_text),
+ entry->text + entry->cursor);
+
+ text_layout_set_text(entry->layout, text);
+ free(text);
+
+ widget_schedule_redraw(entry->widget);
+
+ text_model_set_surrounding_text(entry->model,
+ entry->text,
+ entry->cursor,
+ entry->anchor);
+}
+
+static void
+text_entry_insert_at_cursor(struct text_entry *entry, const char *text)
+{
+ char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
+
+ strncpy(new_text, entry->text, entry->cursor);
+ strcpy(new_text + entry->cursor, text);
+ strcpy(new_text + entry->cursor + strlen(text),
+ entry->text + entry->cursor);
+
+ free(entry->text);
+ entry->text = new_text;
+ entry->cursor += strlen(text);
+ entry->anchor += strlen(text);
+
+ text_entry_update_layout(entry);
+}
+
+static void
+text_entry_set_preedit(struct text_entry *entry,
+ const char *preedit_text,
+ int preedit_cursor)
+{
+ if (entry->preedit_text) {
+ free(entry->preedit_text);
+ entry->preedit_text = NULL;
+ entry->preedit_cursor = 0;
+ }
+
+ if (!preedit_text)
+ return;
+
+ entry->preedit_text = strdup(preedit_text);
+ entry->preedit_cursor = preedit_cursor;
+
+ text_entry_update_layout(entry);
+}
+
+static void
+text_entry_set_cursor_position(struct text_entry *entry,
+ int32_t x, int32_t y)
+{
+ entry->cursor = text_layout_xy_to_index(entry->layout, x, y);
+
+ text_model_reset(entry->model);
+
+ if (entry->cursor >= entry->preedit_cursor) {
+ entry->cursor -= entry->preedit_cursor;
+ }
+
+ text_entry_update_layout(entry);
+
+ widget_schedule_redraw(entry->widget);
+}
+
+static void
+text_entry_set_anchor_position(struct text_entry *entry,
+ int32_t x, int32_t y)
+{
+ entry->anchor = text_layout_xy_to_index(entry->layout, x, y);
+
+ widget_schedule_redraw(entry->widget);
+}
+
+static void
+text_entry_delete_text(struct text_entry *entry,
+ uint32_t index, uint32_t length)
+{
+ if (entry->cursor > index)
+ entry->cursor -= length;
+
+ entry->text[index] = '\0';
+ strcat(entry->text, entry->text + index + length);
+
+ text_entry_update_layout(entry);
+
+ widget_schedule_redraw(entry->widget);
+}
+
+static void
+text_entry_draw_selection(struct text_entry *entry, cairo_t *cr)
+{
+ cairo_text_extents_t extents;
+ uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
+ uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
+ cairo_rectangle_t start;
+ cairo_rectangle_t end;
+
+ if (entry->anchor == entry->cursor)
+ return;
+
+ text_layout_extents(entry->layout, &extents);
+
+ text_layout_index_to_pos(entry->layout, start_index, &start);
+ text_layout_index_to_pos(entry->layout, end_index, &end);
+
+ cairo_save (cr);
+
+ cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 1.0);
+ cairo_rectangle(cr,
+ start.x, extents.y_bearing + extents.height + 2,
+ end.x - start.x, -extents.height - 4);
+ cairo_fill(cr);
+
+ cairo_rectangle(cr,
+ start.x, extents.y_bearing + extents.height,
+ end.x - start.x, -extents.height);
+ cairo_clip(cr);
+ cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
+ text_layout_draw(entry->layout, cr);
+
+ cairo_restore (cr);
+}
+
+static void
+text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
+{
+ cairo_text_extents_t extents;
+ cairo_rectangle_t cursor_pos;
+
+ text_layout_extents(entry->layout, &extents);
+ text_layout_get_cursor_pos(entry->layout,
+ entry->cursor + entry->preedit_cursor,
+ &cursor_pos);
+
+ cairo_set_line_width(cr, 1.0);
+ cairo_move_to(cr, cursor_pos.x, extents.y_bearing + extents.height + 2);
+ cairo_line_to(cr, cursor_pos.x, extents.y_bearing - 2);
+ cairo_stroke(cr);
+}
+
+static void
+text_entry_draw_preedit(struct text_entry *entry, cairo_t *cr)
+{
+ cairo_text_extents_t extents;
+ cairo_rectangle_t start;
+ cairo_rectangle_t end;
+
+ if (!entry->preedit_text)
+ return;
+
+ text_layout_extents(entry->layout, &extents);
+
+ text_layout_index_to_pos(entry->layout, entry->cursor, &start);
+ text_layout_index_to_pos(entry->layout,
+ entry->cursor + strlen(entry->preedit_text),
+ &end);
+
+ cairo_save (cr);
+
+ cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
+ cairo_rectangle(cr,
+ start.x, 0,
+ end.x - start.x, 1);
+ cairo_fill(cr);
+
+ cairo_restore (cr);
+}
+
+static void
+text_entry_redraw_handler(struct widget *widget, void *data)
+{
+ struct text_entry *entry = data;
+ cairo_surface_t *surface;
+ struct rectangle allocation;
+ cairo_t *cr;
+
+ surface = window_get_surface(entry->window);
+ widget_get_allocation(entry->widget, &allocation);
+
+ cr = cairo_create(surface);
+ cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
+ cairo_clip(cr);
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+
+ cairo_push_group(cr);
+ cairo_translate(cr, allocation.x, allocation.y);
+
+ cairo_set_source_rgba(cr, 1, 1, 1, 1);
+ cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
+ cairo_fill(cr);
+
+ cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
+
+ if (entry->active) {
+ cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
+ cairo_set_line_width (cr, 3);
+ cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
+ cairo_stroke(cr);
+ }
+
+ cairo_set_source_rgba(cr, 0, 0, 0, 1);
+
+ cairo_translate(cr, 10, allocation.height / 2);
+ text_layout_draw(entry->layout, cr);
+
+ text_entry_draw_selection(entry, cr);
+
+ text_entry_draw_cursor(entry, cr);
+
+ text_entry_draw_preedit(entry, cr);
+
+ cairo_pop_group_to_source(cr);
+ cairo_paint(cr);
+
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+}
+
+static int
+text_entry_motion_handler(struct widget *widget,
+ struct input *input, uint32_t time,
+ float x, float y, void *data)
+{
+ struct text_entry *entry = data;
+ struct rectangle allocation;
+
+ widget_get_allocation(entry->widget, &allocation);
+
+ text_entry_set_cursor_position(entry,
+ x - allocation.x,
+ y - allocation.y);
+
+ return CURSOR_IBEAM;
+}
+
+static void
+text_entry_button_handler(struct widget *widget,
+ struct input *input, uint32_t time,
+ uint32_t button,
+ enum wl_pointer_button_state state, void *data)
+{
+ struct text_entry *entry = data;
struct rectangle allocation;
int32_t x, y;
- struct wl_seat *seat;
- if (state != WL_POINTER_BUTTON_STATE_PRESSED || button != BTN_LEFT) {
+ widget_get_allocation(entry->widget, &allocation);
+ input_get_position(input, &x, &y);
+
+ if (button != BTN_LEFT) {
return;
}
- input_get_position(input, &x, &y);
+ text_entry_set_cursor_position(entry,
+ x - allocation.x,
+ y - allocation.y);
- widget_get_allocation(editor->widget, &allocation);
- x -= allocation.x;
- y -= allocation.y;
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ struct wl_seat *seat = input_get_seat(input);
- int32_t activate_entry = rectangle_contains(&editor->entry->allocation, x, y);
- int32_t activate_editor = rectangle_contains(&editor->editor->allocation, x, y);
- assert(!(activate_entry && activate_editor));
+ text_entry_activate(entry, seat);
- seat = input_get_seat(input);
+ text_entry_set_anchor_position(entry,
+ x - allocation.x,
+ y - allocation.y);
- if (activate_entry) {
- text_entry_activate(editor->entry, seat);
- } else if (activate_editor) {
- text_entry_activate(editor->editor, seat);
+ widget_set_motion_handler(entry->widget, text_entry_motion_handler);
} else {
+ widget_set_motion_handler(entry->widget, NULL);
+ }
+}
+
+static void
+editor_button_handler(struct widget *widget,
+ struct input *input, uint32_t time,
+ uint32_t button,
+ enum wl_pointer_button_state state, void *data)
+{
+ struct editor *editor = data;
+
+ if (button != BTN_LEFT) {
+ return;
+ }
+
+ if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ struct wl_seat *seat = input_get_seat(input);
+
text_entry_deactivate(editor->entry, seat);
text_entry_deactivate(editor->editor, seat);
}
-
- widget_schedule_redraw(widget);
}
static void
@@ -339,8 +796,6 @@ global_handler(struct wl_display *display, uint32_t id,
if (!strcmp(interface, "text_model_factory")) {
editor->text_model_factory = wl_display_bind(display, id,
&text_model_factory_interface);
- } else if (!strcmp(interface, "wl_seat")) {
- fprintf(stderr, "wl_seat added\n");
}
}
@@ -363,12 +818,13 @@ main(int argc, char *argv[])
editor.entry = text_entry_create(&editor, "Entry");
editor.editor = text_entry_create(&editor, "Editor");
+ text_entry_set_preedit(editor.editor, "preedit", strlen("preedit"));
window_set_title(editor.window, "Text Editor");
widget_set_redraw_handler(editor.widget, redraw_handler);
widget_set_resize_handler(editor.widget, resize_handler);
- widget_set_button_handler(editor.widget, button_handler);
+ widget_set_button_handler(editor.widget, editor_button_handler);
window_schedule_resize(editor.window, 500, 400);
diff --git a/clients/keyboard.c b/clients/keyboard.c
index 9fdd8cc..c90c5b2 100644
--- a/clients/keyboard.c
+++ b/clients/keyboard.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2012 Openismus GmbH
+ * Copyright © 2012 Intel Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
@@ -28,32 +29,144 @@
#include <cairo.h>
#include "window.h"
-#include "text-client-protocol.h"
+#include "input-method-client-protocol.h"
#include "desktop-shell-client-protocol.h"
struct virtual_keyboard {
struct input_panel *input_panel;
struct input_method *input_method;
+ struct input_method_context *context;
struct display *display;
+ char *preedit_string;
+};
+
+enum key_type {
+ keytype_default,
+ keytype_backspace,
+ keytype_enter,
+ keytype_space,
+ keytype_switch,
+ keytype_symbols,
+ keytype_tab
+};
+
+struct key {
+ enum key_type key_type;
+
+ char *label;
+ char *alt;
+
+ unsigned int width;
+};
+
+static const struct key keys[] = {
+ { keytype_default, "q", "Q", 1},
+ { keytype_default, "w", "W", 1},
+ { keytype_default, "e", "E", 1},
+ { keytype_default, "r", "R", 1},
+ { keytype_default, "t", "T", 1},
+ { keytype_default, "y", "Y", 1},
+ { keytype_default, "u", "U", 1},
+ { keytype_default, "i", "I", 1},
+ { keytype_default, "o", "O", 1},
+ { keytype_default, "p", "P", 1},
+ { keytype_backspace, "<--", "<--", 2},
+
+ { keytype_tab, "->|", "->|", 1},
+ { keytype_default, "a", "A", 1},
+ { keytype_default, "s", "S", 1},
+ { keytype_default, "d", "D", 1},
+ { keytype_default, "f", "F", 1},
+ { keytype_default, "g", "G", 1},
+ { keytype_default, "h", "H", 1},
+ { keytype_default, "j", "J", 1},
+ { keytype_default, "k", "K", 1},
+ { keytype_default, "l", "L", 1},
+ { keytype_enter, "Enter", "Enter", 2},
+
+ { keytype_switch, "ABC", "abc", 2},
+ { keytype_default, "z", "Z", 1},
+ { keytype_default, "x", "X", 1},
+ { keytype_default, "c", "C", 1},
+ { keytype_default, "v", "V", 1},
+ { keytype_default, "b", "B", 1},
+ { keytype_default, "n", "N", 1},
+ { keytype_default, "m", "M", 1},
+ { keytype_default, ",", ",", 1},
+ { keytype_default, ".", ".", 1},
+ { keytype_switch, "ABC", "abc", 1},
+
+ { keytype_symbols, "?123", "?123", 2},
+ { keytype_space, "", "", 8},
+ { keytype_symbols, "?123", "?123", 2}
+};
+
+static const unsigned int columns = 12;
+static const unsigned int rows = 4;
+
+static const double key_width = 60;
+static const double key_height = 50;
+
+enum keyboard_state {
+ keyboardstate_default,
+ keyboardstate_uppercase
};
struct keyboard {
struct virtual_keyboard *keyboard;
struct window *window;
struct widget *widget;
- int cx;
- int cy;
+
+ enum keyboard_state state;
};
static void
+draw_key(const struct key *key,
+ cairo_t *cr,
+ enum keyboard_state state,
+ unsigned int row,
+ unsigned int col)
+{
+ const char *label;
+ cairo_text_extents_t extents;
+
+ cairo_save(cr);
+ cairo_rectangle(cr,
+ col * key_width, row * key_height,
+ key->width * key_width, key_height);
+ cairo_clip(cr);
+
+ /* Paint frame */
+ cairo_rectangle(cr,
+ col * key_width, row * key_height,
+ key->width * key_width, key_height);
+ cairo_set_line_width(cr, 3);
+ cairo_stroke(cr);
+
+ /* Paint text */
+ label = state == keyboardstate_default ? key->label : key->alt;
+ cairo_text_extents(cr, label, &extents);
+
+ cairo_translate(cr,
+ col * key_width,
+ row * key_height);
+ cairo_translate(cr,
+ (key->width * key_width - extents.width) / 2,
+ (key_height - extents.y_bearing) / 2);
+ cairo_show_text(cr, label);
+
+ cairo_restore(cr);
+}
+
+static void
redraw_handler(struct widget *widget, void *data)
{
struct keyboard *keyboard = data;
cairo_surface_t *surface;
struct rectangle allocation;
cairo_t *cr;
- int cx, cy;
- int i;
+ unsigned int i;
+ unsigned int row = 0, col = 0;
surface = window_get_surface(keyboard->window);
widget_get_allocation(keyboard->widget, &allocation);
@@ -62,37 +175,26 @@ redraw_handler(struct widget *widget, void *data)
cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
cairo_clip(cr);
- cairo_translate(cr, allocation.x, allocation.y);
+ cairo_select_font_face(cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
+ cairo_set_font_size(cr, 16);
- cx = keyboard->cx;
- cy = keyboard->cy;
+ cairo_translate(cr, allocation.x, allocation.y);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source_rgba(cr, 1, 1, 1, 0.5);
- cairo_rectangle(cr, 0, 0, 10 * cx, 5 * cy);
+ cairo_set_source_rgba(cr, 1, 1, 1, 0.75);
+ cairo_rectangle(cr, 0, 0, columns * key_width, rows * key_height);
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
- for (i = 0; i <= 'Z' - '0'; ++i) {
- const int x = i % 10;
- const int y = i / 10;
- char text[] = { i + '0', '\0' };
- cairo_text_extents_t extents;
- int dx, dy;
-
- cairo_text_extents(cr, text, &extents);
- dx = extents.width;
- dy = extents.height;
-
+ for (i = 0; i < sizeof(keys) / sizeof(*keys); ++i) {
cairo_set_source_rgb(cr, 0, 0, 0);
- cairo_rectangle(cr, x * cx, y * cy, cx, cy);
- cairo_stroke(cr);
-
- cairo_move_to(cr, x * cx + 0.5 * (cx - dx), y * cy + 0.5 * (cy - dy));
-
- cairo_set_source_rgb(cr, 0, 0, 0);
- cairo_show_text(cr, text);
+ draw_key(&keys[i], cr, keyboard->state, row, col);
+ col += keys[i].width;
+ if (col >= columns) {
+ row += 1;
+ col = 0;
+ }
}
cairo_destroy(cr);
@@ -107,6 +209,56 @@ resize_handler(struct widget *widget,
}
static void
+keyboard_handle_key(struct keyboard *keyboard, const struct key *key)
+{
+ const char *label = keyboard->state == keyboardstate_default ? key->label : key->alt;
+
+ switch (key->key_type) {
+ case keytype_default:
+ keyboard->keyboard->preedit_string = strcat(keyboard->keyboard->preedit_string,
+ label);
+ input_method_context_preedit_string(keyboard->keyboard->context,
+ keyboard->keyboard->preedit_string,
+ strlen(keyboard->keyboard->preedit_string));
+ break;
+ case keytype_backspace:
+ if (strlen(keyboard->keyboard->preedit_string) == 0) {
+ input_method_context_delete_surrounding_text(keyboard->keyboard->context,
+ -1, 1);
+ }
+ break;
+ case keytype_enter:
+ input_method_context_key(keyboard->keyboard->context,
+ XKB_KEY_KP_Enter, WL_KEYBOARD_KEY_STATE_PRESSED);
+ break;
+ case keytype_space:
+ keyboard->keyboard->preedit_string = strcat(keyboard->keyboard->preedit_string,
+ " ");
+ input_method_context_preedit_string(keyboard->keyboard->context,
+ "",
+ 0);
+ input_method_context_commit_string(keyboard->keyboard->context,
+ keyboard->keyboard->preedit_string,
+ strlen(keyboard->keyboard->preedit_string));
+ free(keyboard->keyboard->preedit_string);
+ keyboard->keyboard->preedit_string = strdup("");
+ break;
+ case keytype_switch:
+ if (keyboard->state == keyboardstate_default)
+ keyboard->state = keyboardstate_uppercase;
+ else
+ keyboard->state = keyboardstate_default;
+ break;
+ case keytype_symbols:
+ break;
+ case keytype_tab:
+ input_method_context_key(keyboard->keyboard->context,
+ XKB_KEY_Tab, WL_KEYBOARD_KEY_STATE_PRESSED);
+ break;
+ }
+}
+
+static void
button_handler(struct widget *widget,
struct input *input, uint32_t time,
uint32_t button,
@@ -114,8 +266,9 @@ button_handler(struct widget *widget,
{
struct keyboard *keyboard = data;
struct rectangle allocation;
- int32_t x, y;
- char text[] = { '0', '\0' };
+ int32_t x, y;
+ int row, col;
+ unsigned int i;
if (state != WL_POINTER_BUTTON_STATE_PRESSED || button != BTN_LEFT) {
return;
@@ -127,14 +280,92 @@ button_handler(struct widget *widget,
x -= allocation.x;
y -= allocation.y;
- text[0] = y / keyboard->cy * 10 + x / keyboard->cx + '0';
+ row = y / key_height;
+ col = x / key_width + row * columns;
+ for (i = 0; i < sizeof(keys) / sizeof(*keys); ++i) {
+ col -= keys[i].width;
+ if (col < 0)
+ break;
+ }
- input_method_commit_string(keyboard->keyboard->input_method, text, -1);
+ keyboard_handle_key(keyboard, &keys[i]);
widget_schedule_redraw(widget);
}
static void
+input_method_context_surrounding_text(void *data,
+ struct input_method_context *context,
+ const char *text,
+ uint32_t cursor,
+ uint32_t anchor)
+{
+ fprintf(stderr, "Surrounding text updated: %s\n", text);
+}
+
+static void
+input_method_context_reset(void *data,
+ struct input_method_context *context)
+{
+ struct virtual_keyboard *keyboard = data;
+
+ fprintf(stderr, "Reset pre-edit buffer\n");
+
+ if (strlen(keyboard->preedit_string)) {
+ input_method_context_preedit_string(context,
+ "",
+ 0);
+ free(keyboard->preedit_string);
+ keyboard->preedit_string = strdup("");
+ }
+}
+
+static const struct input_method_context_listener input_method_context_listener = {
+ input_method_context_surrounding_text,
+ input_method_context_reset
+};
+
+static void
+input_method_activate(void *data,
+ struct input_method *input_method,
+ struct input_method_context *context)
+{
+ struct virtual_keyboard *keyboard = data;
+
+ if (keyboard->context)
+ input_method_context_destroy(keyboard->context);
+
+ if (keyboard->preedit_string)
+ free(keyboard->preedit_string);
+
+ keyboard->preedit_string = strdup("");
+
+ keyboard->context = context;
+ input_method_context_add_listener(context,
+ &input_method_context_listener,
+ keyboard);
+}
+
+static void
+input_method_deactivate(void *data,
+ struct input_method *input_method,
+ struct input_method_context *context)
+{
+ struct virtual_keyboard *keyboard = data;
+
+ if (!keyboard->context)
+ return;
+
+ input_method_context_destroy(keyboard->context);
+ keyboard->context = NULL;
+}
+
+static const struct input_method_listener input_method_listener = {
+ input_method_activate,
+ input_method_deactivate
+};
+
+static void
global_handler(struct wl_display *display, uint32_t id,
const char *interface, uint32_t version, void *data)
{
@@ -144,6 +375,7 @@ global_handler(struct wl_display *display, uint32_t id,
keyboard->input_panel = wl_display_bind(display, id, &input_panel_interface);
} else if (!strcmp(interface, "input_method")) {
keyboard->input_method = wl_display_bind(display, id, &input_method_interface);
+ input_method_add_listener(keyboard->input_method, &input_method_listener, keyboard);
}
}
@@ -161,15 +393,14 @@ keyboard_create(struct output *output, struct virtual_keyboard *virtual_keyboard
window_set_title(keyboard->window, "Virtual keyboard");
window_set_user_data(keyboard->window, keyboard);
-
- keyboard->cx = 40;
- keyboard->cy = 40;
widget_set_redraw_handler(keyboard->widget, redraw_handler);
widget_set_resize_handler(keyboard->widget, resize_handler);
widget_set_button_handler(keyboard->widget, button_handler);
- window_schedule_resize(keyboard->window, keyboard->cx * 10, keyboard->cy * 5);
+ window_schedule_resize(keyboard->window,
+ columns * key_width,
+ rows * key_height);
input_panel_set_surface(virtual_keyboard->input_panel,
window_get_wl_surface(keyboard->window),
@@ -201,6 +432,9 @@ main(int argc, char *argv[])
return -1;
}
+ virtual_keyboard.context = NULL;
+ virtual_keyboard.preedit_string = NULL;
+
wl_display_add_global_listener(display_get_display(virtual_keyboard.display),
global_handler, &virtual_keyboard);
diff --git a/clients/simple-egl.c b/clients/simple-egl.c
index 808c2ee..a67ce2f 100644
--- a/clients/simple-egl.c
+++ b/clients/simple-egl.c
@@ -280,12 +280,10 @@ toggle_fullscreen(struct window *window, int fullscreen)
window->configured = 0;
if (fullscreen) {
- window->opaque = 1;
wl_shell_surface_set_fullscreen(window->shell_surface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
0, NULL);
} else {
- window->opaque = 0;
wl_shell_surface_set_toplevel(window->shell_surface);
handle_configure(window, window->shell_surface, 0,
window->window_size.width,
@@ -403,7 +401,7 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
eglSwapBuffers(window->display->egl.dpy, window->egl_surface);
- if (window->opaque) {
+ if (window->opaque || window->fullscreen) {
region = wl_compositor_create_region(window->display->compositor);
wl_region_add(region, 0, 0,
window->window_size.width,
@@ -594,7 +592,7 @@ main(int argc, char **argv)
struct sigaction sigint;
struct display display = { 0 };
struct window window = { 0 };
- int i, opaque = 0;
+ int i;
window.display = &display;
display.window = &window;
@@ -605,7 +603,7 @@ main(int argc, char **argv)
if (strcmp("-f", argv[i]) == 0)
window.fullscreen = 1;
else if (strcmp("-o", argv[i]) == 0)
- opaque = 1;
+ window.opaque = 1;
else if (strcmp("-h", argv[i]) == 0)
usage(EXIT_SUCCESS);
else
@@ -621,10 +619,7 @@ main(int argc, char **argv)
wl_display_get_fd(display.display, event_mask_update, &display);
wl_display_iterate(display.display, WL_DISPLAY_READABLE);
- if (window.fullscreen)
- window.opaque = 1;
-
- init_egl(&display, opaque);
+ init_egl(&display, window.opaque);
create_surface(&window);
init_gl(&window);
diff --git a/man/weston.man b/man/weston.man
index eff09c0..7667076 100644
--- a/man/weston.man
+++ b/man/weston.man
@@ -1,4 +1,4 @@
-.TH WESTON 1 "2012-08-29" "Weston __version__"
+.TH WESTON 1 "2012-09-13" "Weston __version__"
.SH NAME
weston \- the reference Wayland server
.SH SYNOPSIS
@@ -22,11 +22,8 @@ under another Wayland server), it should be done with the command
.B weston-launch
to set up proper privileged access to devices.
-Weston also supports X clients by XWayland. XWayland requires a special
-X.org server to be installed. This X server will connect to a Wayland
-server as a Wayland client, and X clients will connect to the X server.
-XWayland provides backwards compatibility to X applications in a Wayland
-stack.
+Weston also supports X clients via
+.BR XWayland ", see below."
.
.\" ***************************************************************
.SH BACKENDS
@@ -70,6 +67,21 @@ and the special client
which provides the basic user interface.
.
.\" ***************************************************************
+.SH XWAYLAND
+XWayland requires a special X.org server to be installed. This X server will
+connect to a Wayland server as a Wayland client, and X clients will connect to
+the X server. XWayland provides backwards compatibility to X applications in a
+Wayland stack.
+
+XWayland is activated by instructing
+.BR weston " to load " xwayland.so " module, see " EXAMPLES .
+Weston starts listening on a new X display socket, and exports it in the
+environment variable
+.BR DISPLAY .
+When the first X client connects, Weston launches a special X server as a
+Wayland client to handle the X client and all future X clients.
+.
+.\" ***************************************************************
.SH OPTIONS
.
.SS Weston core options:
@@ -100,8 +112,8 @@ Append log messages to the file
.I file.log
instead of writing them to stderr.
.TP
-\fB\-\-module\fR=\fImodule.so\fR
-Load a generic plugin module \fImodule.so\fR. Only used by the test
+\fB\-\-modules\fR=\fImodule1.so,module2.so\fR
+Load the comma-separated list of modules. Only used by the test
suite. The file is searched for in
.IR "__weston_modules_dir__" ,
or you can pass an absolute path.
@@ -113,14 +125,6 @@ Weston will export
.B WAYLAND_DISPLAY
with this value in the environment for all child processes to allow them to
connect to the right server automatically.
-.TP
-.B \-\-xserver
-Activate XWayland. Weston starts listening on a new X display socket, and
-exports it in the environment variable
-.BR DISPLAY .
-When the first X client connects, Weston launches a special X server as a
-Wayland client to handle the X client and all future X clients.
-.
.SS DRM backend options:
.TP
\fB\-\-connector\fR=\fIconnectorid\fR
@@ -220,8 +224,10 @@ http://wayland.freedesktop.org/
.
.\" ***************************************************************
.SH EXAMPLES
-.IP "Launch Weston with the DRM backend, directly on a VT"
+.IP "Launch Weston with the DRM backend on a VT"
weston-launch
+.IP "Launch Weston with the DRM backend and XWayland support"
+weston-launch -- --modules=xwayland.so
.IP "Launch Weston (wayland-1) nested in another Weston instance (wayland-0)"
WAYLAND_DISPLAY=wayland-0 weston -Swayland-1
.IP "From an X terminal, launch Weston with the x11 backend"
diff --git a/protocol/Makefile.am b/protocol/Makefile.am
index bf5ef99..c68e4c1 100644
--- a/protocol/Makefile.am
+++ b/protocol/Makefile.am
@@ -4,4 +4,5 @@ EXTRA_DIST = \
tablet-shell.xml \
xserver.xml \
text.xml \
+ input-method.xml \
workspaces.xml
diff --git a/protocol/input-method.xml b/protocol/input-method.xml
new file mode 100644
index 0000000..09ab10c
--- a/dev/null
+++ b/protocol/input-method.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="input_method">
+ <copyright>
+ Copyright © 2012 Intel Corporation
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+ </copyright>
+
+
+ <interface name="input_method_context" version="1">
+ <description summary="input method context">
+ Corresponds to a text model on input method side. An input method context
+ is created on text mode activation on the input method side. It allows to
+ receive information about the text model from the application via events.
+ Input method contexts do not keep state after deactivation and should be
+ destroyed after deactivation is handled.
+ </description>
+ <request name="destroy" type="destructor"/>
+ <request name="commit_string">
+ <description summary="commit string">
+ Send the commit string text to the applications text model.
+ </description>
+ <arg name="text" type="string"/>
+ <arg name="index" type="uint"/>
+ </request>
+ <request name="preedit_string">
+ <description summary="pre-edit string">
+ Send the pre-edit string text to the applications text model.
+ </description>
+ <arg name="text" type="string"/>
+ <arg name="index" type="uint"/>
+ </request>
+ <request name="delete_surrounding_text">
+ <arg name="index" type="int"/>
+ <arg name="length" type="uint"/>
+ </request>
+ <request name="key">
+ <arg name="key" type="uint"/>
+ <arg name="state" type="uint"/>
+ </request>
+ <event name="surrounding_text">
+ <description summary="surrounding text event">
+ The plain surrounding text around the input position. Cursor is the
+ position within the surrounding text. Anchor is the position of the
+ selection anchor within the surrounding text. If there is no selected
+ text anchor is the same as cursor.
+ </description>
+ <arg name="text" type="string"/>
+ <arg name="cursor" type="uint"/>
+ <arg name="anchor" type="uint"/>
+ </event>
+ <event name="reset">
+ </event>
+ </interface>
+
+ <interface name="input_method" version="1">
+ <description summary="input method">
+ An input method object is responsible to compose text in response to
+ input from hardware or virtual keyboards. There is one input method
+ object per seat. On activate there is a new input method context object
+ created which allows the input method to communicate with the text model.
+ </description>
+ <event name="activate">
+ <description summary="activate event">
+ A text model was activated. Creates an input method context object
+ which allows communication with the text model.
+ </description>
+ <arg name="id" type="new_id" interface="input_method_context"/>
+ </event>
+ <event name="deactivate">
+ <description summary="activate event">
+ The text model corresponding to the context argument was deactivated.
+ The input method context should be destroyed after deactivation is
+ handled.
+ </description>
+ <arg name="context" type="object" interface="input_method_context"/>
+ </event>
+ </interface>
+</protocol>
diff --git a/protocol/text.xml b/protocol/text.xml
index e73cacb..857fd83 100644
--- a/protocol/text.xml
+++ b/protocol/text.xml
@@ -1,22 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
<protocol name="text">
- <interface name="text_model" version="1">
+
+ <copyright>
+ Copyright © 2012 Intel Corporation
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+ </copyright>
+
+ <interface name="text_model" version="1">
+ <description summary="text model">
+ A model for text input. Adds support for text input and input methods to
+ applications. A text_model object is created from a text_model_factory and
+ corresponds typically to a text entry in an application. Requests are used
+ to activate/deactivate the model and set information like surrounding and
+ selected text or the content type. The information about entered text is
+ sent to the model via the pre-edit and commit events. Using this interface
+ removes the need for applications to directly process hardware key events
+ and compose text out of them.
+ </description>
<request name="set_surrounding_text">
+ <description summary="sets the surrounding text">
+ Sets the plain surrounding text around the input position. Cursor is the
+ byte index within the surrounding text. Anchor is the byte index of the
+ selection anchor within the surrounding text. If there is no selected
+ text anchor is the same as cursor.
+ </description>
<arg name="text" type="string"/>
- </request>
- <request name="set_cursor_index">
- <arg name="index" type="uint"/>
+ <arg name="cursor" type="uint"/>
+ <arg name="anchor" type="uint"/>
</request>
<request name="activate">
+ <description summary="request activation">
+ Requests the model to be activated (typically when the text entry gets
+ focus). The seat argument is a wl_seat which maintains the focus for
+ this activation. The surface argument is a wl_surface assigned to the
+ model and tracked for focus lost. The activated event is emitted on
+ successful activation.
+ </description>
<arg name="seat" type="object" interface="wl_seat"/>
<arg name="surface" type="object" interface="wl_surface"/>
</request>
<request name="deactivate">
+ <description summary="request deactivation">
+ Requests the model to be deactivated (typically when the text entry
+ lost focus). The seat argument is a wl_seat which was used for
+ activation.
+ </description>
<arg name="seat" type="object" interface="wl_seat"/>
</request>
- <request name="set_selected_text">
- <arg name="text" type="string"/>
- <arg name="index" type="int"/>
- </request>
+ <request name="reset">
+ <description summary="reset">
+ Should be called by an editor widget when the input state should
+ be reseted, for example after the text was changed outside of the
+ normal input method flow.
+ </description>
+ </request>
<request name="set_micro_focus">
<arg name="x" type="int"/>
<arg name="y" type="int"/>
@@ -27,33 +84,73 @@
<request name="set_content_type"/>
<event name="commit_string">
+ <description summary="commit">
+ Notify when text should be inserted into the editor widget. The text
+ to commit could be either just a single character after a key press
+ or the result of some composing (pre-edit). It also sets the new
+ cursor position (as byte index) relative to the inserted text.
+ </description>
<arg name="text" type="string"/>
<arg name="index" type="uint"/>
</event>
<event name="preedit_string">
+ <description summary="pre-edit">
+ Notify when a new composing text (pre-edit) should be set around the
+ current cursor position. Any previously set composing text should
+ be removed. It also sets the cursor positon (as byte index) relative
+ to the start of the composing text.
+ </description>
<arg name="text" type="string"/>
<arg name="index" type="uint"/>
</event>
+ <event name="delete_surrounding_text">
+ <description summary="delete surrounding text">
+ Notify when the text around the current cursor position should be
+ deleted. Index is relative to the current cursor (as byte index).
+ Length is the length of deleted text (as bytes).
+ </description>
+ <arg name="index" type="int"/>
+ <arg name="length" type="uint"/>
+ </event>
<event name="preedit_styling"/>
- <event name="key"/>
+ <event name="key">
+ <description summary="key">
+ Notify when a key event was sent. Key events should not be used
+ for normal text input operations, which should be done with
+ commit_string, delete_surrounfing_text, etc. The key event follows
+ the wl_keyboard key event convention. Key is a XKB keycode, state a
+ wl_keyboard key_state.
+ </description>
+ <arg name="key" type="uint"/>
+ <arg name="state" type="uint"/>
+ </event>
<event name="selection_replacement"/>
<event name="direction"/>
<event name="locale"/>
- <event name="activated"/>
- <event name="deactivated"/>
+ <event name="activated">
+ <description summary="activated event">
+ Notify the model when it is activated. Typically in response to an
+ activate request.
+ </description>
+ </event>
+ <event name="deactivated">
+ <description summary="deactivated event">
+ Notify the model when it is deactivated. Either in response to a
+ deactivate request or when the assigned surface lost focus or was
+ destroyed.
+ </description>
+ </event>
</interface>
<interface name="text_model_factory" version="1">
+ <description summary="text model factory">
+ A factory for text models. This object is a singleton global.
+ </description>
<request name="create_text_model">
+ <description summary="create text model">
+ Creates a new text model object.
+ </description>
<arg name="id" type="new_id" interface="text_model"/>
- <arg name="surface" type="object" interface="wl_surface"/>
- </request>
- </interface>
-
- <interface name="input_method" version="1">
- <request name="commit_string">
- <arg name="text" type="string"/>
- <arg name="index" type="uint"/>
</request>
</interface>
</protocol>
diff --git a/src/.gitignore b/src/.gitignore
index cd68a3e..3c27953 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -13,3 +13,7 @@ desktop-shell-protocol.c
desktop-shell-server-protocol.h
text-protocol.c
text-server-protocol.h
+workspaces-protocol.c
+workspaces-server-protocol.h
+input-method-protocol.c
+input-method-server-protocol.h
diff --git a/src/Makefile.am b/src/Makefile.am
index a20d584..3dd326c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,6 +28,8 @@ weston_SOURCES = \
text-backend.c \
text-protocol.c \
text-server-protocol.h \
+ input-method-protocol.c \
+ input-method-server-protocol.h \
workspaces-protocol.c \
workspaces-server-protocol.h \
util.c \
@@ -176,6 +178,8 @@ BUILT_SOURCES = \
desktop-shell-server-protocol.h \
text-protocol.c \
text-server-protocol.h \
+ input-method-protocol.c \
+ input-method-server-protocol.h \
workspaces-server-protocol.h \
workspaces-protocol.c \
git-version.h
diff --git a/src/compositor-android.c b/src/compositor-android.c
index 8e13da0..c5b1aa5 100644
--- a/src/compositor-android.c
+++ b/src/compositor-android.c
@@ -476,11 +476,11 @@ android_compositor_create(struct wl_display *display, int argc, char *argv[],
if (android_init_egl(compositor, output) < 0)
goto err_output;
+ android_compositor_add_output(compositor, output);
+
if (gles2_renderer_init(&compositor->base) < 0)
goto err_egl;
- android_compositor_add_output(compositor, output);
-
compositor->seat = android_seat_create(compositor);
if (!compositor->seat)
goto err_egl;
diff --git a/src/compositor.c b/src/compositor.c
index f23a658..b5d192a 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -456,8 +456,7 @@ weston_surface_update_transform(struct weston_surface *surface)
weston_surface_damage_below(surface);
- if (weston_surface_is_mapped(surface))
- weston_surface_assign_output(surface);
+ weston_surface_assign_output(surface);
}
WL_EXPORT void
@@ -847,7 +846,6 @@ surface_accumulate_damage(struct weston_surface *surface,
surface->geometry.y - surface->plane->y);
}
- pixman_region32_subtract(&surface->damage, &surface->damage, opaque);
pixman_region32_union(&surface->plane->damage,
&surface->plane->damage, &surface->damage);
empty_region(&surface->damage);
@@ -864,7 +862,7 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs)
struct weston_animation *animation, *next;
struct weston_frame_callback *cb, *cnext;
struct wl_list frame_callback_list;
- pixman_region32_t opaque, output_damage, new_damage;
+ pixman_region32_t opaque, output_damage;
weston_compositor_update_drag_surfaces(ec);
@@ -897,21 +895,10 @@ weston_output_repaint(struct weston_output *output, uint32_t msecs)
pixman_region32_fini(&opaque);
pixman_region32_init(&output_damage);
-
- pixman_region32_init(&new_damage);
- pixman_region32_copy(&new_damage, &ec->primary_plane.damage);
-
- pixman_region32_union(&ec->primary_plane.damage,
- &ec->primary_plane.damage,
- &output->previous_damage);
-
- pixman_region32_intersect(&output->previous_damage,
- &new_damage, &output->region);
-
pixman_region32_intersect(&output_damage,
&ec->primary_plane.damage, &output->region);
-
- pixman_region32_fini(&new_damage);
+ pixman_region32_subtract(&ec->primary_plane.damage,
+ &ec->primary_plane.damage, &output->region);
if (output->dirty)
weston_output_update_matrix(output);
@@ -1038,7 +1025,7 @@ weston_compositor_fade(struct weston_compositor *compositor, float tint)
weston_surface_set_color(surface, 0.0, 0.0, 0.0, 0.0);
wl_list_insert(&compositor->fade_layer.surface_list,
&surface->layer_link);
- weston_surface_assign_output(surface);
+ weston_surface_update_transform(surface);
compositor->fade.surface = surface;
pixman_region32_init(&surface->input);
}
@@ -1941,7 +1928,7 @@ pointer_cursor_surface_configure(struct weston_surface *es,
if (!weston_surface_is_mapped(es)) {
wl_list_insert(&es->compositor->cursor_layer.surface_list,
&es->layer_link);
- weston_surface_assign_output(es);
+ weston_surface_update_transform(es);
}
}
@@ -2428,7 +2415,7 @@ device_map_drag_surface(struct weston_seat *seat)
list = &seat->compositor->cursor_layer.surface_list;
wl_list_insert(list, &seat->drag_surface->layer_link);
- weston_surface_assign_output(seat->drag_surface);
+ weston_surface_update_transform(seat->drag_surface);
empty_region(&seat->drag_surface->input);
}
@@ -2522,9 +2509,13 @@ WL_EXPORT void
weston_output_destroy(struct weston_output *output)
{
struct weston_compositor *c = output->compositor;
+ int i;
pixman_region32_fini(&output->region);
- pixman_region32_fini(&output->previous_damage);
+
+ for (i = 0; i < 2; i++)
+ pixman_region32_fini(&output->buffer_damage[i]);
+
output->compositor->output_id_pool &= ~(1 << output->id);
wl_display_remove_global(c->wl_display, output->global);
@@ -2648,10 +2639,15 @@ weston_output_transform_init(struct weston_output *output, uint32_t transform)
WL_EXPORT void
weston_output_move(struct weston_output *output, int x, int y)
{
+ int i;
+
output->x = x;
output->y = y;
- pixman_region32_init(&output->previous_damage);
+ output->current_buffer = 0;
+ for (i = 0; i < 2; i++)
+ pixman_region32_init(&output->buffer_damage[i]);
+
pixman_region32_init_rect(&output->region, x, y,
output->width,
output->height);
@@ -2770,6 +2766,7 @@ weston_compositor_init(struct weston_compositor *ec,
screenshooter_create(ec);
text_cursor_position_notifier_create(ec);
+ text_model_factory_create(ec);
wl_data_device_manager_init(ec->wl_display);
@@ -2861,7 +2858,7 @@ on_segv_signal(int s, siginfo_t *siginfo, void *context)
static void *
-load_module(const char *name, const char *entrypoint, void **handle)
+load_module(const char *name, const char *entrypoint)
{
char path[PATH_MAX];
void *module, *init;
@@ -2871,6 +2868,13 @@ load_module(const char *name, const char *entrypoint, void **handle)
else
snprintf(path, sizeof path, "%s", name);
+ module = dlopen(path, RTLD_NOW | RTLD_NOLOAD);
+ if (module) {
+ weston_log("Module '%s' already loaded\n", path);
+ dlclose(module);
+ return NULL;
+ }
+
weston_log("Loading module '%s'\n", path);
module = dlopen(path, RTLD_NOW);
if (!module) {
@@ -2887,6 +2891,32 @@ load_module(const char *name, const char *entrypoint, void **handle)
return init;
}
+static int
+load_modules(struct weston_compositor *ec, const char *modules)
+{
+ const char *p, *end;
+ char buffer[256];
+ int (*module_init)(struct weston_compositor *ec);
+
+ if (modules == NULL)
+ return 0;
+
+ p = modules;
+ while (*p) {
+ end = strchrnul(p, ',');
+ snprintf(buffer, sizeof buffer, "%.*s", (int) (end - p), p);
+ module_init = load_module(buffer, "module_init");
+ if (module_init)
+ module_init(ec);
+ p = end;
+ while (*p == ',')
+ p++;
+
+ }
+
+ return 0;
+}
+
static const char xdg_error_message[] =
"fatal: environment variable XDG_RUNTIME_DIR is not set.\n";
@@ -2945,8 +2975,7 @@ usage(int error_code)
"\t\t\t\tx11-backend.so or wayland-backend.so\n"
" -S, --socket=NAME\tName of socket to listen on\n"
" -i, --idle-time=SECS\tIdle time in seconds\n"
- " --xserver\t\tEnable X server integration\n"
- " --module\t\tLoad the specified module\n"
+ " --modules\t\tLoad the comma-separated list of modules\n"
" --log==FILE\t\tLog to the given file\n"
" -h, --help\t\tThis help message\n\n");
@@ -2982,37 +3011,32 @@ int main(int argc, char *argv[])
struct wl_event_source *signals[4];
struct wl_event_loop *loop;
struct sigaction segv_action;
- void *shell_module, *backend_module, *xserver_module;
- int (*module_init)(struct weston_compositor *ec);
struct weston_compositor
*(*backend_init)(struct wl_display *display,
int argc, char *argv[], const char *config_file);
int i;
char *backend = NULL;
- char *shell = NULL;
- char *module = NULL;
+ const char *modules = "desktop-shell.so", *option_modules = NULL;
char *log = NULL;
int32_t idle_time = 300;
- int32_t xserver = 0;
int32_t help = 0;
- char *socket_name = NULL;
+ char *socket_name = "wayland-0";
char *config_file;
- const struct config_key shell_config_keys[] = {
- { "type", CONFIG_KEY_STRING, &shell },
+ const struct config_key core_config_keys[] = {
+ { "modules", CONFIG_KEY_STRING, &modules },
};
const struct config_section cs[] = {
- { "shell",
- shell_config_keys, ARRAY_LENGTH(shell_config_keys) },
+ { "core",
+ core_config_keys, ARRAY_LENGTH(core_config_keys) },
};
const struct weston_option core_options[] = {
{ WESTON_OPTION_STRING, "backend", 'B', &backend },
{ WESTON_OPTION_STRING, "socket", 'S', &socket_name },
{ WESTON_OPTION_INTEGER, "idle-time", 'i', &idle_time },
- { WESTON_OPTION_BOOLEAN, "xserver", 0, &xserver },
- { WESTON_OPTION_STRING, "module", 0, &module },
+ { WESTON_OPTION_STRING, "modules", 0, &option_modules },
{ WESTON_OPTION_STRING, "log", 0, &log },
{ WESTON_OPTION_BOOLEAN, "help", 'h', &help },
};
@@ -3062,9 +3086,9 @@ int main(int argc, char *argv[])
}
config_file = config_file_path("weston.ini");
- parse_config_file(config_file, cs, ARRAY_LENGTH(cs), shell);
+ parse_config_file(config_file, cs, ARRAY_LENGTH(cs), NULL);
- backend_init = load_module(backend, "backend_init", &backend_module);
+ backend_init = load_module(backend, "backend_init");
if (!backend_init)
exit(EXIT_FAILURE);
@@ -3092,35 +3116,12 @@ int main(int argc, char *argv[])
ec->option_idle_time = idle_time;
ec->idle_time = idle_time;
- module_init = NULL;
- if (xserver)
- module_init = load_module("xwayland.so",
- "weston_xserver_init",
- &xserver_module);
- if (module_init && module_init(ec) < 0) {
- ret = EXIT_FAILURE;
- goto out;
- }
-
- if (socket_name)
- setenv("WAYLAND_DISPLAY", socket_name, 1);
+ setenv("WAYLAND_DISPLAY", socket_name, 1);
- if (!shell)
- shell = "desktop-shell.so";
- module_init = load_module(shell, "shell_init", &shell_module);
- if (!module_init || module_init(ec) < 0) {
- ret = EXIT_FAILURE;
+ if (load_modules(ec, modules) < 0)
goto out;
- }
-
-
- module_init = NULL;
- if (module)
- module_init = load_module(module, "module_init", NULL);
- if (module_init && module_init(ec) < 0) {
- ret = EXIT_FAILURE;
+ if (load_modules(ec, option_modules) < 0)
goto out;
- }
if (wl_display_add_socket(display, socket_name)) {
weston_log("fatal: failed to add socket: %m\n");
diff --git a/src/compositor.h b/src/compositor.h
index 2954703..4760993 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -160,7 +160,8 @@ struct weston_output {
int32_t mm_width, mm_height;
struct weston_border border;
pixman_region32_t region;
- pixman_region32_t previous_damage;
+ int current_buffer;
+ pixman_region32_t buffer_damage[2];
int repaint_needed;
int repaint_scheduled;
struct weston_output_zoom zoom;
@@ -276,7 +277,6 @@ struct weston_renderer {
};
struct weston_compositor {
- struct wl_shm *shm;
struct wl_signal destroy_signal;
EGLDisplay egl_display;
@@ -748,6 +748,9 @@ void
text_cursor_position_notifier_create(struct weston_compositor *ec);
void
+text_model_factory_create(struct weston_compositor *ec);
+
+void
input_method_create(struct weston_compositor *ec,
struct weston_seat *seat);
@@ -770,9 +773,6 @@ weston_client_launch(struct weston_compositor *compositor,
void
weston_watch_process(struct weston_process *process);
-int
-weston_xserver_init(struct weston_compositor *compositor);
-
struct weston_surface_animation;
typedef void (*weston_surface_animation_done_func_t)(struct weston_surface_animation *animation, void *data);
@@ -794,10 +794,6 @@ weston_surface_set_color(struct weston_surface *surface,
void
weston_surface_destroy(struct weston_surface *surface);
-struct weston_compositor *
-backend_init(struct wl_display *display, int argc, char *argv[],
- const char *config_file);
-
int
weston_output_switch_mode(struct weston_output *output, struct weston_mode *mode);
@@ -806,4 +802,11 @@ gles2_renderer_init(struct weston_compositor *ec);
void
gles2_renderer_destroy(struct weston_compositor *ec);
+struct weston_compositor *
+backend_init(struct wl_display *display, int argc, char *argv[],
+ const char *config_file);
+
+int
+module_init(struct weston_compositor *compositor);
+
#endif
diff --git a/src/gles2-renderer.c b/src/gles2-renderer.c
index a19c8c5..761f4fe 100644
--- a/src/gles2-renderer.c
+++ b/src/gles2-renderer.c
@@ -25,6 +25,8 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <float.h>
+#include <assert.h>
#include "compositor.h"
@@ -64,65 +66,320 @@ print_egl_error_state(void)
egl_error_string(code), (long)code);
}
+struct polygon8 {
+ GLfloat x[8];
+ GLfloat y[8];
+ int n;
+};
+
+struct clip_context {
+ struct {
+ GLfloat x;
+ GLfloat y;
+ } prev;
+
+ struct {
+ GLfloat x1, y1;
+ GLfloat x2, y2;
+ } clip;
+
+ struct {
+ GLfloat *x;
+ GLfloat *y;
+ } vertices;
+};
+
+static GLfloat
+float_difference(GLfloat a, GLfloat b)
+{
+ /* http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ */
+ static const GLfloat max_diff = 4.0f * FLT_MIN;
+ static const GLfloat max_rel_diff = 4.0e-5;
+ GLfloat diff = a - b;
+ GLfloat adiff = fabsf(diff);
+
+ if (adiff <= max_diff)
+ return 0.0f;
+
+ a = fabsf(a);
+ b = fabsf(b);
+ if (adiff <= (a > b ? a : b) * max_rel_diff)
+ return 0.0f;
+
+ return diff;
+}
+
+/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line x = x_arg.
+ * Compute the y coordinate of the intersection.
+ */
+static GLfloat
+clip_intersect_y(GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y,
+ GLfloat x_arg)
+{
+ GLfloat a;
+ GLfloat diff = float_difference(p1x, p2x);
+
+ /* Practically vertical line segment, yet the end points have already
+ * been determined to be on different sides of the line. Therefore
+ * the line segment is part of the line and intersects everywhere.
+ * Return the end point, so we use the whole line segment.
+ */
+ if (diff == 0.0f)
+ return p2y;
+
+ a = (x_arg - p2x) / diff;
+ return p2y + (p1y - p2y) * a;
+}
+
+/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line y = y_arg.
+ * Compute the x coordinate of the intersection.
+ */
+static GLfloat
+clip_intersect_x(GLfloat p1x, GLfloat p1y, GLfloat p2x, GLfloat p2y,
+ GLfloat y_arg)
+{
+ GLfloat a;
+ GLfloat diff = float_difference(p1y, p2y);
+
+ /* Practically horizontal line segment, yet the end points have already
+ * been determined to be on different sides of the line. Therefore
+ * the line segment is part of the line and intersects everywhere.
+ * Return the end point, so we use the whole line segment.
+ */
+ if (diff == 0.0f)
+ return p2x;
+
+ a = (y_arg - p2y) / diff;
+ return p2x + (p1x - p2x) * a;
+}
+
+enum path_transition {
+ PATH_TRANSITION_OUT_TO_OUT = 0,
+ PATH_TRANSITION_OUT_TO_IN = 1,
+ PATH_TRANSITION_IN_TO_OUT = 2,
+ PATH_TRANSITION_IN_TO_IN = 3,
+};
+
+static void
+clip_append_vertex(struct clip_context *ctx, GLfloat x, GLfloat y)
+{
+ *ctx->vertices.x++ = x;
+ *ctx->vertices.y++ = y;
+}
+
+static enum path_transition
+path_transition_left_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+{
+ return ((ctx->prev.x >= ctx->clip.x1) << 1) | (x >= ctx->clip.x1);
+}
+
+static enum path_transition
+path_transition_right_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+{
+ return ((ctx->prev.x < ctx->clip.x2) << 1) | (x < ctx->clip.x2);
+}
+
+static enum path_transition
+path_transition_top_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+{
+ return ((ctx->prev.y >= ctx->clip.y1) << 1) | (y >= ctx->clip.y1);
+}
+
+static enum path_transition
+path_transition_bottom_edge(struct clip_context *ctx, GLfloat x, GLfloat y)
+{
+ return ((ctx->prev.y < ctx->clip.y2) << 1) | (y < ctx->clip.y2);
+}
+
+static void
+clip_polygon_leftright(struct clip_context *ctx,
+ enum path_transition transition,
+ GLfloat x, GLfloat y, GLfloat clip_x)
+{
+ GLfloat yi;
+
+ switch (transition) {
+ case PATH_TRANSITION_IN_TO_IN:
+ clip_append_vertex(ctx, x, y);
+ break;
+ case PATH_TRANSITION_IN_TO_OUT:
+ yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
+ clip_append_vertex(ctx, clip_x, yi);
+ break;
+ case PATH_TRANSITION_OUT_TO_IN:
+ yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
+ clip_append_vertex(ctx, clip_x, yi);
+ clip_append_vertex(ctx, x, y);
+ break;
+ case PATH_TRANSITION_OUT_TO_OUT:
+ /* nothing */
+ break;
+ default:
+ assert(0 && "bad enum path_transition");
+ }
+
+ ctx->prev.x = x;
+ ctx->prev.y = y;
+}
+
+static void
+clip_polygon_topbottom(struct clip_context *ctx,
+ enum path_transition transition,
+ GLfloat x, GLfloat y, GLfloat clip_y)
+{
+ GLfloat xi;
+
+ switch (transition) {
+ case PATH_TRANSITION_IN_TO_IN:
+ clip_append_vertex(ctx, x, y);
+ break;
+ case PATH_TRANSITION_IN_TO_OUT:
+ xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
+ clip_append_vertex(ctx, xi, clip_y);
+ break;
+ case PATH_TRANSITION_OUT_TO_IN:
+ xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
+ clip_append_vertex(ctx, xi, clip_y);
+ clip_append_vertex(ctx, x, y);
+ break;
+ case PATH_TRANSITION_OUT_TO_OUT:
+ /* nothing */
+ break;
+ default:
+ assert(0 && "bad enum path_transition");
+ }
+
+ ctx->prev.x = x;
+ ctx->prev.y = y;
+}
+
+static void
+clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
+ GLfloat *dst_x, GLfloat *dst_y)
+{
+ ctx->prev.x = src->x[src->n - 1];
+ ctx->prev.y = src->y[src->n - 1];
+ ctx->vertices.x = dst_x;
+ ctx->vertices.y = dst_y;
+}
+
+static int
+clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
+ GLfloat *dst_x, GLfloat *dst_y)
+{
+ enum path_transition trans;
+ int i;
+
+ clip_context_prepare(ctx, src, dst_x, dst_y);
+ for (i = 0; i < src->n; i++) {
+ trans = path_transition_left_edge(ctx, src->x[i], src->y[i]);
+ clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
+ ctx->clip.x1);
+ }
+ return ctx->vertices.x - dst_x;
+}
+
+static int
+clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
+ GLfloat *dst_x, GLfloat *dst_y)
+{
+ enum path_transition trans;
+ int i;
+
+ clip_context_prepare(ctx, src, dst_x, dst_y);
+ for (i = 0; i < src->n; i++) {
+ trans = path_transition_right_edge(ctx, src->x[i], src->y[i]);
+ clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
+ ctx->clip.x2);
+ }
+ return ctx->vertices.x - dst_x;
+}
+
+static int
+clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
+ GLfloat *dst_x, GLfloat *dst_y)
+{
+ enum path_transition trans;
+ int i;
+
+ clip_context_prepare(ctx, src, dst_x, dst_y);
+ for (i = 0; i < src->n; i++) {
+ trans = path_transition_top_edge(ctx, src->x[i], src->y[i]);
+ clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
+ ctx->clip.y1);
+ }
+ return ctx->vertices.x - dst_x;
+}
+
+static int
+clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
+ GLfloat *dst_x, GLfloat *dst_y)
+{
+ enum path_transition trans;
+ int i;
+
+ clip_context_prepare(ctx, src, dst_x, dst_y);
+ for (i = 0; i < src->n; i++) {
+ trans = path_transition_bottom_edge(ctx, src->x[i], src->y[i]);
+ clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
+ ctx->clip.y2);
+ }
+ return ctx->vertices.x - dst_x;
+}
+
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) > (b)) ? (b) : (a))
#define clip(x, a, b) min(max(x, a), b)
-#define sign(x) ((x) >= 0)
+/*
+ * Compute the boundary vertices of the intersection of the global coordinate
+ * aligned rectangle 'rect', and an arbitrary quadrilateral produced from
+ * 'surf_rect' when transformed from surface coordinates into global coordinates.
+ * The vertices are written to 'ex' and 'ey', and the return value is the
+ * number of vertices. Vertices are produced in clockwise winding order.
+ * Guarantees to produce either zero vertices, or 3-8 vertices with non-zero
+ * polygon area.
+ */
static int
calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
{
- int i, n = 0;
+ struct polygon8 polygon;
+ struct clip_context ctx;
+ int i, n;
GLfloat min_x, max_x, min_y, max_y;
- GLfloat x[4] = {
- surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1,
+ struct polygon8 surf = {
+ { surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1 },
+ { surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2 },
+ 4
};
- GLfloat y[4] = {
- surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2,
- };
- GLfloat cx1 = rect->x1;
- GLfloat cx2 = rect->x2;
- GLfloat cy1 = rect->y1;
- GLfloat cy2 = rect->y2;
-
- GLfloat dist_squared(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
- {
- GLfloat dx = (x1 - x2);
- GLfloat dy = (y1 - y2);
- return dx * dx + dy * dy;
- }
- void append_vertex(GLfloat x, GLfloat y)
- {
- /* don't emit duplicate vertices: */
- if ((n > 0) && (ex[n-1] == x) && (ey[n-1] == y))
- return;
- ex[n] = x;
- ey[n] = y;
- n++;
- }
+ ctx.clip.x1 = rect->x1;
+ ctx.clip.y1 = rect->y1;
+ ctx.clip.x2 = rect->x2;
+ ctx.clip.y2 = rect->y2;
/* transform surface to screen space: */
- for (i = 0; i < 4; i++)
- weston_surface_to_global_float(es, x[i], y[i], &x[i], &y[i]);
+ for (i = 0; i < surf.n; i++)
+ weston_surface_to_global_float(es, surf.x[i], surf.y[i],
+ &surf.x[i], &surf.y[i]);
/* find bounding box: */
- min_x = max_x = x[0];
- min_y = max_y = y[0];
-
- for (i = 1; i < 4; i++) {
- min_x = min(min_x, x[i]);
- max_x = max(max_x, x[i]);
- min_y = min(min_y, y[i]);
- max_y = max(max_y, y[i]);
+ min_x = max_x = surf.x[0];
+ min_y = max_y = surf.y[0];
+
+ for (i = 1; i < surf.n; i++) {
+ min_x = min(min_x, surf.x[i]);
+ max_x = max(max_x, surf.x[i]);
+ min_y = min(min_y, surf.y[i]);
+ max_y = max(max_y, surf.y[i]);
}
/* First, simple bounding box check to discard early transformed
* surface rects that do not intersect with the clip region:
*/
- if ((min_x > cx2) || (max_x < cx1) ||
- (min_y > cy2) || (max_y < cy1))
+ if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
+ (min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
return 0;
/* Simple case, bounding box edges are parallel to surface edges,
@@ -130,224 +387,42 @@ calculate_edges(struct weston_surface *es, pixman_box32_t *rect,
* vertices to the clip rect bounds:
*/
if (!es->transform.enabled) {
- for (i = 0; i < 4; i++) {
- ex[n] = clip(x[i], cx1, cx2);
- ey[n] = clip(y[i], cy1, cy2);
- n++;
+ for (i = 0; i < surf.n; i++) {
+ ex[i] = clip(surf.x[i], ctx.clip.x1, ctx.clip.x2);
+ ey[i] = clip(surf.y[i], ctx.clip.y1, ctx.clip.y2);
}
- return 4;
+ return surf.n;
}
- /* Hard case, transformation applied. We need to find the vertices
- * of the shape that is the intersection of the clip rect and
- * transformed surface. This can be anything from 3 to 8 sides.
- *
- * Observation: all the resulting vertices will be the intersection
- * points of the transformed surface and the clip rect, plus the
- * vertices of the clip rect which are enclosed by the transformed
- * surface and the vertices of the transformed surface which are
- * enclosed by the clip rect.
- *
- * Observation: there will be zero, one, or two resulting vertices
- * for each edge of the src rect.
- *
- * Loop over four edges of the transformed rect:
+ /* Transformed case: use a general polygon clipping algorithm to
+ * clip the surface rectangle with each side of 'rect'.
+ * The algorithm is Sutherland-Hodgman, as explained in
+ * http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
+ * but without looking at any of that code.
*/
- for (i = 0; i < 4; i++) {
- GLfloat x1, y1, x2, y2;
- int last_n = n;
-
- x1 = x[i];
- y1 = y[i];
-
- /* if this vertex is contained in the clip rect, use it as-is: */
- if ((cx1 <= x1) && (x1 <= cx2) &&
- (cy1 <= y1) && (y1 <= cy2))
- append_vertex(x1, y1);
-
- /* for remaining, we consider the point as part of a line: */
- x2 = x[(i+1) % 4];
- y2 = y[(i+1) % 4];
-
- if (x1 == x2) {
- append_vertex(clip(x1, cx1, cx2), clip(y1, cy1, cy2));
- append_vertex(clip(x2, cx1, cx2), clip(y2, cy1, cy2));
- } else if (y1 == y2) {
- append_vertex(clip(x1, cx1, cx2), clip(y1, cy1, cy2));
- append_vertex(clip(x2, cx1, cx2), clip(y2, cy1, cy2));
- } else {
- GLfloat m, c, p;
- GLfloat tx[2], ty[2];
- int tn = 0;
-
- int intersect_horiz(GLfloat y, GLfloat *p)
- {
- GLfloat x;
-
- /* if y does not lie between y1 and y2, no
- * intersection possible
- */
- if (sign(y-y1) == sign(y-y2))
- return 0;
-
- x = (y - c) / m;
-
- /* if x does not lie between cx1 and cx2, no
- * intersection:
- */
- if (sign(x-cx1) == sign(x-cx2))
- return 0;
-
- *p = x;
- return 1;
- }
-
- int intersect_vert(GLfloat x, GLfloat *p)
- {
- GLfloat y;
-
- if (sign(x-x1) == sign(x-x2))
- return 0;
-
- y = m * x + c;
-
- if (sign(y-cy1) == sign(y-cy2))
- return 0;
-
- *p = y;
- return 1;
- }
-
- /* y = mx + c */
- m = (y2 - y1) / (x2 - x1);
- c = y1 - m * x1;
-
- /* check for up to two intersections with the four edges
- * of the clip rect. Note that we don't know the orientation
- * of the transformed surface wrt. the clip rect. So if when
- * there are two intersection points, we need to put the one
- * closest to x1,y1 first:
- */
-
- /* check top clip rect edge: */
- if (intersect_horiz(cy1, &p)) {
- ty[tn] = cy1;
- tx[tn] = p;
- tn++;
- }
-
- /* check right clip rect edge: */
- if (intersect_vert(cx2, &p)) {
- ty[tn] = p;
- tx[tn] = cx2;
- tn++;
- if (tn == 2)
- goto edge_check_done;
- }
-
- /* check bottom clip rect edge: */
- if (intersect_horiz(cy2, &p)) {
- ty[tn] = cy2;
- tx[tn] = p;
- tn++;
- if (tn == 2)
- goto edge_check_done;
- }
-
- /* check left clip rect edge: */
- if (intersect_vert(cx1, &p)) {
- ty[tn] = p;
- tx[tn] = cx1;
- tn++;
- }
-
-edge_check_done:
- if (tn == 1) {
- append_vertex(tx[0], ty[0]);
- } else if (tn == 2) {
- if (dist_squared(x1, y1, tx[0], ty[0]) <
- dist_squared(x1, y1, tx[1], ty[1])) {
- append_vertex(tx[0], ty[0]);
- append_vertex(tx[1], ty[1]);
- } else {
- append_vertex(tx[1], ty[1]);
- append_vertex(tx[0], ty[0]);
- }
- }
-
- if (n == last_n) {
- GLfloat best_x=0, best_y=0;
- uint32_t d, best_d = (unsigned int)-1; /* distance squared */
- uint32_t max_d = dist_squared(x2, y2,
- x[(i+2) % 4], y[(i+2) % 4]);
-
- /* if there are no vertices on this line, it could be that
- * there is a vertex of the clip rect that is enclosed by
- * the transformed surface. Find the vertex of the clip
- * rect that is reached by the shortest line perpendicular
- * to the current edge, if any.
- *
- * slope of perpendicular is 1/m, so
- *
- * cy = -cx/m + c2
- * c2 = cy + cx/m
- *
- */
-
- int perp_intersect(GLfloat cx, GLfloat cy, uint32_t *d)
- {
- GLfloat c2 = cy + cx/m;
- GLfloat x = (c2 - c) / (m + 1/m);
-
- /* if the x position of the intersection of the
- * perpendicular with the transformed edge does
- * not lie within the bounds of the edge, then
- * no intersection:
- */
- if (sign(x-x1) == sign(x-x2))
- return 0;
-
- *d = dist_squared(cx, cy, x, (m * x) + c);
-
- /* if intersection distance is further away than
- * opposite edge of surface region, it is invalid:
- */
- if (*d > max_d)
- return 0;
-
- return 1;
- }
-
- if (perp_intersect(cx1, cy1, &d)) {
- best_x = cx1;
- best_y = cy1;
- best_d = d;
- }
-
- if (perp_intersect(cx1, cy2, &d) && (d < best_d)) {
- best_x = cx1;
- best_y = cy2;
- best_d = d;
- }
-
- if (perp_intersect(cx2, cy2, &d) && (d < best_d)) {
- best_x = cx2;
- best_y = cy2;
- best_d = d;
- }
-
- if (perp_intersect(cx2, cy1, &d) && (d < best_d)) {
- best_x = cx2;
- best_y = cy1;
- best_d = d;
- }
-
- if (best_d != (unsigned int)-1) // XXX can this happen?
- append_vertex(best_x, best_y);
- }
- }
-
+ polygon.n = clip_polygon_left(&ctx, &surf, polygon.x, polygon.y);
+ surf.n = clip_polygon_right(&ctx, &polygon, surf.x, surf.y);
+ polygon.n = clip_polygon_top(&ctx, &surf, polygon.x, polygon.y);
+ surf.n = clip_polygon_bottom(&ctx, &polygon, surf.x, surf.y);
+
+ /* Get rid of duplicate vertices */
+ ex[0] = surf.x[0];
+ ey[0] = surf.y[0];
+ n = 1;
+ for (i = 1; i < surf.n; i++) {
+ if (float_difference(ex[n - 1], surf.x[i]) == 0.0f &&
+ float_difference(ey[n - 1], surf.y[i]) == 0.0f)
+ continue;
+ ex[n] = surf.x[i];
+ ey[n] = surf.y[i];
+ n++;
}
+ if (float_difference(ex[n - 1], surf.x[0]) == 0.0f &&
+ float_difference(ey[n - 1], surf.y[0]) == 0.0f)
+ n--;
+
+ if (n < 3)
+ return 0;
return n;
}
@@ -537,6 +612,7 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
pixman_region32_t repaint;
/* non-opaque region in surface coordinates: */
pixman_region32_t surface_blend;
+ pixman_region32_t *buffer_damage;
GLint filter;
int i;
@@ -548,8 +624,8 @@ draw_surface(struct weston_surface *es, struct weston_output *output,
if (!pixman_region32_not_empty(&repaint))
goto out;
- pixman_region32_subtract(&ec->primary_plane.damage,
- &ec->primary_plane.damage, &repaint);
+ buffer_damage = &output->buffer_damage[output->current_buffer];
+ pixman_region32_subtract(buffer_damage, buffer_damage, &repaint);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
@@ -627,7 +703,7 @@ gles2_renderer_repaint_output(struct weston_output *output,
struct weston_compositor *compositor = output->compositor;
EGLBoolean ret;
static int errored;
- int32_t width, height;
+ int32_t width, height, i;
width = output->current->width +
output->border.left + output->border.right;
@@ -661,6 +737,14 @@ gles2_renderer_repaint_output(struct weston_output *output,
pixman_region32_fini(&undamaged);
}
+ for (i = 0; i < 2; i++)
+ pixman_region32_union(&output->buffer_damage[i],
+ &output->buffer_damage[i],
+ output_damage);
+
+ pixman_region32_union(output_damage, output_damage,
+ &output->buffer_damage[output->current_buffer]);
+
repaint_surfaces(output, output_damage);
wl_signal_emit(&output->frame_signal, output);
@@ -672,6 +756,8 @@ gles2_renderer_repaint_output(struct weston_output *output,
print_egl_error_state();
}
+ output->current_buffer ^= 1;
+
}
static void
diff --git a/src/screenshooter.c b/src/screenshooter.c
index ba80ce5..ffcc970 100644
--- a/src/screenshooter.c
+++ b/src/screenshooter.c
@@ -261,7 +261,7 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data)
struct weston_output *output = data;
uint32_t msecs = output->frame_time;
pixman_box32_t *r;
- pixman_region32_t damage;
+ pixman_region32_t damage, *previous_damage;
int i, j, k, n, width, height, run, stride;
uint32_t delta, prev, *d, *s, *p, next;
struct {
@@ -270,9 +270,18 @@ weston_recorder_frame_notify(struct wl_listener *listener, void *data)
} header;
struct iovec v[2];
+ /* When recording, this will be exactly the region that was repainted
+ * in this frame. Since overlays are disabled, the whole primary plane
+ * damage is rendered. For the first frame, the whole output will be
+ * damaged and that damage will be added to both buffers causing the
+ * non-current buffer damage to be while output. Rendering will clear
+ * all the damage in the current buffer so in the next frame (when
+ * that is non-current) the only damage left will be the one added
+ * from the primary plane. */
+ previous_damage = &output->buffer_damage[output->current_buffer ^ 1];
+
pixman_region32_init(&damage);
- pixman_region32_intersect(&damage, &output->region,
- &output->previous_damage);
+ pixman_region32_intersect(&damage, &output->region, previous_damage);
r = pixman_region32_rectangles(&damage, &n);
if (n == 0)
diff --git a/src/shell.c b/src/shell.c
index 86ba202..f6c26eb 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -2190,7 +2190,7 @@ lock_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
if (!weston_surface_is_mapped(surface)) {
wl_list_insert(&shell->lock_layer.surface_list,
&surface->layer_link);
- weston_surface_assign_output(surface);
+ weston_surface_update_transform(surface);
weston_compositor_wake(shell->compositor);
}
}
@@ -2764,7 +2764,7 @@ show_input_panels(struct wl_listener *listener, void *data)
ws = surface->surface;
wl_list_insert(&shell->input_panel_layer.surface_list,
&ws->layer_link);
- weston_surface_assign_output(ws);
+ weston_surface_update_transform(ws);
weston_surface_damage(ws);
weston_slide_run(ws, ws->geometry.height, 0, NULL, NULL);
}
@@ -2919,7 +2919,7 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
}
if (surface_type != SHELL_SURFACE_NONE) {
- weston_surface_assign_output(surface);
+ weston_surface_update_transform(surface);
if (surface_type == SHELL_SURFACE_MAXIMIZED)
surface->output = shsurf->output;
}
@@ -2992,7 +2992,7 @@ configure(struct desktop_shell *shell, struct weston_surface *surface,
/* XXX: would a fullscreen surface need the same handling? */
if (surface->output) {
- weston_surface_assign_output(surface);
+ weston_surface_update_transform(surface);
if (surface_type == SHELL_SURFACE_MAXIMIZED)
surface->output = shsurf->output;
@@ -3130,7 +3130,7 @@ screensaver_configure(struct weston_surface *surface, int32_t sx, int32_t sy)
if (wl_list_empty(&surface->layer_link)) {
wl_list_insert(shell->lock_layer.surface_list.prev,
&surface->layer_link);
- weston_surface_assign_output(surface);
+ weston_surface_update_transform(surface);
shell->compositor->idle_time = shell->screensaver.duration;
weston_compositor_wake(shell->compositor);
shell->compositor->state = WESTON_COMPOSITOR_IDLE;
@@ -3469,7 +3469,6 @@ debug_repaint_binding(struct wl_seat *seat, uint32_t time, uint32_t key,
weston_surface_configure(surface, 0, 0, 8192, 8192);
wl_list_insert(&compositor->fade_layer.surface_list,
&surface->layer_link);
- weston_surface_assign_output(surface);
pixman_region32_init(&surface->input);
/* Here's the dirty little trick that makes the
@@ -3694,11 +3693,8 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
}
}
-int
-shell_init(struct weston_compositor *ec);
-
WL_EXPORT int
-shell_init(struct weston_compositor *ec)
+module_init(struct weston_compositor *ec)
{
struct weston_seat *seat;
struct desktop_shell *shell;
diff --git a/src/tablet-shell.c b/src/tablet-shell.c
index f17d888..3623736 100644
--- a/src/tablet-shell.c
+++ b/src/tablet-shell.c
@@ -162,7 +162,7 @@ tablet_shell_surface_configure(struct weston_surface *surface,
&surface->layer_link);
}
- weston_surface_assign_output(surface);
+ weston_surface_update_transform(surface);
}
static void
@@ -530,18 +530,15 @@ tablet_shell_destroy(struct wl_listener *listener, void *data)
free(shell);
}
-void
-shell_init(struct weston_compositor *compositor);
-
-WL_EXPORT void
-shell_init(struct weston_compositor *compositor)
+WL_EXPORT int
+module_init(struct weston_compositor *compositor)
{
struct tablet_shell *shell;
struct wl_event_loop *loop;
shell = malloc(sizeof *shell);
if (shell == NULL)
- return;
+ return -1;
memset(shell, 0, sizeof *shell);
shell->compositor = compositor;
@@ -583,4 +580,6 @@ shell_init(struct weston_compositor *compositor)
launch_ux_daemon(shell);
tablet_shell_set_state(shell, STATE_STARTING);
+
+ return 0;
}
diff --git a/src/text-backend.c b/src/text-backend.c
index ddeec20..4190fe7 100644
--- a/src/text-backend.c
+++ b/src/text-backend.c
@@ -1,5 +1,6 @@
/*
* Copyright © 2012 Openismus GmbH
+ * Copyright © 2012 Intel Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
@@ -24,8 +25,10 @@
#include "compositor.h"
#include "text-server-protocol.h"
+#include "input-method-server-protocol.h"
struct input_method;
+struct input_method_context;
struct text_model {
struct wl_resource resource;
@@ -37,13 +40,19 @@ struct text_model {
struct wl_surface *surface;
};
+struct text_model_factory {
+ struct wl_global *text_model_factory_global;
+ struct wl_listener destroy_listener;
+
+ struct weston_compositor *ec;
+};
+
struct input_method {
struct wl_resource *input_method_binding;
struct wl_global *input_method_global;
- struct wl_global *text_model_factory_global;
struct wl_listener destroy_listener;
- struct weston_compositor *ec;
+ struct weston_seat *seat;
struct text_model *model;
struct wl_list link;
@@ -51,8 +60,21 @@ struct input_method {
struct wl_listener keyboard_focus_listener;
int focus_listener_initialized;
+
+ struct input_method_context *context;
};
+struct input_method_context {
+ struct wl_resource resource;
+
+ struct text_model *model;
+
+ struct wl_list link;
+};
+
+static void input_method_context_create(struct text_model *model,
+ struct input_method *input_method);
+
static void input_method_init_seat(struct weston_seat *seat);
static void
@@ -62,8 +84,11 @@ deactivate_text_model(struct text_model *text_model,
struct weston_compositor *ec = text_model->ec;
if (input_method->model == text_model) {
+ if (input_method->input_method_binding)
+ input_method_send_deactivate(input_method->input_method_binding, &input_method->context->resource);
wl_list_remove(&input_method->link);
input_method->model = NULL;
+ input_method->context = NULL;
wl_signal_emit(&ec->hide_input_panel_signal, ec);
text_model_send_deactivated(&text_model->resource);
}
@@ -85,15 +110,21 @@ destroy_text_model(struct wl_resource *resource)
static void
text_model_set_surrounding_text(struct wl_client *client,
struct wl_resource *resource,
- const char *text)
+ const char *text,
+ uint32_t cursor,
+ uint32_t anchor)
{
-}
+ struct text_model *text_model = resource->data;
+ struct input_method *input_method, *next;
-static void
-text_model_set_cursor_index(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t index)
-{
+ wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
+ if (!input_method->context)
+ continue;
+ input_method_context_send_surrounding_text(&input_method->context->resource,
+ text,
+ cursor,
+ anchor);
+ }
}
static void
@@ -104,6 +135,7 @@ text_model_activate(struct wl_client *client,
{
struct text_model *text_model = resource->data;
struct weston_seat *weston_seat = seat->data;
+ struct input_method *input_method = weston_seat->input_method;
struct text_model *old = weston_seat->input_method->model;
struct weston_compositor *ec = text_model->ec;
@@ -115,12 +147,14 @@ text_model_activate(struct wl_client *client,
weston_seat->input_method);
}
- weston_seat->input_method->model = text_model;
- wl_list_insert(&text_model->input_methods, &weston_seat->input_method->link);
+ input_method->model = text_model;
+ wl_list_insert(&text_model->input_methods, &input_method->link);
input_method_init_seat(weston_seat);
text_model->surface = surface->data;
+ input_method_context_create(text_model, input_method);
+
wl_signal_emit(&ec->show_input_panel_signal, ec);
text_model_send_activated(&text_model->resource);
@@ -139,11 +173,17 @@ text_model_deactivate(struct wl_client *client,
}
static void
-text_model_set_selected_text(struct wl_client *client,
- struct wl_resource *resource,
- const char *text,
- int32_t index)
+text_model_reset(struct wl_client *client,
+ struct wl_resource *resource)
{
+ struct text_model *text_model = resource->data;
+ struct input_method *input_method, *next;
+
+ wl_list_for_each_safe(input_method, next, &text_model->input_methods, link) {
+ if (!input_method->context)
+ continue;
+ input_method_context_send_reset(&input_method->context->resource);
+ }
}
static void
@@ -170,10 +210,9 @@ text_model_set_content_type(struct wl_client *client,
static const struct text_model_interface text_model_implementation = {
text_model_set_surrounding_text,
- text_model_set_cursor_index,
text_model_activate,
text_model_deactivate,
- text_model_set_selected_text,
+ text_model_reset,
text_model_set_micro_focus,
text_model_set_preedit,
text_model_set_content_type
@@ -181,27 +220,26 @@ static const struct text_model_interface text_model_implementation = {
static void text_model_factory_create_text_model(struct wl_client *client,
struct wl_resource *resource,
- uint32_t id,
- struct wl_resource *surface)
+ uint32_t id)
{
- struct input_method *input_method = resource->data;
+ struct text_model_factory *text_model_factory = resource->data;
struct text_model *text_model;
text_model = calloc(1, sizeof *text_model);
- text_model->resource.destroy = destroy_text_model;
-
text_model->resource.object.id = id;
text_model->resource.object.interface = &text_model_interface;
text_model->resource.object.implementation =
(void (**)(void)) &text_model_implementation;
- text_model->resource.data = text_model;
- text_model->ec = input_method->ec;
+ text_model->resource.data = text_model;
+ text_model->resource.destroy = destroy_text_model;
- wl_client_add_resource(client, &text_model->resource);
+ text_model->ec = text_model_factory->ec;
wl_list_init(&text_model->input_methods);
+
+ wl_client_add_resource(client, &text_model->resource);
};
static const struct text_model_factory_interface text_model_factory_implementation = {
@@ -214,38 +252,149 @@ bind_text_model_factory(struct wl_client *client,
uint32_t version,
uint32_t id)
{
- struct input_method *input_method = data;
+ struct text_model_factory *text_model_factory = data;
/* No checking for duplicate binding necessary.
* No events have to be sent, so we don't need the return value. */
wl_client_add_object(client, &text_model_factory_interface,
&text_model_factory_implementation,
- id, input_method);
+ id, text_model_factory);
}
static void
-input_method_commit_string(struct wl_client *client,
- struct wl_resource *resource,
- const char *text,
- uint32_t index)
+text_model_factory_notifier_destroy(struct wl_listener *listener, void *data)
{
- struct input_method *input_method = resource->data;
+ struct text_model_factory *text_model_factory =
+ container_of(listener, struct text_model_factory, destroy_listener);
- if (input_method->model) {
- text_model_send_commit_string(&input_method->model->resource, text, index);
- }
+ wl_display_remove_global(text_model_factory->ec->wl_display,
+ text_model_factory->text_model_factory_global);
+
+ free(text_model_factory);
}
-static const struct input_method_interface input_method_implementation = {
- input_method_commit_string
+WL_EXPORT void
+text_model_factory_create(struct weston_compositor *ec)
+{
+ struct text_model_factory *text_model_factory;
+
+ text_model_factory = calloc(1, sizeof *text_model_factory);
+
+ text_model_factory->ec = ec;
+
+ text_model_factory->text_model_factory_global =
+ wl_display_add_global(ec->wl_display,
+ &text_model_factory_interface,
+ text_model_factory, bind_text_model_factory);
+
+ text_model_factory->destroy_listener.notify = text_model_factory_notifier_destroy;
+ wl_signal_add(&ec->destroy_signal, &text_model_factory->destroy_listener);
+}
+
+static void
+input_method_context_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+input_method_context_commit_string(struct wl_client *client,
+ struct wl_resource *resource,
+ const char *text,
+ uint32_t index)
+{
+ struct input_method_context *context = resource->data;
+
+ text_model_send_commit_string(&context->model->resource, text, index);
+}
+
+static void
+input_method_context_preedit_string(struct wl_client *client,
+ struct wl_resource *resource,
+ const char *text,
+ uint32_t index)
+{
+ struct input_method_context *context = resource->data;
+
+ text_model_send_preedit_string(&context->model->resource, text, index);
+}
+
+static void
+input_method_context_delete_surrounding_text(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t index,
+ uint32_t length)
+{
+ struct input_method_context *context = resource->data;
+
+ text_model_send_delete_surrounding_text(&context->model->resource, index, length);
+}
+
+static void
+input_method_context_key(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t key,
+ uint32_t state)
+{
+ struct input_method_context *context = resource->data;
+
+ text_model_send_key(&context->model->resource, key, state);
+}
+
+static const struct input_method_context_interface input_method_context_implementation = {
+ input_method_context_destroy,
+ input_method_context_commit_string,
+ input_method_context_preedit_string,
+ input_method_context_delete_surrounding_text,
+ input_method_context_key
};
static void
+destroy_input_method_context(struct wl_resource *resource)
+{
+ struct input_method_context *context = resource->data;
+
+ free(context);
+}
+
+static void
+input_method_context_create(struct text_model *model,
+ struct input_method *input_method)
+{
+ struct input_method_context *context;
+
+ if (!input_method->input_method_binding)
+ return;
+
+ context = malloc(sizeof *context);
+ if (context == NULL)
+ return;
+
+ context->resource.destroy = destroy_input_method_context;
+ context->resource.object.id = 0;
+ context->resource.object.interface = &input_method_context_interface;
+ context->resource.object.implementation =
+ (void (**)(void)) &input_method_context_implementation;
+ context->resource.data = context;
+ wl_signal_init(&context->resource.destroy_signal);
+
+ context->model = model;
+ input_method->context = context;
+
+ wl_client_add_resource(input_method->input_method_binding->client, &context->resource);
+
+ input_method_send_activate(input_method->input_method_binding, &context->resource);
+}
+
+static void
unbind_input_method(struct wl_resource *resource)
{
struct input_method *input_method = resource->data;
input_method->input_method_binding = NULL;
+ input_method->context = NULL;
+
free(resource);
}
@@ -259,7 +408,7 @@ bind_input_method(struct wl_client *client,
struct wl_resource *resource;
resource = wl_client_add_object(client, &input_method_interface,
- &input_method_implementation,
+ NULL,
id, input_method);
if (input_method->input_method_binding == NULL) {
@@ -279,10 +428,12 @@ input_method_notifier_destroy(struct wl_listener *listener, void *data)
struct input_method *input_method =
container_of(listener, struct input_method, destroy_listener);
- wl_display_remove_global(input_method->ec->wl_display,
+ if (input_method->model)
+ deactivate_text_model(input_method->model, input_method);
+
+ wl_display_remove_global(input_method->seat->compositor->wl_display,
input_method->input_method_global);
- wl_display_remove_global(input_method->ec->wl_display,
- input_method->text_model_factory_global);
+
free(input_method);
}
@@ -316,7 +467,7 @@ input_method_init_seat(struct weston_seat *seat)
seat->input_method->focus_listener_initialized = 1;
}
-void
+WL_EXPORT void
input_method_create(struct weston_compositor *ec,
struct weston_seat *seat)
{
@@ -324,22 +475,18 @@ input_method_create(struct weston_compositor *ec,
input_method = calloc(1, sizeof *input_method);
- input_method->ec = ec;
+ input_method->seat = seat;
input_method->model = NULL;
input_method->focus_listener_initialized = 0;
+ input_method->context = NULL;
input_method->input_method_global =
wl_display_add_global(ec->wl_display,
&input_method_interface,
input_method, bind_input_method);
- input_method->text_model_factory_global =
- wl_display_add_global(ec->wl_display,
- &text_model_factory_interface,
- input_method, bind_text_model_factory);
-
input_method->destroy_listener.notify = input_method_notifier_destroy;
- wl_signal_add(&ec->destroy_signal, &input_method->destroy_listener);
+ wl_signal_add(&seat->seat.destroy_signal, &input_method->destroy_listener);
seat->input_method = input_method;
}
diff --git a/src/xwayland/launcher.c b/src/xwayland/launcher.c
index aab74f0..00f064e 100644
--- a/src/xwayland/launcher.c
+++ b/src/xwayland/launcher.c
@@ -312,7 +312,7 @@ weston_xserver_destroy(struct wl_listener *l, void *data)
}
WL_EXPORT int
-weston_xserver_init(struct weston_compositor *compositor)
+module_init(struct weston_compositor *compositor)
{
struct wl_display *display = compositor->wl_display;
struct weston_xserver *mxs;
diff --git a/tests/event-test.c b/tests/event-test.c
index e137213..2cbfc2d 100644
--- a/tests/event-test.c
+++ b/tests/event-test.c
@@ -49,7 +49,7 @@ handle_surface(struct test_client *client)
surface = (struct weston_surface *) resource;
weston_surface_configure(surface, 100, 100, 200, 200);
- weston_surface_assign_output(surface);
+ weston_surface_update_transform(surface);
weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
wl_list_insert(&layer->surface_list, &surface->layer_link);
weston_surface_damage(surface);
diff --git a/tests/test-text-client.c b/tests/test-text-client.c
index 828f3a0..897909a 100644
--- a/tests/test-text-client.c
+++ b/tests/test-text-client.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2012 Openismus GmbH
+ * Copyright © 2012 Intel Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -60,6 +60,14 @@ text_model_preedit_string(void *data,
}
static void
+text_model_delete_surrounding_text(void *data,
+ struct text_model *text_model,
+ int32_t index,
+ uint32_t length)
+{
+}
+
+static void
text_model_preedit_styling(void *data,
struct text_model *text_model)
{
@@ -67,10 +75,12 @@ text_model_preedit_styling(void *data,
static void
text_model_key(void *data,
- struct text_model *text_model)
+ struct text_model *text_model,
+ uint32_t key,
+ uint32_t state)
{
}
-
+
static void
text_model_selection_replacement(void *data,
struct text_model *text_model)
@@ -112,6 +122,7 @@ text_model_deactivated(void *data,
static const struct text_model_listener text_model_listener = {
text_model_commit_string,
text_model_preedit_string,
+ text_model_delete_surrounding_text,
text_model_preedit_styling,
text_model_key,
text_model_selection_replacement,
@@ -160,7 +171,7 @@ create_text_model(int fd, struct display *display)
char buf[64];
int len;
- display->text_model = text_model_factory_create_text_model(display->factory, display->surface);
+ display->text_model = text_model_factory_create_text_model(display->factory);
text_model_add_listener(display->text_model, &text_model_listener, display);
wl_display_flush(display->display);
diff --git a/tests/text-test.c b/tests/text-test.c
index bd2a5c5..942cb3b 100644
--- a/tests/text-test.c
+++ b/tests/text-test.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2012 Openismus GmbH
+ * Copyright © 2012 Intel Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
@@ -178,7 +178,7 @@ handle_surface(struct test_client *client)
surface = (struct weston_surface *) resource;
weston_surface_configure(surface, 100, 100, 200, 200);
- weston_surface_assign_output(surface);
+ weston_surface_update_transform(surface);
weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
data->layer = malloc(sizeof *data->layer);
diff --git a/tests/weston-test b/tests/weston-test
index 2314514..27b40de 100644
--- a/tests/weston-test
+++ b/tests/weston-test
@@ -1,4 +1,4 @@
#!/bin/sh
-../src/weston --module=$abs_builddir/.libs/${1/.la/.so}
+../src/weston --modules=$abs_builddir/.libs/${1/.la/.so}