diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/.gitignore | 13 | ||||
-rw-r--r-- | tests/Makefile.am | 158 | ||||
-rw-r--r-- | tests/button-test.c | 55 | ||||
-rw-r--r-- | tests/config-parser-test.c | 203 | ||||
-rw-r--r-- | tests/event-test.c | 418 | ||||
-rw-r--r-- | tests/keyboard-test.c | 65 | ||||
-rw-r--r-- | tests/matrix-test.c | 419 | ||||
-rw-r--r-- | tests/setbacklight.c | 186 | ||||
-rw-r--r-- | tests/subsurface-test.c | 549 | ||||
-rw-r--r-- | tests/surface-global-test.c | 80 | ||||
-rw-r--r-- | tests/surface-test.c | 63 | ||||
-rw-r--r-- | tests/text-test.c | 214 | ||||
-rw-r--r-- | tests/vertex-clip-test.c | 219 | ||||
-rw-r--r-- | tests/weston-test-client-helper.c | 539 | ||||
-rw-r--r-- | tests/weston-test-client-helper.h | 123 | ||||
-rw-r--r-- | tests/weston-test-runner.c | 167 | ||||
-rw-r--r-- | tests/weston-test-runner.h | 76 | ||||
-rw-r--r-- | tests/weston-test.c | 250 | ||||
-rwxr-xr-x | tests/weston-tests-env | 43 | ||||
-rw-r--r-- | tests/xwayland-test.c | 142 |
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, §ion, &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, ®istry_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); +} |