summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/.gitignore13
-rw-r--r--tests/Makefile.am158
-rw-r--r--tests/button-test.c55
-rw-r--r--tests/config-parser-test.c203
-rw-r--r--tests/event-test.c418
-rw-r--r--tests/keyboard-test.c65
-rw-r--r--tests/matrix-test.c419
-rw-r--r--tests/setbacklight.c186
-rw-r--r--tests/subsurface-test.c549
-rw-r--r--tests/surface-global-test.c80
-rw-r--r--tests/surface-test.c63
-rw-r--r--tests/text-test.c214
-rw-r--r--tests/vertex-clip-test.c219
-rw-r--r--tests/weston-test-client-helper.c539
-rw-r--r--tests/weston-test-client-helper.h123
-rw-r--r--tests/weston-test-runner.c167
-rw-r--r--tests/weston-test-runner.h76
-rw-r--r--tests/weston-test.c250
-rwxr-xr-xtests/weston-tests-env43
-rw-r--r--tests/xwayland-test.c142
20 files changed, 3982 insertions, 0 deletions
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 00000000..aba378c3
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1,13 @@
+*.test
+*.trs
+*.weston
+logs
+matrix-test
+setbacklight
+test-client
+test-text-client
+wayland-test-client-protocol.h
+wayland-test-protocol.c
+wayland-test-server-protocol.h
+subsurface-client-protocol.h
+subsurface-protocol.c
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 00000000..5be52c6e
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,158 @@
+TESTS = $(shared_tests) $(module_tests) $(weston_tests)
+
+shared_tests = \
+ config-parser.test \
+ vertex-clip.test
+
+module_tests = \
+ surface-test.la \
+ surface-global-test.la
+
+weston_test = weston-test.la
+
+weston_tests = \
+ keyboard.weston \
+ event.weston \
+ button.weston \
+ text.weston \
+ subsurface.weston \
+ $(xwayland_test)
+
+AM_TESTS_ENVIRONMENT = \
+ abs_builddir='$(abs_builddir)'; export abs_builddir;
+
+TEST_EXTENSIONS = .la .weston
+LA_LOG_COMPILER = $(srcdir)/weston-tests-env
+WESTON_LOG_COMPILER = $(srcdir)/weston-tests-env
+
+clean-local:
+ -rm -rf logs
+
+# To remove when automake 1.11 support is dropped
+export abs_builddir
+
+noinst_LTLIBRARIES = \
+ $(weston_test) \
+ $(module_tests)
+
+noinst_PROGRAMS = \
+ $(setbacklight) \
+ $(shared_tests) \
+ $(weston_tests) \
+ matrix-test
+
+AM_CFLAGS = $(GCC_CFLAGS)
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src \
+ -I$(top_srcdir)/shared \
+ -I$(top_builddir)/src \
+ -DUNIT_TEST \
+ $(COMPOSITOR_CFLAGS)
+
+surface_global_test_la_SOURCES = surface-global-test.c
+surface_global_test_la_LDFLAGS = -module -avoid-version -rpath $(libdir)
+surface_test_la_SOURCES = surface-test.c
+surface_test_la_LDFLAGS = -module -avoid-version -rpath $(libdir)
+
+weston_test_la_LIBADD = $(COMPOSITOR_LIBS) \
+ ../shared/libshared.la
+weston_test_la_LDFLAGS = -module -avoid-version -rpath $(libdir)
+weston_test_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+weston_test_la_SOURCES = \
+ weston-test.c \
+ wayland-test-protocol.c \
+ wayland-test-server-protocol.h
+
+weston_test_runner_src = \
+ weston-test-runner.c \
+ weston-test-runner.h
+
+check_LTLIBRARIES = libshared-test.la
+
+libshared_test_la_SOURCES = \
+ $(weston_test_runner_src)
+libshared_test_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+
+config_parser_test_LDADD = \
+ ../shared/libshared.la \
+ libshared-test.la \
+ $(COMPOSITOR_LIBS)
+config_parser_test_SOURCES = \
+ config-parser-test.c
+vertex_clip_test_SOURCES = \
+ vertex-clip-test.c \
+ ../src/vertex-clipping.c \
+ ../src/vertex-clipping.h
+vertex_clip_test_LDADD = \
+ libshared-test.la \
+ -lm -lrt
+
+weston_test_client_src = \
+ weston-test-client-helper.c \
+ weston-test-client-helper.h \
+ wayland-test-protocol.c \
+ wayland-test-client-protocol.h \
+ subsurface-protocol.c \
+ subsurface-client-protocol.h
+weston_test_client_libs = \
+ $(SIMPLE_CLIENT_LIBS) \
+ ../shared/libshared.la \
+ libshared-test.la
+
+keyboard_weston_SOURCES = keyboard-test.c $(weston_test_client_src)
+keyboard_weston_LDADD = $(weston_test_client_libs)
+
+event_weston_SOURCES = event-test.c $(weston_test_client_src)
+event_weston_LDADD = $(weston_test_client_libs)
+
+button_weston_SOURCES = button-test.c $(weston_test_client_src)
+button_weston_LDADD = $(weston_test_client_libs)
+
+text_weston_SOURCES = \
+ text-test.c \
+ ../clients/text-protocol.c \
+ $(weston_test_client_src)
+text_weston_LDADD = $(weston_test_client_libs)
+
+subsurface_weston_SOURCES = subsurface-test.c $(weston_test_client_src)
+subsurface_weston_LDADD = $(weston_test_client_libs)
+
+xwayland_weston_SOURCES = xwayland-test.c $(weston_test_client_src)
+
+xwayland_weston_LDADD = $(weston_test_client_libs) $(XWAYLAND_TEST_LIBS)
+
+if ENABLE_XWAYLAND_TEST
+xwayland_test = xwayland.weston
+endif
+
+matrix_test_SOURCES = \
+ matrix-test.c \
+ $(top_srcdir)/shared/matrix.c \
+ $(top_srcdir)/shared/matrix.h
+matrix_test_LDADD = -lm -lrt
+
+setbacklight_SOURCES = \
+ setbacklight.c \
+ $(top_srcdir)/src/libbacklight.c \
+ $(top_srcdir)/src/libbacklight.h
+
+setbacklight_CFLAGS = $(AM_CFLAGS) $(SETBACKLIGHT_CFLAGS)
+setbacklight_LDADD = $(SETBACKLIGHT_LIBS)
+
+if BUILD_SETBACKLIGHT
+setbacklight = setbacklight
+endif
+
+EXTRA_DIST = weston-tests-env
+
+BUILT_SOURCES = \
+ subsurface-protocol.c \
+ subsurface-client-protocol.h \
+ wayland-test-protocol.c \
+ wayland-test-server-protocol.h \
+ wayland-test-client-protocol.h
+
+CLEANFILES = $(BUILT_SOURCES)
+
+wayland_protocoldir = $(top_srcdir)/protocol
+include $(top_srcdir)/wayland-scanner.mk
diff --git a/tests/button-test.c b/tests/button-test.c
new file mode 100644
index 00000000..dc02fd44
--- /dev/null
+++ b/tests/button-test.c
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include <linux/input.h>
+#include "weston-test-client-helper.h"
+
+TEST(simple_button_test)
+{
+ struct client *client;
+ struct pointer *pointer;
+
+ client = client_create(100, 100, 100, 100);
+ assert(client);
+
+ pointer = client->input->pointer;
+
+ assert(pointer->button == 0);
+ assert(pointer->state == 0);
+
+ wl_test_move_pointer(client->test->wl_test, 150, 150);
+ client_roundtrip(client);
+ assert(pointer->x == 50);
+ assert(pointer->y == 50);
+
+ wl_test_send_button(client->test->wl_test, BTN_LEFT,
+ WL_POINTER_BUTTON_STATE_PRESSED);
+ client_roundtrip(client);
+ assert(pointer->button == BTN_LEFT);
+ assert(pointer->state == WL_POINTER_BUTTON_STATE_PRESSED);
+
+ wl_test_send_button(client->test->wl_test, BTN_LEFT,
+ WL_POINTER_BUTTON_STATE_RELEASED);
+ client_roundtrip(client);
+ assert(pointer->button == BTN_LEFT);
+ assert(pointer->state == WL_POINTER_BUTTON_STATE_RELEASED);
+}
diff --git a/tests/config-parser-test.c b/tests/config-parser-test.c
new file mode 100644
index 00000000..4b8fc7e7
--- /dev/null
+++ b/tests/config-parser-test.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright © 2013 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.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "config-parser.h"
+
+static struct weston_config *
+run_test(const char *text)
+{
+ struct weston_config *config;
+ char file[] = "/tmp/weston-config-parser-test-XXXXXX";
+ int fd, len;
+
+ fd = mkstemp(file);
+ len = write(fd, text, strlen(text));
+ assert(len == (int) strlen(text));
+
+ config = weston_config_parse(file);
+ close(fd);
+ unlink(file);
+
+ return config;
+}
+
+static const char t0[] =
+ "# nothing in this file...\n";
+
+static const char t1[] =
+ "# comment line here...\n"
+ "\n"
+ "[foo]\n"
+ "a=b\n"
+ "name= Roy Batty \n"
+ "\n"
+ "\n"
+ "[bar]\n"
+ "# more comments\n"
+ "number=5252\n"
+ "flag=false\n"
+ "\n"
+ "[stuff]\n"
+ "flag= true \n"
+ "\n"
+ "[bucket]\n"
+ "color=blue \n"
+ "contents=live crabs\n"
+ "pinchy=true\n"
+ "\n"
+ "[bucket]\n"
+ "material=plastic \n"
+ "color=red\n"
+ "contents=sand\n";
+
+static const char *section_names[] = {
+ "foo", "bar", "stuff", "bucket", "bucket"
+};
+
+static const char t2[] =
+ "# invalid section...\n"
+ "[this bracket isn't closed\n";
+
+static const char t3[] =
+ "# line without = ...\n"
+ "[bambam]\n"
+ "this line isn't any kind of valid\n";
+
+static const char t4[] =
+ "# starting with = ...\n"
+ "[bambam]\n"
+ "=not valid at all\n";
+
+int main(int argc, char *argv[])
+{
+ struct weston_config *config;
+ struct weston_config_section *section;
+ const char *name;
+ char *s;
+ int r, b, i;
+ int32_t n;
+ uint32_t u;
+
+ config = run_test(t0);
+ assert(config);
+ weston_config_destroy(config);
+
+ config = run_test(t1);
+ assert(config);
+ section = weston_config_get_section(config, "mollusc", NULL, NULL);
+ assert(section == NULL);
+
+ section = weston_config_get_section(config, "foo", NULL, NULL);
+ r = weston_config_section_get_string(section, "a", &s, NULL);
+ assert(r == 0 && strcmp(s, "b") == 0);
+ free(s);
+
+ section = weston_config_get_section(config, "foo", NULL, NULL);
+ r = weston_config_section_get_string(section, "b", &s, NULL);
+ assert(r == -1 && errno == ENOENT && s == NULL);
+
+ section = weston_config_get_section(config, "foo", NULL, NULL);
+ r = weston_config_section_get_string(section, "name", &s, NULL);
+ assert(r == 0 && strcmp(s, "Roy Batty") == 0);
+ free(s);
+
+ section = weston_config_get_section(config, "bar", NULL, NULL);
+ r = weston_config_section_get_string(section, "a", &s, "boo");
+ assert(r == -1 && errno == ENOENT && strcmp(s, "boo") == 0);
+ free(s);
+
+ section = weston_config_get_section(config, "bar", NULL, NULL);
+ r = weston_config_section_get_int(section, "number", &n, 600);
+ assert(r == 0 && n == 5252);
+
+ section = weston_config_get_section(config, "bar", NULL, NULL);
+ r = weston_config_section_get_int(section, "+++", &n, 700);
+ assert(r == -1 && errno == ENOENT && n == 700);
+
+ section = weston_config_get_section(config, "bar", NULL, NULL);
+ r = weston_config_section_get_uint(section, "number", &u, 600);
+ assert(r == 0 && u == 5252);
+
+ section = weston_config_get_section(config, "bar", NULL, NULL);
+ r = weston_config_section_get_uint(section, "+++", &u, 600);
+ assert(r == -1 && errno == ENOENT && u == 600);
+
+ section = weston_config_get_section(config, "bar", NULL, NULL);
+ r = weston_config_section_get_bool(section, "flag", &b, 600);
+ assert(r == 0 && b == 0);
+
+ section = weston_config_get_section(config, "stuff", NULL, NULL);
+ r = weston_config_section_get_bool(section, "flag", &b, -1);
+ assert(r == 0 && b == 1);
+
+ section = weston_config_get_section(config, "stuff", NULL, NULL);
+ r = weston_config_section_get_bool(section, "bonk", &b, -1);
+ assert(r == -1 && errno == ENOENT && b == -1);
+
+ section = weston_config_get_section(config, "bucket", "color", "blue");
+ r = weston_config_section_get_string(section, "contents", &s, NULL);
+ assert(r == 0 && strcmp(s, "live crabs") == 0);
+ free(s);
+
+ section = weston_config_get_section(config, "bucket", "color", "red");
+ r = weston_config_section_get_string(section, "contents", &s, NULL);
+ assert(r == 0 && strcmp(s, "sand") == 0);
+ free(s);
+
+ section = weston_config_get_section(config, "bucket", "color", "pink");
+ assert(section == NULL);
+ r = weston_config_section_get_string(section, "contents", &s, "eels");
+ assert(r == -1 && errno == ENOENT && strcmp(s, "eels") == 0);
+ free(s);
+
+ section = NULL;
+ i = 0;
+ while (weston_config_next_section(config, &section, &name))
+ assert(strcmp(section_names[i++], name) == 0);
+ assert(i == 5);
+
+ weston_config_destroy(config);
+
+ config = run_test(t2);
+ assert(config == NULL);
+
+ config = run_test(t3);
+ assert(config == NULL);
+
+ config = run_test(t4);
+ assert(config == NULL);
+
+ weston_config_destroy(NULL);
+ assert(weston_config_next_section(NULL, NULL, NULL) == 0);
+
+ section = weston_config_get_section(NULL, "bucket", NULL, NULL);
+ assert(section == NULL);
+
+ return 0;
+}
diff --git a/tests/event-test.c b/tests/event-test.c
new file mode 100644
index 00000000..980dfaad
--- /dev/null
+++ b/tests/event-test.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2013 Collabora, Ltd.
+ *
+ * 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.
+ */
+
+#include "weston-test-client-helper.h"
+
+static void
+check_pointer(struct client *client, int x, int y)
+{
+ int sx, sy;
+
+ /* check that the client got the global pointer update */
+ assert(client->test->pointer_x == x);
+ assert(client->test->pointer_y == y);
+
+ /* Does global pointer map onto the surface? */
+ if (surface_contains(client->surface, x, y)) {
+ /* check that the surface has the pointer focus */
+ assert(client->input->pointer->focus == client->surface);
+
+ /*
+ * check that the local surface pointer maps
+ * to the global pointer.
+ */
+ sx = client->input->pointer->x + client->surface->x;
+ sy = client->input->pointer->y + client->surface->y;
+ assert(sx == x);
+ assert(sy == y);
+ } else {
+ /*
+ * The global pointer does not map onto surface. So
+ * check that it doesn't have the pointer focus.
+ */
+ assert(client->input->pointer->focus == NULL);
+ }
+}
+
+static void
+check_pointer_move(struct client *client, int x, int y)
+{
+ wl_test_move_pointer(client->test->wl_test, x, y);
+ client_roundtrip(client);
+ check_pointer(client, x, y);
+}
+
+TEST(test_pointer_top_left)
+{
+ struct client *client;
+ int x, y;
+
+ client = client_create(46, 76, 111, 134);
+ assert(client);
+
+ /* move pointer outside top left */
+ x = client->surface->x - 1;
+ y = client->surface->y - 1;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer on top left */
+ x += 1; y += 1;
+ assert(surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer outside top left */
+ x -= 1; y -= 1;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+}
+
+TEST(test_pointer_bottom_left)
+{
+ struct client *client;
+ int x, y;
+
+ client = client_create(99, 100, 100, 98);
+ assert(client);
+
+ /* move pointer outside bottom left */
+ x = client->surface->x - 1;
+ y = client->surface->y + client->surface->height;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer on bottom left */
+ x += 1; y -= 1;
+ assert(surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer outside bottom left */
+ x -= 1; y += 1;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+}
+
+TEST(test_pointer_top_right)
+{
+ struct client *client;
+ int x, y;
+
+ client = client_create(48, 100, 67, 100);
+ assert(client);
+
+ /* move pointer outside top right */
+ x = client->surface->x + client->surface->width;
+ y = client->surface->y - 1;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer on top right */
+ x -= 1; y += 1;
+ assert(surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer outside top right */
+ x += 1; y -= 1;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+}
+
+TEST(test_pointer_bottom_right)
+{
+ struct client *client;
+ int x, y;
+
+ client = client_create(100, 123, 100, 69);
+ assert(client);
+
+ /* move pointer outside bottom right */
+ x = client->surface->x + client->surface->width;
+ y = client->surface->y + client->surface->height;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer on bottom right */
+ x -= 1; y -= 1;
+ assert(surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer outside bottom right */
+ x += 1; y += 1;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+}
+
+TEST(test_pointer_top_center)
+{
+ struct client *client;
+ int x, y;
+
+ client = client_create(100, 201, 100, 50);
+ assert(client);
+
+ /* move pointer outside top center */
+ x = client->surface->x + client->surface->width/2;
+ y = client->surface->y - 1;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer on top center */
+ y += 1;
+ assert(surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer outside top center */
+ y -= 1;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+}
+
+TEST(test_pointer_bottom_center)
+{
+ struct client *client;
+ int x, y;
+
+ client = client_create(100, 45, 67, 100);
+ assert(client);
+
+ /* move pointer outside bottom center */
+ x = client->surface->x + client->surface->width/2;
+ y = client->surface->y + client->surface->height;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer on bottom center */
+ y -= 1;
+ assert(surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer outside bottom center */
+ y += 1;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+}
+
+TEST(test_pointer_left_center)
+{
+ struct client *client;
+ int x, y;
+
+ client = client_create(167, 45, 78, 100);
+ assert(client);
+
+ /* move pointer outside left center */
+ x = client->surface->x - 1;
+ y = client->surface->y + client->surface->height/2;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer on left center */
+ x += 1;
+ assert(surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer outside left center */
+ x -= 1;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+}
+
+TEST(test_pointer_right_center)
+{
+ struct client *client;
+ int x, y;
+
+ client = client_create(110, 37, 100, 46);
+ assert(client);
+
+ /* move pointer outside right center */
+ x = client->surface->x + client->surface->width;
+ y = client->surface->y + client->surface->height/2;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer on right center */
+ x -= 1;
+ assert(surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+
+ /* move pointer outside right center */
+ x += 1;
+ assert(!surface_contains(client->surface, x, y));
+ check_pointer_move(client, x, y);
+}
+
+TEST(test_pointer_surface_move)
+{
+ struct client *client;
+
+ client = client_create(100, 100, 100, 100);
+ assert(client);
+
+ /* move pointer outside of client */
+ assert(!surface_contains(client->surface, 50, 50));
+ check_pointer_move(client, 50, 50);
+
+ /* move client center to pointer */
+ move_client(client, 0, 0);
+ assert(surface_contains(client->surface, 50, 50));
+ check_pointer(client, 50, 50);
+}
+
+static int
+output_contains_client(struct client *client)
+{
+ struct output *output = client->output;
+ struct surface *surface = client->surface;
+
+ return !(output->x >= surface->x + surface->width
+ || output->x + output->width <= surface->x
+ || output->y >= surface->y + surface->height
+ || output->y + output->height <= surface->y);
+}
+
+static void
+check_client_move(struct client *client, int x, int y)
+{
+ move_client(client, x, y);
+
+ if (output_contains_client(client)) {
+ assert(client->surface->output == client->output);
+ } else {
+ assert(client->surface->output == NULL);
+ }
+}
+
+TEST(test_surface_output)
+{
+ struct client *client;
+ int x, y;
+
+ client = client_create(100, 100, 100, 100);
+ assert(client);
+
+ assert(output_contains_client(client));
+
+ /* not visible */
+ x = 0;
+ y = -client->surface->height;
+ check_client_move(client, x, y);
+
+ /* visible */
+ check_client_move(client, x, ++y);
+
+ /* not visible */
+ x = -client->surface->width;
+ y = 0;
+ check_client_move(client, x, y);
+
+ /* visible */
+ check_client_move(client, ++x, y);
+
+ /* not visible */
+ x = client->output->width;
+ y = 0;
+ check_client_move(client, x, y);
+
+ /* visible */
+ check_client_move(client, --x, y);
+ assert(output_contains_client(client));
+
+ /* not visible */
+ x = 0;
+ y = client->output->height;
+ check_client_move(client, x, y);
+ assert(!output_contains_client(client));
+
+ /* visible */
+ check_client_move(client, x, --y);
+ assert(output_contains_client(client));
+}
+
+static void
+buffer_release_handler(void *data, struct wl_buffer *buffer)
+{
+ int *released = data;
+
+ *released = 1;
+}
+
+static struct wl_buffer_listener buffer_listener = {
+ buffer_release_handler
+};
+
+TEST(buffer_release)
+{
+ struct client *client;
+ struct wl_surface *surface;
+ struct wl_buffer *buf1;
+ struct wl_buffer *buf2;
+ struct wl_buffer *buf3;
+ int buf1_released = 0;
+ int buf2_released = 0;
+ int buf3_released = 0;
+ int frame;
+
+ client = client_create(100, 100, 100, 100);
+ assert(client);
+ surface = client->surface->wl_surface;
+
+ buf1 = create_shm_buffer(client, 100, 100, NULL);
+ wl_buffer_add_listener(buf1, &buffer_listener, &buf1_released);
+
+ buf2 = create_shm_buffer(client, 100, 100, NULL);
+ wl_buffer_add_listener(buf2, &buffer_listener, &buf2_released);
+
+ buf3 = create_shm_buffer(client, 100, 100, NULL);
+ wl_buffer_add_listener(buf3, &buffer_listener, &buf3_released);
+
+ /*
+ * buf1 must never be released, since it is replaced before
+ * it is committed, therefore it never becomes busy.
+ */
+
+ wl_surface_attach(surface, buf1, 0, 0);
+ wl_surface_attach(surface, buf2, 0, 0);
+ frame_callback_set(surface, &frame);
+ wl_surface_commit(surface);
+ frame_callback_wait(client, &frame);
+ assert(buf1_released == 0);
+ /* buf2 may or may not be released */
+ assert(buf3_released == 0);
+
+ wl_surface_attach(surface, buf3, 0, 0);
+ frame_callback_set(surface, &frame);
+ wl_surface_commit(surface);
+ frame_callback_wait(client, &frame);
+ assert(buf1_released == 0);
+ assert(buf2_released == 1);
+ /* buf3 may or may not be released */
+
+ wl_surface_attach(surface, client->surface->wl_buffer, 0, 0);
+ frame_callback_set(surface, &frame);
+ wl_surface_commit(surface);
+ frame_callback_wait(client, &frame);
+ assert(buf1_released == 0);
+ assert(buf2_released == 1);
+ assert(buf3_released == 1);
+}
diff --git a/tests/keyboard-test.c b/tests/keyboard-test.c
new file mode 100644
index 00000000..542bf4eb
--- /dev/null
+++ b/tests/keyboard-test.c
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#include "weston-test-client-helper.h"
+
+TEST(simple_keyboard_test)
+{
+ struct client *client;
+ struct surface *expect_focus = NULL;
+ struct keyboard *keyboard;
+ uint32_t expect_key = 0;
+ uint32_t expect_state = 0;
+
+ client = client_create(10, 10, 1, 1);
+ assert(client);
+
+ keyboard = client->input->keyboard;
+
+ while(1) {
+ assert(keyboard->key == expect_key);
+ assert(keyboard->state == expect_state);
+ assert(keyboard->focus == expect_focus);
+
+ if (keyboard->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ expect_state = WL_KEYBOARD_KEY_STATE_RELEASED;
+ wl_test_send_key(client->test->wl_test, expect_key,
+ expect_state);
+ } else if (keyboard->focus) {
+ expect_focus = NULL;
+ wl_test_activate_surface(client->test->wl_test,
+ NULL);
+ } else if (expect_key < 10) {
+ expect_key++;
+ expect_focus = client->surface;
+ expect_state = WL_KEYBOARD_KEY_STATE_PRESSED;
+ wl_test_activate_surface(client->test->wl_test,
+ expect_focus->wl_surface);
+ wl_test_send_key(client->test->wl_test, expect_key,
+ expect_state);
+ } else {
+ break;
+ }
+
+ client_roundtrip(client);
+ }
+}
diff --git a/tests/matrix-test.c b/tests/matrix-test.c
new file mode 100644
index 00000000..5b0513f3
--- /dev/null
+++ b/tests/matrix-test.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+
+#include "../shared/matrix.h"
+
+struct inverse_matrix {
+ double LU[16]; /* column-major */
+ unsigned perm[4]; /* permutation */
+};
+
+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 double
+det3x3(const float *c0, const float *c1, const float *c2)
+{
+ return (double)
+ c0[0] * c1[1] * c2[2] +
+ c1[0] * c2[1] * c0[2] +
+ c2[0] * c0[1] * c1[2] -
+ c0[2] * c1[1] * c2[0] -
+ c1[2] * c2[1] * c0[0] -
+ c2[2] * c0[1] * c1[0];
+}
+
+static double
+determinant(const struct weston_matrix *m)
+{
+ double det = 0;
+#if 1
+ /* develop on last row */
+ det -= m->d[3 + 0 * 4] * det3x3(&m->d[4], &m->d[8], &m->d[12]);
+ det += m->d[3 + 1 * 4] * det3x3(&m->d[0], &m->d[8], &m->d[12]);
+ det -= m->d[3 + 2 * 4] * det3x3(&m->d[0], &m->d[4], &m->d[12]);
+ det += m->d[3 + 3 * 4] * det3x3(&m->d[0], &m->d[4], &m->d[8]);
+#else
+ /* develop on first row */
+ det += m->d[0 + 0 * 4] * det3x3(&m->d[5], &m->d[9], &m->d[13]);
+ det -= m->d[0 + 1 * 4] * det3x3(&m->d[1], &m->d[9], &m->d[13]);
+ det += m->d[0 + 2 * 4] * det3x3(&m->d[1], &m->d[5], &m->d[13]);
+ det -= m->d[0 + 3 * 4] * det3x3(&m->d[1], &m->d[5], &m->d[9]);
+#endif
+ return det;
+}
+
+static void
+print_permutation_matrix(const struct inverse_matrix *m)
+{
+ const unsigned *p = m->perm;
+ const char *row[4] = {
+ "1 0 0 0\n",
+ "0 1 0 0\n",
+ "0 0 1 0\n",
+ "0 0 0 1\n"
+ };
+
+ printf(" P =\n%s%s%s%s", row[p[0]], row[p[1]], row[p[2]], row[p[3]]);
+}
+
+static void
+print_LU_decomposition(const struct inverse_matrix *m)
+{
+ unsigned r, c;
+
+ printf(" L "
+ " U\n");
+ for (r = 0; r < 4; ++r) {
+ double v;
+
+ for (c = 0; c < 4; ++c) {
+ if (c < r)
+ v = m->LU[r + c * 4];
+ else if (c == r)
+ v = 1.0;
+ else
+ v = 0.0;
+ printf(" %12.6f", v);
+ }
+
+ printf(" | ");
+
+ for (c = 0; c < 4; ++c) {
+ if (c >= r)
+ v = m->LU[r + c * 4];
+ else
+ v = 0.0;
+ printf(" %12.6f", v);
+ }
+ printf("\n");
+ }
+}
+
+static void
+print_inverse_data_matrix(const struct inverse_matrix *m)
+{
+ unsigned r, c;
+
+ for (r = 0; r < 4; ++r) {
+ for (c = 0; c < 4; ++c)
+ printf(" %12.6f", m->LU[r + c * 4]);
+ printf("\n");
+ }
+
+ printf("permutation: ");
+ for (r = 0; r < 4; ++r)
+ printf(" %u", m->perm[r]);
+ printf("\n");
+}
+
+static void
+print_matrix(const struct weston_matrix *m)
+{
+ unsigned r, c;
+
+ for (r = 0; r < 4; ++r) {
+ for (c = 0; c < 4; ++c)
+ printf(" %14.6e", m->d[r + c * 4]);
+ printf("\n");
+ }
+}
+
+static double
+frand(void)
+{
+ double r = random();
+ return r / (double)(RAND_MAX / 2) - 1.0f;
+}
+
+static void
+randomize_matrix(struct weston_matrix *m)
+{
+ unsigned i;
+ for (i = 0; i < 16; ++i)
+#if 1
+ m->d[i] = frand() * exp(10.0 * frand());
+#else
+ m->d[i] = frand();
+#endif
+}
+
+/* Take a matrix, compute inverse, multiply together
+ * and subtract the identity matrix to get the error matrix.
+ * Return the largest absolute value from the error matrix.
+ */
+static double
+test_inverse(struct weston_matrix *m)
+{
+ unsigned i;
+ struct inverse_matrix q;
+ double errsup = 0.0;
+
+ if (matrix_invert(q.LU, q.perm, m) != 0)
+ return INFINITY;
+
+ for (i = 0; i < 4; ++i)
+ inverse_transform(q.LU, q.perm, &m->d[i * 4]);
+
+ m->d[0] -= 1.0f;
+ m->d[5] -= 1.0f;
+ m->d[10] -= 1.0f;
+ m->d[15] -= 1.0f;
+
+ for (i = 0; i < 16; ++i) {
+ double err = fabs(m->d[i]);
+ if (err > errsup)
+ errsup = err;
+ }
+
+ return errsup;
+}
+
+enum {
+ TEST_OK,
+ TEST_NOT_INVERTIBLE_OK,
+ TEST_FAIL,
+ TEST_COUNT
+};
+
+static int
+test(void)
+{
+ struct weston_matrix m;
+ double det, errsup;
+
+ randomize_matrix(&m);
+ det = determinant(&m);
+
+ errsup = test_inverse(&m);
+ if (errsup < 1e-6)
+ return TEST_OK;
+
+ if (fabs(det) < 1e-5 && isinf(errsup))
+ return TEST_NOT_INVERTIBLE_OK;
+
+ printf("test fail, det: %g, error sup: %g\n", det, errsup);
+
+ return TEST_FAIL;
+}
+
+static int running;
+static void
+stopme(int n)
+{
+ running = 0;
+}
+
+static void
+test_loop_precision(void)
+{
+ int counts[TEST_COUNT] = { 0 };
+
+ printf("\nRunning a test loop for 10 seconds...\n");
+ running = 1;
+ alarm(10);
+ while (running) {
+ counts[test()]++;
+ }
+
+ printf("tests: %d ok, %d not invertible but ok, %d failed.\n"
+ "Total: %d iterations.\n",
+ counts[TEST_OK], counts[TEST_NOT_INVERTIBLE_OK],
+ counts[TEST_FAIL],
+ counts[TEST_OK] + counts[TEST_NOT_INVERTIBLE_OK] +
+ counts[TEST_FAIL]);
+}
+
+static void __attribute__((noinline))
+test_loop_speed_matrixvector(void)
+{
+ struct weston_matrix m;
+ struct weston_vector v = { { 0.5, 0.5, 0.5, 1.0 } };
+ unsigned long count = 0;
+ double t;
+
+ printf("\nRunning 3 s test on weston_matrix_transform()...\n");
+
+ weston_matrix_init(&m);
+
+ running = 1;
+ alarm(3);
+ reset_timer();
+ while (running) {
+ weston_matrix_transform(&m, &v);
+ count++;
+ }
+ t = read_timer();
+
+ printf("%lu iterations in %f seconds, avg. %.1f us/iter.\n",
+ count, t, 1e9 * t / count);
+}
+
+static void __attribute__((noinline))
+test_loop_speed_inversetransform(void)
+{
+ struct weston_matrix m;
+ struct inverse_matrix inv;
+ struct weston_vector v = { { 0.5, 0.5, 0.5, 1.0 } };
+ unsigned long count = 0;
+ double t;
+
+ printf("\nRunning 3 s test on inverse_transform()...\n");
+
+ weston_matrix_init(&m);
+ matrix_invert(inv.LU, inv.perm, &m);
+
+ running = 1;
+ alarm(3);
+ reset_timer();
+ while (running) {
+ inverse_transform(inv.LU, inv.perm, v.f);
+ count++;
+ }
+ t = read_timer();
+
+ printf("%lu iterations in %f seconds, avg. %.1f us/iter.\n",
+ count, t, 1e9 * t / count);
+}
+
+static void __attribute__((noinline))
+test_loop_speed_invert(void)
+{
+ struct weston_matrix m;
+ struct inverse_matrix inv;
+ unsigned long count = 0;
+ double t;
+
+ printf("\nRunning 3 s test on matrix_invert()...\n");
+
+ weston_matrix_init(&m);
+
+ running = 1;
+ alarm(3);
+ reset_timer();
+ while (running) {
+ matrix_invert(inv.LU, inv.perm, &m);
+ count++;
+ }
+ t = read_timer();
+
+ printf("%lu iterations in %f seconds, avg. %.1f ns/iter.\n",
+ count, t, 1e9 * t / count);
+}
+
+static void __attribute__((noinline))
+test_loop_speed_invert_explicit(void)
+{
+ struct weston_matrix m;
+ unsigned long count = 0;
+ double t;
+
+ printf("\nRunning 3 s test on weston_matrix_invert()...\n");
+
+ weston_matrix_init(&m);
+
+ running = 1;
+ alarm(3);
+ reset_timer();
+ while (running) {
+ weston_matrix_invert(&m, &m);
+ count++;
+ }
+ t = read_timer();
+
+ printf("%lu iterations in %f seconds, avg. %.1f ns/iter.\n",
+ count, t, 1e9 * t / count);
+}
+
+int main(void)
+{
+ struct sigaction ding;
+ struct weston_matrix M;
+ struct inverse_matrix Q;
+ int ret;
+ double errsup;
+ double det;
+
+ ding.sa_handler = stopme;
+ sigemptyset(&ding.sa_mask);
+ ding.sa_flags = 0;
+ sigaction(SIGALRM, &ding, NULL);
+
+ srandom(13);
+
+ M.d[0] = 3.0; M.d[4] = 17.0; M.d[8] = 10.0; M.d[12] = 0.0;
+ M.d[1] = 2.0; M.d[5] = 4.0; M.d[9] = -2.0; M.d[13] = 0.0;
+ M.d[2] = 6.0; M.d[6] = 18.0; M.d[10] = -12; M.d[14] = 0.0;
+ M.d[3] = 0.0; M.d[7] = 0.0; M.d[11] = 0.0; M.d[15] = 1.0;
+
+ ret = matrix_invert(Q.LU, Q.perm, &M);
+ printf("ret = %d\n", ret);
+ printf("det = %g\n\n", determinant(&M));
+
+ if (ret != 0)
+ return 1;
+
+ print_inverse_data_matrix(&Q);
+ printf("P * A = L * U\n");
+ print_permutation_matrix(&Q);
+ print_LU_decomposition(&Q);
+
+
+ printf("a random matrix:\n");
+ randomize_matrix(&M);
+ det = determinant(&M);
+ print_matrix(&M);
+ errsup = test_inverse(&M);
+ printf("\nThe matrix multiplied by its inverse, error:\n");
+ print_matrix(&M);
+ printf("max abs error: %g, original determinant %g\n", errsup, det);
+
+ test_loop_precision();
+ test_loop_speed_matrixvector();
+ test_loop_speed_inversetransform();
+ test_loop_speed_invert();
+ test_loop_speed_invert_explicit();
+
+ return 0;
+}
diff --git a/tests/setbacklight.c b/tests/setbacklight.c
new file mode 100644
index 00000000..92bd4bf3
--- /dev/null
+++ b/tests/setbacklight.c
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ *
+ * Author: Tiago Vignatti
+ */
+/*
+ * \file setbacklight.c
+ * Test program to get a backlight connector and set its brightness value.
+ * Queries for the connectors id can be performed using drm/tests/modeprint
+ * program.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "libbacklight.h"
+
+static uint32_t
+get_drm_connector_type(struct udev_device *drm_device, uint32_t connector_id)
+{
+ const char *filename;
+ int fd, i, connector_type;
+ drmModeResPtr res;
+ drmModeConnectorPtr connector;
+
+ filename = udev_device_get_devnode(drm_device);
+ fd = open(filename, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ printf("couldn't open drm_device\n");
+ return -1;
+ }
+
+ res = drmModeGetResources(fd);
+ if (res == 0) {
+ printf("Failed to get resources from card\n");
+ close(fd);
+ return -1;
+ }
+
+ for (i = 0; i < res->count_connectors; i++) {
+ connector = drmModeGetConnector(fd, res->connectors[i]);
+ if (!connector)
+ continue;
+
+ if ((connector->connection == DRM_MODE_DISCONNECTED) ||
+ (connector->connector_id != connector_id)) {
+ drmModeFreeConnector(connector);
+ continue;
+ }
+
+ connector_type = connector->connector_type;
+ drmModeFreeConnector(connector);
+ drmModeFreeResources(res);
+
+ close(fd);
+ return connector_type;
+ }
+
+ close(fd);
+ drmModeFreeResources(res);
+ return -1;
+}
+
+/* returns a value between 0-255 range, where higher is brighter */
+static uint32_t
+get_normalized_backlight(struct backlight *backlight)
+{
+ long brightness, max_brightness;
+ long norm;
+
+ brightness = backlight_get_brightness(backlight);
+ max_brightness = backlight_get_max_brightness(backlight);
+
+ /* convert it to a scale of 0 to 255 */
+ norm = (brightness * 255)/(max_brightness);
+
+ return (int) norm;
+}
+
+static void
+set_backlight(struct udev_device *drm_device, int connector_id, int blight)
+{
+ int connector_type;
+ long max_brightness, brightness, actual_brightness;
+ struct backlight *backlight;
+ long new_blight;
+
+ connector_type = get_drm_connector_type(drm_device, connector_id);
+ if (connector_type < 0)
+ return;
+
+ backlight = backlight_init(drm_device, connector_type);
+ if (!backlight) {
+ printf("backlight adjust failed\n");
+ return;
+ }
+
+ max_brightness = backlight_get_max_brightness(backlight);
+ printf("Max backlight: %ld\n", max_brightness);
+
+ brightness = backlight_get_brightness(backlight);
+ printf("Cached backlight: %ld\n", brightness);
+
+ actual_brightness = backlight_get_actual_brightness(backlight);
+ printf("Hardware backlight: %ld\n", actual_brightness);
+
+ printf("normalized current brightness: %d\n",
+ get_normalized_backlight(backlight));
+
+ /* denormalized value */
+ new_blight = (blight * max_brightness) / 255;
+
+ backlight_set_brightness(backlight, new_blight);
+ printf("Setting brightness to: %ld (norm: %d)\n", new_blight, blight);
+
+ backlight_destroy(backlight);
+}
+
+int
+main(int argc, char **argv)
+{
+ int blight, connector_id;
+ const char *path;
+ struct udev *udev;
+ struct udev_enumerate *e;
+ struct udev_list_entry *entry;
+ struct udev_device *drm_device;
+
+ if (argc < 3) {
+ printf("Please add connector_id and brightness values from 0-255\n");
+ return 1;
+ }
+
+ connector_id = atoi(argv[1]);
+ blight = atoi(argv[2]);
+
+ udev = udev_new();
+ if (udev == NULL) {
+ printf("failed to initialize udev context\n");
+ return 1;
+ }
+
+ e = udev_enumerate_new(udev);
+ udev_enumerate_add_match_subsystem(e, "drm");
+ udev_enumerate_add_match_sysname(e, "card[0-9]*");
+
+ udev_enumerate_scan_devices(e);
+ drm_device = NULL;
+ udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
+ path = udev_list_entry_get_name(entry);
+ drm_device = udev_device_new_from_syspath(udev, path);
+ break;
+ }
+
+ if (drm_device == NULL) {
+ printf("no drm device found\n");
+ return 1;
+ }
+
+ set_backlight(drm_device, connector_id, blight);
+
+ udev_device_unref(drm_device);
+ return 0;
+}
diff --git a/tests/subsurface-test.c b/tests/subsurface-test.c
new file mode 100644
index 00000000..98e00fea
--- /dev/null
+++ b/tests/subsurface-test.c
@@ -0,0 +1,549 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * 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.
+ */
+
+#include <string.h>
+
+#include "weston-test-client-helper.h"
+#include "subsurface-client-protocol.h"
+#include <stdio.h>
+
+#define NUM_SUBSURFACES 3
+
+struct compound_surface {
+ struct wl_subcompositor *subco;
+ struct wl_surface *parent;
+ struct wl_surface *child[NUM_SUBSURFACES];
+ struct wl_subsurface *sub[NUM_SUBSURFACES];
+};
+
+static struct wl_subcompositor *
+get_subcompositor(struct client *client)
+{
+ struct global *g;
+ struct global *global_sub = NULL;
+ struct wl_subcompositor *sub;
+
+ wl_list_for_each(g, &client->global_list, link) {
+ if (strcmp(g->interface, "wl_subcompositor"))
+ continue;
+
+ if (global_sub)
+ assert(0 && "multiple wl_subcompositor objects");
+
+ global_sub = g;
+ }
+
+ assert(global_sub && "no wl_subcompositor found");
+
+ assert(global_sub->version == 1);
+
+ sub = wl_registry_bind(client->wl_registry, global_sub->name,
+ &wl_subcompositor_interface, 1);
+ assert(sub);
+
+ return sub;
+}
+
+static void
+populate_compound_surface(struct compound_surface *com, struct client *client)
+{
+ int i;
+
+ com->subco = get_subcompositor(client);
+
+ com->parent = wl_compositor_create_surface(client->wl_compositor);
+
+ for (i = 0; i < NUM_SUBSURFACES; i++) {
+ com->child[i] =
+ wl_compositor_create_surface(client->wl_compositor);
+ com->sub[i] =
+ wl_subcompositor_get_subsurface(com->subco,
+ com->child[i],
+ com->parent);
+ }
+}
+
+TEST(test_subsurface_basic_protocol)
+{
+ struct client *client;
+ struct compound_surface com1;
+ struct compound_surface com2;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ populate_compound_surface(&com1, client);
+ populate_compound_surface(&com2, client);
+
+ client_roundtrip(client);
+}
+
+TEST(test_subsurface_position_protocol)
+{
+ struct client *client;
+ struct compound_surface com;
+ int i;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ populate_compound_surface(&com, client);
+ for (i = 0; i < NUM_SUBSURFACES; i++)
+ wl_subsurface_set_position(com.sub[i],
+ (i + 2) * 20, (i + 2) * 10);
+
+ client_roundtrip(client);
+}
+
+TEST(test_subsurface_placement_protocol)
+{
+ struct client *client;
+ struct compound_surface com;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ populate_compound_surface(&com, client);
+
+ wl_subsurface_place_above(com.sub[0], com.child[1]);
+ wl_subsurface_place_above(com.sub[1], com.parent);
+ wl_subsurface_place_below(com.sub[2], com.child[0]);
+ wl_subsurface_place_below(com.sub[1], com.parent);
+
+ client_roundtrip(client);
+}
+
+FAIL_TEST(test_subsurface_paradox)
+{
+ struct client *client;
+ struct wl_surface *parent;
+ struct wl_subcompositor *subco;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ subco = get_subcompositor(client);
+ parent = wl_compositor_create_surface(client->wl_compositor);
+
+ /* surface is its own parent */
+ wl_subcompositor_get_subsurface(subco, parent, parent);
+
+ client_roundtrip(client);
+}
+
+FAIL_TEST(test_subsurface_identical_link)
+{
+ struct client *client;
+ struct compound_surface com;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ populate_compound_surface(&com, client);
+
+ /* surface is already a subsurface */
+ wl_subcompositor_get_subsurface(com.subco, com.child[0], com.parent);
+
+ client_roundtrip(client);
+}
+
+FAIL_TEST(test_subsurface_change_link)
+{
+ struct client *client;
+ struct compound_surface com;
+ struct wl_surface *stranger;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ stranger = wl_compositor_create_surface(client->wl_compositor);
+ populate_compound_surface(&com, client);
+
+ /* surface is already a subsurface */
+ wl_subcompositor_get_subsurface(com.subco, com.child[0], stranger);
+
+ client_roundtrip(client);
+}
+
+TEST(test_subsurface_nesting)
+{
+ struct client *client;
+ struct compound_surface com;
+ struct wl_surface *stranger;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ stranger = wl_compositor_create_surface(client->wl_compositor);
+ populate_compound_surface(&com, client);
+
+ /* parent is a sub-surface */
+ wl_subcompositor_get_subsurface(com.subco, stranger, com.child[0]);
+
+ client_roundtrip(client);
+}
+
+TEST(test_subsurface_nesting_parent)
+{
+ struct client *client;
+ struct compound_surface com;
+ struct wl_surface *stranger;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ stranger = wl_compositor_create_surface(client->wl_compositor);
+ populate_compound_surface(&com, client);
+
+ /* surface is already a parent */
+ wl_subcompositor_get_subsurface(com.subco, com.parent, stranger);
+
+ client_roundtrip(client);
+}
+
+FAIL_TEST(test_subsurface_loop_paradox)
+{
+ struct client *client;
+ struct wl_surface *surface[3];
+ struct wl_subcompositor *subco;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ subco = get_subcompositor(client);
+ surface[0] = wl_compositor_create_surface(client->wl_compositor);
+ surface[1] = wl_compositor_create_surface(client->wl_compositor);
+ surface[2] = wl_compositor_create_surface(client->wl_compositor);
+
+ /* create a nesting loop */
+ wl_subcompositor_get_subsurface(subco, surface[1], surface[0]);
+ wl_subcompositor_get_subsurface(subco, surface[2], surface[1]);
+ wl_subcompositor_get_subsurface(subco, surface[0], surface[2]);
+
+ client_roundtrip(client);
+}
+
+FAIL_TEST(test_subsurface_place_above_stranger)
+{
+ struct client *client;
+ struct compound_surface com;
+ struct wl_surface *stranger;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ stranger = wl_compositor_create_surface(client->wl_compositor);
+ populate_compound_surface(&com, client);
+
+ /* bad sibling */
+ wl_subsurface_place_above(com.sub[0], stranger);
+
+ client_roundtrip(client);
+}
+
+FAIL_TEST(test_subsurface_place_below_stranger)
+{
+ struct client *client;
+ struct compound_surface com;
+ struct wl_surface *stranger;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ stranger = wl_compositor_create_surface(client->wl_compositor);
+ populate_compound_surface(&com, client);
+
+ /* bad sibling */
+ wl_subsurface_place_below(com.sub[0], stranger);
+
+ client_roundtrip(client);
+}
+
+FAIL_TEST(test_subsurface_place_above_foreign)
+{
+ struct client *client;
+ struct compound_surface com1;
+ struct compound_surface com2;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ populate_compound_surface(&com1, client);
+ populate_compound_surface(&com2, client);
+
+ /* bad sibling */
+ wl_subsurface_place_above(com1.sub[0], com2.child[0]);
+
+ client_roundtrip(client);
+}
+
+FAIL_TEST(test_subsurface_place_below_foreign)
+{
+ struct client *client;
+ struct compound_surface com1;
+ struct compound_surface com2;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ populate_compound_surface(&com1, client);
+ populate_compound_surface(&com2, client);
+
+ /* bad sibling */
+ wl_subsurface_place_below(com1.sub[0], com2.child[0]);
+
+ client_roundtrip(client);
+}
+
+TEST(test_subsurface_destroy_protocol)
+{
+ struct client *client;
+ struct compound_surface com;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ populate_compound_surface(&com, client);
+
+ /* not needed anymore */
+ wl_subcompositor_destroy(com.subco);
+
+ /* detach child from parent */
+ wl_subsurface_destroy(com.sub[0]);
+
+ /* destroy: child, parent */
+ wl_surface_destroy(com.child[1]);
+ wl_surface_destroy(com.parent);
+
+ /* destroy: parent, child */
+ wl_surface_destroy(com.child[2]);
+
+ /* destroy: sub, child */
+ wl_surface_destroy(com.child[0]);
+
+ /* 2x destroy: child, sub */
+ wl_subsurface_destroy(com.sub[2]);
+ wl_subsurface_destroy(com.sub[1]);
+
+ client_roundtrip(client);
+}
+
+static void
+create_subsurface_tree(struct client *client, struct wl_surface **surfs,
+ struct wl_subsurface **subs, int n)
+{
+ struct wl_subcompositor *subco;
+ int i;
+
+ subco = get_subcompositor(client);
+
+ for (i = 0; i < n; i++)
+ surfs[i] = wl_compositor_create_surface(client->wl_compositor);
+
+ /*
+ * The tree of sub-surfaces:
+ * 0
+ * / \
+ * 1 2 - 10
+ * / \ |\
+ * 3 5 9 6
+ * / / \
+ * 4 7 8
+ * Surface 0 has no wl_subsurface, others do.
+ */
+
+ switch (n) {
+ default:
+ assert(0);
+ break;
+
+#define SUB_LINK(s,p) \
+ subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p])
+
+ case 11:
+ SUB_LINK(10, 2);
+ case 10:
+ SUB_LINK(9, 2);
+ case 9:
+ SUB_LINK(8, 6);
+ case 8:
+ SUB_LINK(7, 6);
+ case 7:
+ SUB_LINK(6, 2);
+ case 6:
+ SUB_LINK(5, 1);
+ case 5:
+ SUB_LINK(4, 3);
+ case 4:
+ SUB_LINK(3, 1);
+ case 3:
+ SUB_LINK(2, 0);
+ case 2:
+ SUB_LINK(1, 0);
+
+#undef SUB_LINK
+ };
+}
+
+static void
+destroy_subsurface_tree(struct wl_surface **surfs,
+ struct wl_subsurface **subs, int n)
+{
+ int i;
+
+ for (i = n; i-- > 0; ) {
+ if (surfs[i])
+ wl_surface_destroy(surfs[i]);
+
+ if (subs[i])
+ wl_subsurface_destroy(subs[i]);
+ }
+}
+
+static int
+has_dupe(int *cnt, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ if (cnt[i] == cnt[n])
+ return 1;
+
+ return 0;
+}
+
+/* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)!
+ */
+#define NSTEPS 3
+
+struct permu_state {
+ int set_size;
+ int cnt[NSTEPS];
+};
+
+static void
+permu_init(struct permu_state *s, int set_size)
+{
+ int i;
+
+ s->set_size = set_size;
+ for (i = 0; i < NSTEPS; i++)
+ s->cnt[i] = 0;
+}
+
+static int
+permu_next(struct permu_state *s)
+{
+ int k;
+
+ s->cnt[NSTEPS - 1]++;
+
+ while (1) {
+ if (s->cnt[0] >= s->set_size) {
+ return -1;
+ }
+
+ for (k = 1; k < NSTEPS; k++) {
+ if (s->cnt[k] >= s->set_size) {
+ s->cnt[k - 1]++;
+ s->cnt[k] = 0;
+ break;
+ }
+
+ if (has_dupe(s->cnt, k)) {
+ s->cnt[k]++;
+ break;
+ }
+ }
+
+ if (k == NSTEPS)
+ return 0;
+ }
+}
+
+static void
+destroy_permu_object(struct wl_surface **surfs,
+ struct wl_subsurface **subs, int i)
+{
+ int h = (i + 1) / 2;
+
+ if (i & 1) {
+ fprintf(stderr, " [sub %2d]", h);
+ wl_subsurface_destroy(subs[h]);
+ subs[h] = NULL;
+ } else {
+ fprintf(stderr, " [surf %2d]", h);
+ wl_surface_destroy(surfs[h]);
+ surfs[h] = NULL;
+ }
+}
+
+TEST(test_subsurface_destroy_permutations)
+{
+ /*
+ * Test wl_surface and wl_subsurface destruction orders in a
+ * complex tree of sub-surfaces.
+ *
+ * In the tree of sub-surfaces, go through every possible
+ * permutation of destroying all wl_surface and wl_subsurface
+ * objects. Execpt, to limit running time to a reasonable level,
+ * execute only the first NSTEPS destructions from each
+ * permutation, and ignore identical cases.
+ */
+
+ const int test_size = 11;
+ struct client *client;
+ struct wl_surface *surfs[test_size];
+ struct wl_subsurface *subs[test_size];
+ struct permu_state per;
+ int counter = 0;
+ int i;
+
+ client = client_create(100, 50, 123, 77);
+ assert(client);
+
+ permu_init(&per, test_size * 2 - 1);
+ while (permu_next(&per) != -1) {
+ /* for each permutation of NSTEPS out of test_size */
+ memset(surfs, 0, sizeof surfs);
+ memset(subs, 0, sizeof subs);
+
+ create_subsurface_tree(client, surfs, subs, test_size);
+
+ fprintf(stderr, "permu");
+
+ for (i = 0; i < NSTEPS; i++)
+ fprintf(stderr, " %2d", per.cnt[i]);
+
+ for (i = 0; i < NSTEPS; i++)
+ destroy_permu_object(surfs, subs, per.cnt[i]);
+
+ fprintf(stderr, "\n");
+ client_roundtrip(client);
+
+ destroy_subsurface_tree(surfs, subs, test_size);
+ counter++;
+ }
+
+ client_roundtrip(client);
+ fprintf(stderr, "tried %d destroy permutations\n", counter);
+}
diff --git a/tests/surface-global-test.c b/tests/surface-global-test.c
new file mode 100644
index 00000000..04b64d6a
--- /dev/null
+++ b/tests/surface-global-test.c
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#include <assert.h>
+
+#include "../src/compositor.h"
+
+static void
+surface_to_from_global(void *data)
+{
+ struct weston_compositor *compositor = data;
+ struct weston_surface *surface;
+ float x, y;
+ wl_fixed_t fx, fy;
+ int32_t ix, iy;
+
+ surface = weston_surface_create(compositor);
+ assert(surface);
+ weston_surface_configure(surface, 5, 10, 50, 50);
+ weston_surface_update_transform(surface);
+
+ weston_surface_to_global_float(surface, 33, 22, &x, &y);
+ assert(x == 38 && y == 32);
+
+ weston_surface_to_global_float(surface, -8, -2, &x, &y);
+ assert(x == -3 && y == 8);
+
+ weston_surface_to_global_fixed(surface, wl_fixed_from_int(12),
+ wl_fixed_from_int(5), &fx, &fy);
+ assert(fx == wl_fixed_from_int(17) && fy == wl_fixed_from_int(15));
+
+ weston_surface_from_global_float(surface, 38, 32, &x, &y);
+ assert(x == 33 && y == 22);
+
+ weston_surface_from_global_float(surface, 42, 5, &x, &y);
+ assert(x == 37 && y == -5);
+
+ weston_surface_from_global_fixed(surface, wl_fixed_from_int(21),
+ wl_fixed_from_int(100), &fx, &fy);
+ assert(fx == wl_fixed_from_int(16) && fy == wl_fixed_from_int(90));
+
+ weston_surface_from_global(surface, 0, 0, &ix, &iy);
+ assert(ix == -5 && iy == -10);
+
+ weston_surface_from_global(surface, 5, 10, &ix, &iy);
+ assert(ix == 0 && iy == 0);
+
+ wl_display_terminate(compositor->wl_display);
+}
+
+WL_EXPORT int
+module_init(struct weston_compositor *compositor, int *argc, char *argv[])
+{
+ struct wl_event_loop *loop;
+
+ loop = wl_display_get_event_loop(compositor->wl_display);
+
+ wl_event_loop_add_idle(loop, surface_to_from_global, compositor);
+
+ return 0;
+}
diff --git a/tests/surface-test.c b/tests/surface-test.c
new file mode 100644
index 00000000..e8af2ed7
--- /dev/null
+++ b/tests/surface-test.c
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "../src/compositor.h"
+
+static void
+surface_transform(void *data)
+{
+ struct weston_compositor *compositor = data;
+ struct weston_surface *surface;
+ float x, y;
+
+ surface = weston_surface_create(compositor);
+ assert(surface);
+ weston_surface_configure(surface, 100, 100, 200, 200);
+ weston_surface_update_transform(surface);
+ weston_surface_to_global_float(surface, 20, 20, &x, &y);
+
+ fprintf(stderr, "20,20 maps to %f, %f\n", x, y);
+ assert(x == 120 && y == 120);
+
+ weston_surface_set_position(surface, 150, 300);
+ weston_surface_update_transform(surface);
+ weston_surface_to_global_float(surface, 50, 40, &x, &y);
+ assert(x == 200 && y == 340);
+
+ wl_display_terminate(compositor->wl_display);
+}
+
+WL_EXPORT int
+module_init(struct weston_compositor *compositor, int *argc, char *argv[])
+{
+ struct wl_event_loop *loop;
+
+ loop = wl_display_get_event_loop(compositor->wl_display);
+
+ wl_event_loop_add_idle(loop, surface_transform, compositor);
+
+ return 0;
+}
diff --git a/tests/text-test.c b/tests/text-test.c
new file mode 100644
index 00000000..48f2b5a6
--- /dev/null
+++ b/tests/text-test.c
@@ -0,0 +1,214 @@
+/*
+ * 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.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <linux/input.h>
+#include "weston-test-client-helper.h"
+#include "../clients/text-client-protocol.h"
+
+struct text_input_state {
+ int activated;
+ int deactivated;
+};
+
+static void
+text_input_commit_string(void *data,
+ struct wl_text_input *text_input,
+ uint32_t serial,
+ const char *text)
+{
+}
+
+static void
+text_input_preedit_string(void *data,
+ struct wl_text_input *text_input,
+ uint32_t serial,
+ const char *text,
+ const char *commit)
+{
+}
+
+static void
+text_input_delete_surrounding_text(void *data,
+ struct wl_text_input *text_input,
+ int32_t index,
+ uint32_t length)
+{
+}
+
+static void
+text_input_cursor_position(void *data,
+ struct wl_text_input *text_input,
+ int32_t index,
+ int32_t anchor)
+{
+}
+
+static void
+text_input_preedit_styling(void *data,
+ struct wl_text_input *text_input,
+ uint32_t index,
+ uint32_t length,
+ uint32_t style)
+{
+}
+
+static void
+text_input_preedit_cursor(void *data,
+ struct wl_text_input *text_input,
+ int32_t index)
+{
+}
+
+static void
+text_input_modifiers_map(void *data,
+ struct wl_text_input *text_input,
+ struct wl_array *map)
+{
+}
+
+static void
+text_input_keysym(void *data,
+ struct wl_text_input *text_input,
+ uint32_t serial,
+ uint32_t time,
+ uint32_t sym,
+ uint32_t state,
+ uint32_t modifiers)
+{
+}
+
+static void
+text_input_enter(void *data,
+ struct wl_text_input *text_input,
+ struct wl_surface *surface)
+
+{
+ struct text_input_state *state = data;
+
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ state->activated += 1;
+}
+
+static void
+text_input_leave(void *data,
+ struct wl_text_input *text_input)
+{
+ struct text_input_state *state = data;
+
+ state->deactivated += 1;
+}
+
+static void
+text_input_input_panel_state(void *data,
+ struct wl_text_input *text_input,
+ uint32_t state)
+{
+}
+
+static void
+text_input_language(void *data,
+ struct wl_text_input *text_input,
+ uint32_t serial,
+ const char *language)
+{
+}
+
+static void
+text_input_text_direction(void *data,
+ struct wl_text_input *text_input,
+ uint32_t serial,
+ uint32_t direction)
+{
+}
+
+static const struct wl_text_input_listener text_input_listener = {
+ text_input_enter,
+ text_input_leave,
+ text_input_modifiers_map,
+ text_input_input_panel_state,
+ text_input_preedit_string,
+ text_input_preedit_styling,
+ text_input_preedit_cursor,
+ text_input_commit_string,
+ text_input_cursor_position,
+ text_input_delete_surrounding_text,
+ text_input_keysym,
+ text_input_language,
+ text_input_text_direction
+};
+
+TEST(text_test)
+{
+ struct client *client;
+ struct global *global;
+ struct wl_text_input_manager *factory;
+ struct wl_text_input *text_input;
+ struct text_input_state state;
+
+ client = client_create(100, 100, 100, 100);
+ assert(client);
+
+ factory = NULL;
+ wl_list_for_each(global, &client->global_list, link) {
+ if (strcmp(global->interface, "wl_text_input_manager") == 0)
+ factory = wl_registry_bind(client->wl_registry,
+ global->name,
+ &wl_text_input_manager_interface, 1);
+ }
+
+ assert(factory);
+
+ memset(&state, 0, sizeof state);
+ text_input = wl_text_input_manager_create_text_input(factory);
+ wl_text_input_add_listener(text_input, &text_input_listener, &state);
+
+ /* Make sure our test surface has keyboard focus. */
+ wl_test_activate_surface(client->test->wl_test,
+ client->surface->wl_surface);
+ client_roundtrip(client);
+ assert(client->input->keyboard->focus == client->surface);
+
+ /* Activate test model and make sure we get enter event. */
+ wl_text_input_activate(text_input, client->input->wl_seat,
+ client->surface->wl_surface);
+ client_roundtrip(client);
+ assert(state.activated == 1 && state.deactivated == 0);
+
+ /* Deactivate test model and make sure we get leave event. */
+ wl_text_input_deactivate(text_input, client->input->wl_seat);
+ client_roundtrip(client);
+ assert(state.activated == 1 && state.deactivated == 1);
+
+ /* Activate test model again. */
+ wl_text_input_activate(text_input, client->input->wl_seat,
+ client->surface->wl_surface);
+ client_roundtrip(client);
+ assert(state.activated == 2 && state.deactivated == 1);
+
+ /* Take keyboard focus away and verify we get leave event. */
+ wl_test_activate_surface(client->test->wl_test, NULL);
+ client_roundtrip(client);
+ assert(state.activated == 2 && state.deactivated == 2);
+}
diff --git a/tests/vertex-clip-test.c b/tests/vertex-clip-test.c
new file mode 100644
index 00000000..5b2e08c5
--- /dev/null
+++ b/tests/vertex-clip-test.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright © 2013 Sam Spilsbury <smspillaz@gmail.com>
+ *
+ * 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.
+ */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "weston-test-runner.h"
+
+#include "../src/vertex-clipping.h"
+
+#define BOUNDING_BOX_TOP_Y 100.0f
+#define BOUNDING_BOX_LEFT_X 50.0f
+#define BOUNDING_BOX_RIGHT_X 100.0f
+#define BOUNDING_BOX_BOTTOM_Y 50.0f
+
+#define INSIDE_X1 (BOUNDING_BOX_LEFT_X + 1.0f)
+#define INSIDE_X2 (BOUNDING_BOX_RIGHT_X - 1.0f)
+#define INSIDE_Y1 (BOUNDING_BOX_BOTTOM_Y + 1.0f)
+#define INSIDE_Y2 (BOUNDING_BOX_TOP_Y - 1.0f)
+
+#define OUTSIDE_X1 (BOUNDING_BOX_LEFT_X - 1.0f)
+#define OUTSIDE_X2 (BOUNDING_BOX_RIGHT_X + 1.0f)
+#define OUTSIDE_Y1 (BOUNDING_BOX_BOTTOM_Y - 1.0f)
+#define OUTSIDE_Y2 (BOUNDING_BOX_TOP_Y + 1.0f)
+
+static void
+populate_clip_context (struct clip_context *ctx)
+{
+ ctx->clip.x1 = BOUNDING_BOX_LEFT_X;
+ ctx->clip.y1 = BOUNDING_BOX_BOTTOM_Y;
+ ctx->clip.x2 = BOUNDING_BOX_RIGHT_X;
+ ctx->clip.y2 = BOUNDING_BOX_TOP_Y;
+}
+
+static int
+clip_polygon (struct clip_context *ctx,
+ struct polygon8 *polygon,
+ GLfloat *vertices_x,
+ GLfloat *vertices_y)
+{
+ populate_clip_context(ctx);
+ return clip_transformed(ctx, polygon, vertices_x, vertices_y);
+}
+
+struct vertex_clip_test_data
+{
+ struct polygon8 surface;
+ struct polygon8 expected;
+};
+
+const struct vertex_clip_test_data test_data[] =
+{
+ /* All inside */
+ {
+ {
+ { INSIDE_X1, INSIDE_X2, INSIDE_X2, INSIDE_X1 },
+ { INSIDE_Y1, INSIDE_Y1, INSIDE_Y2, INSIDE_Y2 },
+ 4
+ },
+ {
+ { INSIDE_X1, INSIDE_X2, INSIDE_X2, INSIDE_X1 },
+ { INSIDE_Y1, INSIDE_Y1, INSIDE_Y2, INSIDE_Y2 },
+ 4
+ }
+ },
+ /* Top outside */
+ {
+ {
+ { INSIDE_X1, INSIDE_X2, INSIDE_X2, INSIDE_X1 },
+ { INSIDE_Y1, INSIDE_Y1, OUTSIDE_Y2, OUTSIDE_Y2 },
+ 4
+ },
+ {
+ { INSIDE_X1, INSIDE_X1, INSIDE_X2, INSIDE_X2 },
+ { BOUNDING_BOX_TOP_Y, INSIDE_Y1, INSIDE_Y1, BOUNDING_BOX_TOP_Y },
+ 4
+ }
+ },
+ /* Bottom outside */
+ {
+ {
+ { INSIDE_X1, INSIDE_X2, INSIDE_X2, INSIDE_X1 },
+ { OUTSIDE_Y1, OUTSIDE_Y1, INSIDE_Y2, INSIDE_Y2 },
+ 4
+ },
+ {
+ { INSIDE_X1, INSIDE_X2, INSIDE_X2, INSIDE_X1 },
+ { BOUNDING_BOX_BOTTOM_Y, BOUNDING_BOX_BOTTOM_Y, INSIDE_Y2, INSIDE_Y2 },
+ 4
+ }
+ },
+ /* Left outside */
+ {
+ {
+ { OUTSIDE_X1, INSIDE_X2, INSIDE_X2, OUTSIDE_X1 },
+ { INSIDE_Y1, INSIDE_Y1, INSIDE_Y2, INSIDE_Y2 },
+ 4
+ },
+ {
+ { BOUNDING_BOX_LEFT_X, INSIDE_X2, INSIDE_X2, BOUNDING_BOX_LEFT_X },
+ { INSIDE_Y1, INSIDE_Y1, INSIDE_Y2, INSIDE_Y2 },
+ 4
+ }
+ },
+ /* Right outside */
+ {
+ {
+ { INSIDE_X1, OUTSIDE_X2, OUTSIDE_X2, INSIDE_X1 },
+ { INSIDE_Y1, INSIDE_Y1, INSIDE_Y2, INSIDE_Y2 },
+ 4
+ },
+ {
+ { INSIDE_X1, BOUNDING_BOX_RIGHT_X, BOUNDING_BOX_RIGHT_X, INSIDE_X1 },
+ { INSIDE_Y1, INSIDE_Y1, INSIDE_Y2, INSIDE_Y2 },
+ 4
+ }
+ },
+ /* Diamond extending from bounding box edges, clip to bounding box */
+ {
+ {
+ { BOUNDING_BOX_LEFT_X - 25, BOUNDING_BOX_LEFT_X + 25, BOUNDING_BOX_RIGHT_X + 25, BOUNDING_BOX_RIGHT_X - 25 },
+ { BOUNDING_BOX_BOTTOM_Y + 25, BOUNDING_BOX_TOP_Y + 25, BOUNDING_BOX_TOP_Y - 25, BOUNDING_BOX_BOTTOM_Y - 25 },
+ 4
+ },
+ {
+ { BOUNDING_BOX_LEFT_X, BOUNDING_BOX_LEFT_X, BOUNDING_BOX_RIGHT_X, BOUNDING_BOX_RIGHT_X },
+ { BOUNDING_BOX_BOTTOM_Y, BOUNDING_BOX_TOP_Y, BOUNDING_BOX_TOP_Y, BOUNDING_BOX_BOTTOM_Y },
+ 4
+ }
+ },
+ /* Diamond inside of bounding box edges, clip t bounding box, 8 resulting vertices */
+ {
+ {
+ { BOUNDING_BOX_LEFT_X - 12.5, BOUNDING_BOX_LEFT_X + 25, BOUNDING_BOX_RIGHT_X + 12.5, BOUNDING_BOX_RIGHT_X - 25 },
+ { BOUNDING_BOX_BOTTOM_Y + 25, BOUNDING_BOX_TOP_Y + 12.5, BOUNDING_BOX_TOP_Y - 25, BOUNDING_BOX_BOTTOM_Y - 12.5 },
+ 4
+ },
+ {
+ { BOUNDING_BOX_LEFT_X + 12.5, BOUNDING_BOX_LEFT_X, BOUNDING_BOX_LEFT_X, BOUNDING_BOX_LEFT_X + 12.5,
+ BOUNDING_BOX_RIGHT_X - 12.5, BOUNDING_BOX_RIGHT_X, BOUNDING_BOX_RIGHT_X, BOUNDING_BOX_RIGHT_X - 12.5 },
+ { BOUNDING_BOX_BOTTOM_Y, BOUNDING_BOX_BOTTOM_Y + 12.5, BOUNDING_BOX_TOP_Y - 12.5, BOUNDING_BOX_TOP_Y,
+ BOUNDING_BOX_TOP_Y, BOUNDING_BOX_TOP_Y - 12.5, BOUNDING_BOX_BOTTOM_Y + 12.5, BOUNDING_BOX_BOTTOM_Y },
+ 8
+ }
+ }
+};
+
+/* clip_polygon modifies the source operand and the test data must
+ * be const, so we need to deep copy it */
+static void
+deep_copy_polygon8(const struct polygon8 *src, struct polygon8 *dst)
+{
+ dst->n = src->n;
+ memcpy((void *) dst->x, src->x, sizeof (src->x));
+ memcpy((void *) dst->y, src->y, sizeof (src->y));
+}
+
+TEST_P(clip_polygon_n_vertices_emitted, test_data)
+{
+ struct vertex_clip_test_data *tdata = data;
+ struct clip_context ctx;
+ struct polygon8 polygon;
+ GLfloat vertices_x[8];
+ GLfloat vertices_y[8];
+ deep_copy_polygon8(&tdata->surface, &polygon);
+ int emitted = clip_polygon(&ctx, &polygon, vertices_x, vertices_y);
+
+ assert(emitted == tdata->expected.n);
+}
+
+TEST_P(clip_polygon_expected_vertices, test_data)
+{
+ struct vertex_clip_test_data *tdata = data;
+ struct clip_context ctx;
+ struct polygon8 polygon;
+ GLfloat vertices_x[8];
+ GLfloat vertices_y[8];
+ deep_copy_polygon8(&tdata->surface, &polygon);
+ int emitted = clip_polygon(&ctx, &polygon, vertices_x, vertices_y);
+ int i = 0;
+
+ for (; i < emitted; ++i)
+ {
+ assert(vertices_x[i] == tdata->expected.x[i]);
+ assert(vertices_y[i] == tdata->expected.y[i]);
+ }
+}
+
+TEST(float_difference_different)
+{
+ assert(float_difference(1.0f, 0.0f) == 1.0f);
+}
+
+TEST(float_difference_same)
+{
+ assert(float_difference(1.0f, 1.0f) == 0.0f);
+}
+
diff --git a/tests/weston-test-client-helper.c b/tests/weston-test-client-helper.c
new file mode 100644
index 00000000..b19be400
--- /dev/null
+++ b/tests/weston-test-client-helper.c
@@ -0,0 +1,539 @@
+/*
+ * 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.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "../shared/os-compatibility.h"
+#include "weston-test-client-helper.h"
+
+static inline void *
+xzalloc(size_t size)
+{
+ void *p;
+
+ p = calloc(1, size);
+ assert(p);
+
+ return p;
+}
+
+int
+surface_contains(struct surface *surface, int x, int y)
+{
+ /* test whether a global x,y point is contained in the surface */
+ int sx = surface->x;
+ int sy = surface->y;
+ int sw = surface->width;
+ int sh = surface->height;
+ return x >= sx && y >= sy && x < sx + sw && y < sy + sh;
+}
+
+static void
+frame_callback_handler(void *data, struct wl_callback *callback, uint32_t time)
+{
+ int *done = data;
+
+ *done = 1;
+
+ wl_callback_destroy(callback);
+}
+
+static const struct wl_callback_listener frame_listener = {
+ frame_callback_handler
+};
+
+struct wl_callback *
+frame_callback_set(struct wl_surface *surface, int *done)
+{
+ struct wl_callback *callback;
+
+ *done = 0;
+ callback = wl_surface_frame(surface);
+ wl_callback_add_listener(callback, &frame_listener, done);
+
+ return callback;
+}
+
+void
+frame_callback_wait(struct client *client, int *done)
+{
+ while (!*done) {
+ assert(wl_display_dispatch(client->wl_display) >= 0);
+ }
+}
+
+void
+move_client(struct client *client, int x, int y)
+{
+ struct surface *surface = client->surface;
+ int done;
+
+ client->surface->x = x;
+ client->surface->y = y;
+ wl_test_move_surface(client->test->wl_test, surface->wl_surface,
+ surface->x, surface->y);
+ /* The attach here is necessary because commit() will call congfigure
+ * only on surfaces newly attached, and the one that sets the surface
+ * position is the configure. */
+ wl_surface_attach(surface->wl_surface, surface->wl_buffer, 0, 0);
+ wl_surface_damage(surface->wl_surface, 0, 0, surface->width,
+ surface->height);
+
+ frame_callback_set(surface->wl_surface, &done);
+
+ wl_surface_commit(surface->wl_surface);
+
+ frame_callback_wait(client, &done);
+}
+
+static void
+pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
+ uint32_t serial, struct wl_surface *wl_surface,
+ wl_fixed_t x, wl_fixed_t y)
+{
+ struct pointer *pointer = data;
+
+ pointer->focus = wl_surface_get_user_data(wl_surface);
+ pointer->x = wl_fixed_to_int(x);
+ pointer->y = wl_fixed_to_int(y);
+
+ fprintf(stderr, "test-client: got pointer enter %d %d, surface %p\n",
+ pointer->x, pointer->y, pointer->focus);
+}
+
+static void
+pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
+ uint32_t serial, struct wl_surface *wl_surface)
+{
+ struct pointer *pointer = data;
+
+ pointer->focus = NULL;
+
+ fprintf(stderr, "test-client: got pointer leave, surface %p\n",
+ wl_surface_get_user_data(wl_surface));
+}
+
+static void
+pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, wl_fixed_t x, wl_fixed_t y)
+{
+ struct pointer *pointer = data;
+
+ pointer->x = wl_fixed_to_int(x);
+ pointer->y = wl_fixed_to_int(y);
+
+ fprintf(stderr, "test-client: got pointer motion %d %d\n",
+ pointer->x, pointer->y);
+}
+
+static void
+pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
+ uint32_t serial, uint32_t time, uint32_t button,
+ uint32_t state)
+{
+ struct pointer *pointer = data;
+
+ pointer->button = button;
+ pointer->state = state;
+
+ fprintf(stderr, "test-client: got pointer button %u %u\n",
+ button, state);
+}
+
+static void
+pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+ fprintf(stderr, "test-client: got pointer axis %u %f\n",
+ axis, wl_fixed_to_double(value));
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+ pointer_handle_enter,
+ pointer_handle_leave,
+ pointer_handle_motion,
+ pointer_handle_button,
+ pointer_handle_axis,
+};
+
+static void
+keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
+ uint32_t format, int fd, uint32_t size)
+{
+ close(fd);
+
+ fprintf(stderr, "test-client: got keyboard keymap\n");
+}
+
+static void
+keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
+ uint32_t serial, struct wl_surface *wl_surface,
+ struct wl_array *keys)
+{
+ struct keyboard *keyboard = data;
+
+ keyboard->focus = wl_surface_get_user_data(wl_surface);
+
+ fprintf(stderr, "test-client: got keyboard enter, surface %p\n",
+ keyboard->focus);
+}
+
+static void
+keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
+ uint32_t serial, struct wl_surface *wl_surface)
+{
+ struct keyboard *keyboard = data;
+
+ keyboard->focus = NULL;
+
+ fprintf(stderr, "test-client: got keyboard leave, surface %p\n",
+ wl_surface_get_user_data(wl_surface));
+}
+
+static void
+keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
+ uint32_t serial, uint32_t time, uint32_t key,
+ uint32_t state)
+{
+ struct keyboard *keyboard = data;
+
+ keyboard->key = key;
+ keyboard->state = state;
+
+ fprintf(stderr, "test-client: got keyboard key %u %u\n", key, state);
+}
+
+static void
+keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
+ uint32_t serial, uint32_t mods_depressed,
+ uint32_t mods_latched, uint32_t mods_locked,
+ uint32_t group)
+{
+ struct keyboard *keyboard = data;
+
+ keyboard->mods_depressed = mods_depressed;
+ keyboard->mods_latched = mods_latched;
+ keyboard->mods_locked = mods_locked;
+ keyboard->group = group;
+
+ fprintf(stderr, "test-client: got keyboard modifiers %u %u %u %u\n",
+ mods_depressed, mods_latched, mods_locked, group);
+}
+
+static const struct wl_keyboard_listener keyboard_listener = {
+ keyboard_handle_keymap,
+ keyboard_handle_enter,
+ keyboard_handle_leave,
+ keyboard_handle_key,
+ keyboard_handle_modifiers,
+};
+
+static void
+surface_enter(void *data,
+ struct wl_surface *wl_surface, struct wl_output *output)
+{
+ struct surface *surface = data;
+
+ surface->output = wl_output_get_user_data(output);
+
+ fprintf(stderr, "test-client: got surface enter output %p\n",
+ surface->output);
+}
+
+static void
+surface_leave(void *data,
+ struct wl_surface *wl_surface, struct wl_output *output)
+{
+ struct surface *surface = data;
+
+ surface->output = NULL;
+
+ fprintf(stderr, "test-client: got surface leave output %p\n",
+ wl_output_get_user_data(output));
+}
+
+static const struct wl_surface_listener surface_listener = {
+ surface_enter,
+ surface_leave
+};
+
+struct wl_buffer *
+create_shm_buffer(struct client *client, int width, int height, void **pixels)
+{
+ struct wl_shm *shm = client->wl_shm;
+ int stride = width * 4;
+ int size = stride * height;
+ struct wl_shm_pool *pool;
+ struct wl_buffer *buffer;
+ int fd;
+ void *data;
+
+ fd = os_create_anonymous_file(size);
+ assert(fd >= 0);
+
+ data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (data == MAP_FAILED) {
+ close(fd);
+ assert(data != MAP_FAILED);
+ }
+
+ pool = wl_shm_create_pool(shm, fd, size);
+ buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
+ WL_SHM_FORMAT_ARGB8888);
+ wl_shm_pool_destroy(pool);
+
+ close(fd);
+
+ if (pixels)
+ *pixels = data;
+
+ return buffer;
+}
+
+static void
+shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
+{
+ struct client *client = data;
+
+ if (format == WL_SHM_FORMAT_ARGB8888)
+ client->has_argb = 1;
+}
+
+struct wl_shm_listener shm_listener = {
+ shm_format
+};
+
+static void
+test_handle_pointer_position(void *data, struct wl_test *wl_test,
+ wl_fixed_t x, wl_fixed_t y)
+{
+ struct test *test = data;
+ test->pointer_x = wl_fixed_to_int(x);
+ test->pointer_y = wl_fixed_to_int(y);
+
+ fprintf(stderr, "test-client: got global pointer %d %d\n",
+ test->pointer_x, test->pointer_y);
+}
+
+static const struct wl_test_listener test_listener = {
+ test_handle_pointer_position
+};
+
+static void
+seat_handle_capabilities(void *data, struct wl_seat *seat,
+ enum wl_seat_capability caps)
+{
+ struct input *input = data;
+ struct pointer *pointer;
+ struct keyboard *keyboard;
+
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
+ pointer = xzalloc(sizeof *pointer);
+ pointer->wl_pointer = wl_seat_get_pointer(seat);
+ wl_pointer_set_user_data(pointer->wl_pointer, pointer);
+ wl_pointer_add_listener(pointer->wl_pointer, &pointer_listener,
+ pointer);
+ input->pointer = pointer;
+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
+ wl_pointer_destroy(input->pointer->wl_pointer);
+ free(input->pointer);
+ input->pointer = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
+ keyboard = xzalloc(sizeof *keyboard);
+ keyboard->wl_keyboard = wl_seat_get_keyboard(seat);
+ wl_keyboard_set_user_data(keyboard->wl_keyboard, keyboard);
+ wl_keyboard_add_listener(keyboard->wl_keyboard, &keyboard_listener,
+ keyboard);
+ input->keyboard = keyboard;
+ } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
+ wl_keyboard_destroy(input->keyboard->wl_keyboard);
+ free(input->keyboard);
+ input->keyboard = NULL;
+ }
+}
+
+static const struct wl_seat_listener seat_listener = {
+ seat_handle_capabilities,
+};
+
+static void
+output_handle_geometry(void *data,
+ struct wl_output *wl_output,
+ int x, int y,
+ int physical_width,
+ int physical_height,
+ int subpixel,
+ const char *make,
+ const char *model,
+ int32_t transform)
+{
+ struct output *output = data;
+
+ output->x = x;
+ output->y = y;
+}
+
+static void
+output_handle_mode(void *data,
+ struct wl_output *wl_output,
+ uint32_t flags,
+ int width,
+ int height,
+ int refresh)
+{
+ struct output *output = data;
+
+ if (flags & WL_OUTPUT_MODE_CURRENT) {
+ output->width = width;
+ output->height = height;
+ }
+}
+
+static const struct wl_output_listener output_listener = {
+ output_handle_geometry,
+ output_handle_mode
+};
+
+static void
+handle_global(void *data, struct wl_registry *registry,
+ uint32_t id, const char *interface, uint32_t version)
+{
+ struct client *client = data;
+ struct input *input;
+ struct output *output;
+ struct test *test;
+ struct global *global;
+
+ global = xzalloc(sizeof *global);
+ global->name = id;
+ global->interface = strdup(interface);
+ assert(interface);
+ global->version = version;
+ wl_list_insert(client->global_list.prev, &global->link);
+
+ if (strcmp(interface, "wl_compositor") == 0) {
+ client->wl_compositor =
+ wl_registry_bind(registry, id,
+ &wl_compositor_interface, 1);
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ input = xzalloc(sizeof *input);
+ input->wl_seat =
+ wl_registry_bind(registry, id,
+ &wl_seat_interface, 1);
+ wl_seat_add_listener(input->wl_seat, &seat_listener, input);
+ client->input = input;
+ } else if (strcmp(interface, "wl_shm") == 0) {
+ client->wl_shm =
+ wl_registry_bind(registry, id,
+ &wl_shm_interface, 1);
+ wl_shm_add_listener(client->wl_shm, &shm_listener, client);
+ } else if (strcmp(interface, "wl_output") == 0) {
+ output = xzalloc(sizeof *output);
+ output->wl_output =
+ wl_registry_bind(registry, id,
+ &wl_output_interface, 1);
+ wl_output_add_listener(output->wl_output,
+ &output_listener, output);
+ client->output = output;
+ } else if (strcmp(interface, "wl_test") == 0) {
+ test = xzalloc(sizeof *test);
+ test->wl_test =
+ wl_registry_bind(registry, id,
+ &wl_test_interface, 1);
+ wl_test_add_listener(test->wl_test, &test_listener, test);
+ client->test = test;
+ }
+}
+
+static const struct wl_registry_listener registry_listener = {
+ handle_global
+};
+
+static void
+log_handler(const char *fmt, va_list args)
+{
+ fprintf(stderr, "libwayland: ");
+ vfprintf(stderr, fmt, args);
+}
+
+struct client *
+client_create(int x, int y, int width, int height)
+{
+ struct client *client;
+ struct surface *surface;
+
+ wl_log_set_handler_client(log_handler);
+
+ /* connect to display */
+ client = xzalloc(sizeof *client);
+ client->wl_display = wl_display_connect(NULL);
+ assert(client->wl_display);
+ wl_list_init(&client->global_list);
+
+ /* setup registry so we can bind to interfaces */
+ client->wl_registry = wl_display_get_registry(client->wl_display);
+ wl_registry_add_listener(client->wl_registry, &registry_listener, client);
+
+ /* trigger global listener */
+ wl_display_dispatch(client->wl_display);
+ wl_display_roundtrip(client->wl_display);
+
+ /* must have WL_SHM_FORMAT_ARGB32 */
+ assert(client->has_argb);
+
+ /* must have wl_test interface */
+ assert(client->test);
+
+ /* must have an output */
+ assert(client->output);
+
+ /* initialize the client surface */
+ surface = xzalloc(sizeof *surface);
+ surface->wl_surface =
+ wl_compositor_create_surface(client->wl_compositor);
+ assert(surface->wl_surface);
+
+ wl_surface_add_listener(surface->wl_surface, &surface_listener,
+ surface);
+
+ client->surface = surface;
+ wl_surface_set_user_data(surface->wl_surface, surface);
+
+ surface->width = width;
+ surface->height = height;
+ surface->wl_buffer = create_shm_buffer(client, width, height,
+ &surface->data);
+
+ memset(surface->data, 64, width * height * 4);
+
+ move_client(client, x, y);
+
+ return client;
+}
diff --git a/tests/weston-test-client-helper.h b/tests/weston-test-client-helper.h
new file mode 100644
index 00000000..a5edca90
--- /dev/null
+++ b/tests/weston-test-client-helper.h
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+#ifndef _WESTON_TEST_CLIENT_HELPER_H_
+#define _WESTON_TEST_CLIENT_HELPER_H_
+
+#include <assert.h>
+#include "weston-test-runner.h"
+#include "wayland-test-client-protocol.h"
+
+struct client {
+ struct wl_display *wl_display;
+ struct wl_registry *wl_registry;
+ struct wl_compositor *wl_compositor;
+ struct wl_shm *wl_shm;
+ struct test *test;
+ struct input *input;
+ struct output *output;
+ struct surface *surface;
+ int has_argb;
+ struct wl_list global_list;
+};
+
+struct global {
+ uint32_t name;
+ char *interface;
+ uint32_t version;
+ struct wl_list link;
+};
+
+struct test {
+ struct wl_test *wl_test;
+ int pointer_x;
+ int pointer_y;
+};
+
+struct input {
+ struct wl_seat *wl_seat;
+ struct pointer *pointer;
+ struct keyboard *keyboard;
+};
+
+struct pointer {
+ struct wl_pointer *wl_pointer;
+ struct surface *focus;
+ int x;
+ int y;
+ uint32_t button;
+ uint32_t state;
+};
+
+struct keyboard {
+ struct wl_keyboard *wl_keyboard;
+ struct surface *focus;
+ uint32_t key;
+ uint32_t state;
+ uint32_t mods_depressed;
+ uint32_t mods_latched;
+ uint32_t mods_locked;
+ uint32_t group;
+};
+
+struct output {
+ struct wl_output *wl_output;
+ int x;
+ int y;
+ int width;
+ int height;
+};
+
+struct surface {
+ struct wl_surface *wl_surface;
+ struct wl_buffer *wl_buffer;
+ struct output *output;
+ int x;
+ int y;
+ int width;
+ int height;
+ void *data;
+};
+
+struct client *
+client_create(int x, int y, int width, int height);
+
+struct wl_buffer *
+create_shm_buffer(struct client *client, int width, int height, void **pixels);
+
+int
+surface_contains(struct surface *surface, int x, int y);
+
+void
+move_client(struct client *client, int x, int y);
+
+#define client_roundtrip(c) do { \
+ assert(wl_display_roundtrip((c)->wl_display) >= 0); \
+} while (0)
+
+struct wl_callback *
+frame_callback_set(struct wl_surface *surface, int *done);
+
+void
+frame_callback_wait(struct client *client, int *done);
+
+#endif
diff --git a/tests/weston-test-runner.c b/tests/weston-test-runner.c
new file mode 100644
index 00000000..4274b393
--- /dev/null
+++ b/tests/weston-test-runner.c
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include "weston-test-runner.h"
+
+extern const struct weston_test __start_test_section, __stop_test_section;
+
+static const struct weston_test *
+find_test(const char *name)
+{
+ const struct weston_test *t;
+
+ for (t = &__start_test_section; t < &__stop_test_section; t++)
+ if (strcmp(t->name, name) == 0)
+ return t;
+
+ return NULL;
+}
+
+static void
+run_test(const struct weston_test *t, void *data)
+{
+ t->run(data);
+ exit(EXIT_SUCCESS);
+}
+
+static void
+list_tests(void)
+{
+ const struct weston_test *t;
+
+ fprintf(stderr, "Available test names:\n");
+ for (t = &__start_test_section; t < &__stop_test_section; t++)
+ fprintf(stderr, " %s\n", t->name);
+}
+
+static int
+exec_and_report_test(const struct weston_test *t, void *test_data, int iteration)
+{
+ int success = 0;
+ int hardfail = 0;
+ siginfo_t info;
+
+ pid_t pid = fork();
+ assert(pid >= 0);
+
+ if (pid == 0)
+ run_test(t, test_data); /* never returns */
+
+ if (waitid(P_ALL, 0, &info, WEXITED)) {
+ fprintf(stderr, "waitid failed: %m\n");
+ abort();
+ }
+
+ if (test_data)
+ fprintf(stderr, "test \"%s/%i\":\t", t->name, iteration);
+ else
+ fprintf(stderr, "test \"%s\":\t", t->name);
+
+ switch (info.si_code) {
+ case CLD_EXITED:
+ fprintf(stderr, "exit status %d", info.si_status);
+ if (info.si_status == EXIT_SUCCESS)
+ success = 1;
+ break;
+ case CLD_KILLED:
+ case CLD_DUMPED:
+ fprintf(stderr, "signal %d", info.si_status);
+ if (info.si_status != SIGABRT)
+ hardfail = 1;
+ break;
+ }
+
+ if (t->must_fail)
+ success = !success;
+
+ if (success && !hardfail) {
+ fprintf(stderr, ", pass.\n");
+ return 1;
+ } else {
+ fprintf(stderr, ", fail.\n");
+ return 0;
+ }
+}
+
+/* Returns number of tests and number of pass / fail in param args */
+static int
+iterate_test(const struct weston_test *t, int *passed)
+{
+ int i;
+ void *current_test_data = (void *) t->table_data;
+ for (i = 0; i < t->n_elements; ++i, current_test_data += t->element_size)
+ {
+ if (exec_and_report_test(t, current_test_data, i))
+ ++(*passed);
+ }
+
+ return t->n_elements;
+}
+
+int main(int argc, char *argv[])
+{
+ const struct weston_test *t;
+ int total = 0;
+ int pass = 0;
+
+ if (argc == 2) {
+ const char *testname = argv[1];
+ if (strcmp(testname, "--help") == 0 ||
+ strcmp(testname, "-h") == 0) {
+ fprintf(stderr, "Usage: %s [test-name]\n", program_invocation_short_name);
+ list_tests();
+ exit(EXIT_SUCCESS);
+ }
+
+ t = find_test(argv[1]);
+ if (t == NULL) {
+ fprintf(stderr, "unknown test: \"%s\"\n", argv[1]);
+ list_tests();
+ exit(EXIT_FAILURE);
+ }
+
+ int number_passed_in_test = 0;
+ total += iterate_test(t, &number_passed_in_test);
+ pass += number_passed_in_test;
+ } else {
+ for (t = &__start_test_section; t < &__stop_test_section; t++) {
+ int number_passed_in_test = 0;
+ total += iterate_test(t, &number_passed_in_test);
+ pass += number_passed_in_test;
+ }
+ }
+
+ fprintf(stderr, "%d tests, %d pass, %d fail\n",
+ total, pass, total - pass);
+
+ return pass == total ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/tests/weston-test-runner.h b/tests/weston-test-runner.h
new file mode 100644
index 00000000..457cf31c
--- /dev/null
+++ b/tests/weston-test-runner.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2013 Sam Spilsbury <smspillaz@gmail.com>
+ *
+ * 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.
+ */
+
+#ifndef _WESTON_TEST_RUNNER_H_
+#define _WESTON_TEST_RUNNER_H_
+
+#include <stdlib.h>
+
+#ifdef NDEBUG
+#error "Tests must not be built with NDEBUG defined, they rely on assert()."
+#endif
+
+struct weston_test {
+ const char *name;
+ void (*run)(void *);
+ const void *table_data;
+ size_t element_size;
+ int n_elements;
+ int must_fail;
+} __attribute__ ((aligned (32)));
+
+#define TEST_BEGIN(name, arg) \
+ static void name(arg)
+
+#define TEST_COMMON(func, name, ret, data, size, n_elem) \
+ static void func(void *); \
+ \
+ const struct weston_test test##name \
+ __attribute__ ((section ("test_section"))) = \
+ { \
+ #name, func, data, size, n_elem, ret \
+ };
+
+#define NO_ARG_TEST(name, ret) \
+ TEST_COMMON(wrap##name, name, ret, NULL, 0, 1) \
+ static void name(void); \
+ static void wrap##name(void *data) \
+ { \
+ (void) data; \
+ name(); \
+ } \
+ \
+ TEST_BEGIN(name, void)
+
+#define ARG_TEST(name, ret, test_data) \
+ TEST_COMMON(name, name, ret, test_data, \
+ sizeof(test_data[0]), \
+ sizeof(test_data) / sizeof (test_data[0])) \
+ TEST_BEGIN(name, void *data) \
+
+#define TEST(name) NO_ARG_TEST(name, 0)
+#define FAIL_TEST(name) NO_ARG_TEST(name, 1)
+#define TEST_P(name, data) ARG_TEST(name, 0, data)
+#define FAIL_TEST_P(name, data) ARG_TEST(name, 1, data)
+
+#endif
diff --git a/tests/weston-test.c b/tests/weston-test.c
new file mode 100644
index 00000000..bc5b6e9d
--- /dev/null
+++ b/tests/weston-test.c
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <unistd.h>
+#include "../src/compositor.h"
+#include "wayland-test-server-protocol.h"
+
+struct weston_test {
+ struct weston_compositor *compositor;
+ struct weston_layer layer;
+ struct weston_process process;
+};
+
+struct weston_test_surface {
+ struct weston_surface *surface;
+ int32_t x, y;
+ struct weston_test *test;
+};
+
+static void
+test_client_sigchld(struct weston_process *process, int status)
+{
+ struct weston_test *test =
+ container_of(process, struct weston_test, process);
+
+ assert(status == 0);
+
+ wl_display_terminate(test->compositor->wl_display);
+}
+
+static struct weston_seat *
+get_seat(struct weston_test *test)
+{
+ struct wl_list *seat_list;
+ struct weston_seat *seat;
+
+ seat_list = &test->compositor->seat_list;
+ assert(wl_list_length(seat_list) == 1);
+ seat = container_of(seat_list->next, struct weston_seat, link);
+
+ return seat;
+}
+
+static void
+notify_pointer_position(struct weston_test *test, struct wl_resource *resource)
+{
+ struct weston_seat *seat = get_seat(test);
+ struct weston_pointer *pointer = seat->pointer;
+
+ wl_test_send_pointer_position(resource, pointer->x, pointer->y);
+}
+
+static void
+test_surface_configure(struct weston_surface *surface, int32_t sx, int32_t sy, int32_t width, int32_t height)
+{
+ struct weston_test_surface *test_surface = surface->configure_private;
+ struct weston_test *test = test_surface->test;
+
+ if (wl_list_empty(&surface->layer_link))
+ wl_list_insert(&test->layer.surface_list,
+ &surface->layer_link);
+
+ weston_surface_configure(surface, test_surface->x, test_surface->y,
+ width, height);
+
+ if (!weston_surface_is_mapped(surface))
+ weston_surface_update_transform(surface);
+}
+
+static void
+move_surface(struct wl_client *client, struct wl_resource *resource,
+ struct wl_resource *surface_resource,
+ int32_t x, int32_t y)
+{
+ struct weston_surface *surface =
+ wl_resource_get_user_data(surface_resource);
+ struct weston_test_surface *test_surface;
+
+ surface->configure = test_surface_configure;
+ if (surface->configure_private == NULL)
+ surface->configure_private = malloc(sizeof *test_surface);
+ test_surface = surface->configure_private;
+ if (test_surface == NULL) {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ test_surface->surface = surface;
+ test_surface->test = wl_resource_get_user_data(resource);
+ test_surface->x = x;
+ test_surface->y = y;
+}
+
+static void
+move_pointer(struct wl_client *client, struct wl_resource *resource,
+ int32_t x, int32_t y)
+{
+ struct weston_test *test = wl_resource_get_user_data(resource);
+ struct weston_seat *seat = get_seat(test);
+ struct weston_pointer *pointer = seat->pointer;
+
+ test->compositor->focus = 1;
+
+ notify_motion(seat, 100,
+ wl_fixed_from_int(x) - pointer->x,
+ wl_fixed_from_int(y) - pointer->y);
+
+ notify_pointer_position(test, resource);
+}
+
+static void
+send_button(struct wl_client *client, struct wl_resource *resource,
+ int32_t button, uint32_t state)
+{
+ struct weston_test *test = wl_resource_get_user_data(resource);
+ struct weston_seat *seat = get_seat(test);
+
+ test->compositor->focus = 1;
+
+ notify_button(seat, 100, button, state);
+}
+
+static void
+activate_surface(struct wl_client *client, struct wl_resource *resource,
+ struct wl_resource *surface_resource)
+{
+ struct weston_surface *surface = surface_resource ?
+ wl_resource_get_user_data(surface_resource) : NULL;
+ struct weston_test *test = wl_resource_get_user_data(resource);
+ struct weston_seat *seat;
+
+ seat = get_seat(test);
+
+ if (surface) {
+ weston_surface_activate(surface, seat);
+ notify_keyboard_focus_in(seat, &seat->keyboard->keys,
+ STATE_UPDATE_AUTOMATIC);
+ }
+ else {
+ notify_keyboard_focus_out(seat);
+ weston_surface_activate(surface, seat);
+ }
+}
+
+static void
+send_key(struct wl_client *client, struct wl_resource *resource,
+ uint32_t key, enum wl_keyboard_key_state state)
+{
+ struct weston_test *test = wl_resource_get_user_data(resource);
+ struct weston_seat *seat = get_seat(test);
+
+ test->compositor->focus = 1;
+
+ notify_key(seat, 100, key, state, STATE_UPDATE_AUTOMATIC);
+}
+
+static const struct wl_test_interface test_implementation = {
+ move_surface,
+ move_pointer,
+ send_button,
+ activate_surface,
+ send_key
+};
+
+static void
+bind_test(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+ struct weston_test *test = data;
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(client, &wl_test_interface, 1, id);
+ wl_resource_set_implementation(resource,
+ &test_implementation, test, NULL);
+
+ notify_pointer_position(test, resource);
+}
+
+static void
+idle_launch_client(void *data)
+{
+ struct weston_test *test = data;
+ pid_t pid;
+ sigset_t allsigs;
+ char *path;
+
+ path = getenv("WESTON_TEST_CLIENT_PATH");
+ if (path == NULL)
+ exit(EXIT_FAILURE);
+ pid = fork();
+ if (pid == -1)
+ exit(EXIT_FAILURE);
+ if (pid == 0) {
+ sigfillset(&allsigs);
+ sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
+ execl(path, path, NULL);
+ weston_log("compositor: executing '%s' failed: %m\n", path);
+ exit(EXIT_FAILURE);
+ }
+
+ test->process.pid = pid;
+ test->process.cleanup = test_client_sigchld;
+ weston_watch_process(&test->process);
+}
+
+WL_EXPORT int
+module_init(struct weston_compositor *ec,
+ int *argc, char *argv[])
+{
+ struct weston_test *test;
+ struct wl_event_loop *loop;
+
+ test = zalloc(sizeof *test);
+ if (test == NULL)
+ return -1;
+
+ test->compositor = ec;
+ weston_layer_init(&test->layer, &ec->cursor_layer.link);
+
+ if (wl_global_create(ec->wl_display, &wl_test_interface, 1,
+ test, bind_test) == NULL)
+ return -1;
+
+ loop = wl_display_get_event_loop(ec->wl_display);
+ wl_event_loop_add_idle(loop, idle_launch_client, test);
+
+ return 0;
+}
diff --git a/tests/weston-tests-env b/tests/weston-tests-env
new file mode 100755
index 00000000..b7322507
--- /dev/null
+++ b/tests/weston-tests-env
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+TESTNAME=$1
+
+if test -z "$TESTNAME"; then
+ echo "usage: $(basename $0) <test name>"
+ exit 1;
+fi
+
+WESTON=$abs_builddir/../src/weston
+LOGDIR=$abs_builddir/logs
+
+mkdir -p "$LOGDIR"
+
+SERVERLOG="$LOGDIR/$1-serverlog.txt"
+OUTLOG="$LOGDIR/$1-log.txt"
+
+rm -f "$SERVERLOG"
+
+if test x$WAYLAND_DISPLAY != x; then
+ BACKEND=$abs_builddir/../src/.libs/wayland-backend.so
+elif test x$DISPLAY != x; then
+ BACKEND=$abs_builddir/../src/.libs/x11-backend.so
+else
+ BACKEND=$abs_builddir/../src/.libs/wayland-backend.so
+fi
+
+case $TESTNAME in
+ *.la|*.so)
+ $WESTON --backend=$BACKEND \
+ --socket=test-$(basename $TESTNAME) \
+ --modules=$abs_builddir/.libs/${TESTNAME/.la/.so},xwayland.so \
+ --log="$SERVERLOG" \
+ &> "$OUTLOG"
+ ;;
+ *)
+ WESTON_TEST_CLIENT_PATH=$abs_builddir/$TESTNAME $WESTON \
+ --socket=test-$(basename $TESTNAME) \
+ --backend=$BACKEND \
+ --log="$SERVERLOG" \
+ --modules=$abs_builddir/.libs/weston-test.so,xwayland.so \
+ &> "$OUTLOG"
+esac
diff --git a/tests/xwayland-test.c b/tests/xwayland-test.c
new file mode 100644
index 00000000..658453f3
--- /dev/null
+++ b/tests/xwayland-test.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright © 2013 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.
+ *
+ * Author: Tiago Vignatti
+ *
+ * xwayland-test: the idea is to guarantee that XWayland infrastructure in
+ * general works with Weston.
+ */
+
+#include "weston-test-runner.h"
+
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <xcb/xcb.h>
+#include <xcb/dri2.h>
+#include <xf86drm.h>
+
+
+static int
+dri2_open(xcb_connection_t *c, xcb_screen_t *screen)
+{
+ xcb_dri2_connect_cookie_t cookie;
+ xcb_dri2_connect_reply_t *reply;
+ xcb_dri2_authenticate_cookie_t cookie_auth;
+ xcb_dri2_authenticate_reply_t *reply_auth;
+ char *driver, *device;
+ int fd;
+ drm_magic_t magic;
+
+ cookie = xcb_dri2_connect(c, screen->root, XCB_DRI2_DRIVER_TYPE_DRI);
+ reply = xcb_dri2_connect_reply(c, cookie, 0);
+ assert(reply);
+
+ driver = strndup(xcb_dri2_connect_driver_name (reply),
+ xcb_dri2_connect_driver_name_length (reply));
+ device = strndup(xcb_dri2_connect_device_name (reply),
+ xcb_dri2_connect_device_name_length (reply));
+
+ fd = open(device, O_RDWR);
+ printf ("Trying connect to %s driver on %s\n", driver, device);
+ free(driver);
+ free(device);
+
+ if (fd < 0)
+ return -1;
+
+ drmGetMagic(fd, &magic);
+
+ cookie_auth = xcb_dri2_authenticate(c, screen->root, magic);
+ reply_auth = xcb_dri2_authenticate_reply(c, cookie_auth, 0);
+ assert(reply_auth);
+
+ return fd;
+}
+
+static int
+create_window(void)
+{
+ xcb_connection_t *c;
+ xcb_screen_t *screen;
+ xcb_window_t win;
+ int fd;
+
+ c = xcb_connect (NULL, NULL);
+ if (c == NULL) {
+ printf("failed to get X11 connection\n");
+ return -1;
+ }
+
+ screen = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
+
+ win = xcb_generate_id(c);
+ xcb_create_window(c, XCB_COPY_FROM_PARENT, win, screen->root,
+ 0, 0, 150, 150, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT,
+ screen->root_visual, 0, NULL);
+
+ xcb_change_property (c, XCB_PROP_MODE_REPLACE, win,
+ XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
+ 5, "title");
+ xcb_map_window(c, win);
+ xcb_flush(c);
+
+ fd = dri2_open(c, screen);
+ if (fd < 0)
+ return -1;
+
+ xcb_destroy_window(c, win);
+ xcb_disconnect(c);
+ return 0;
+}
+
+/*
+ * Ideally, the X Window Manager (XWM) and Weston Wayland compositor shouldn't
+ * be in the same process because they are using two different protocol
+ * streams in which one does not interface with the other. Probably the
+ * biggest problem with such architecture are the potentials dead locks that
+ * it may occur. So hypothetically, an X client might issue an X11 blocking
+ * request via X (DRI2Authenticate) which in turn sends a Wayland blocking
+ * request for Weston process it. X is blocked. At the same time, XWM might be
+ * trying to process an XChangeProperty, so it requests a blocking X11 call to
+ * the X server (xcb_get_property_reply -> xcb_wait_for_reply) which therefore
+ * will blocks there. It's a deadlock situation and this test is trying to
+ * catch that.
+ */
+static void
+check_dri2_authenticate(void)
+{
+ int i, num_tests;
+
+ /* TODO: explain why num_tests times */
+ num_tests = 10;
+ for (i = 0; i < num_tests; i++)
+ assert(create_window() == 0);
+}
+
+TEST(xwayland_client_test)
+{
+ check_dri2_authenticate();
+ exit(EXIT_SUCCESS);
+}