diff --git a/tests/event-test.c b/tests/event-test.c index 2cbfc2d2..59e6970e 100644 --- a/tests/event-test.c +++ b/tests/event-test.c @@ -25,50 +25,313 @@ #include #include #include - #include #include "test-runner.h" +struct state { + int px; /* pointer x */ + int py; /* pointer y */ + int sx; /* surface x */ + int sy; /* surface y */ + int sw; /* surface width */ + int sh; /* surface height */ +}; + +static size_t state_size = sizeof(struct state); + +struct context { + struct weston_layer *layer; + struct weston_seat *seat; + struct weston_surface *surface; + int pointer_x; /* server pointer x */ + int pointer_y; /* server pointer y */ + size_t index; + struct wl_array states; +}; + +static void +resize(struct context *context, int w, int h) +{ + /* resize the surface only if the width or height is different */ + if (context->surface->geometry.width != w || + context->surface->geometry.height != h) { + + weston_surface_configure(context->surface, + context->surface->geometry.x, + context->surface->geometry.y, + w, h); + weston_surface_update_transform(context->surface); + weston_surface_damage(context->surface); + + fprintf(stderr, "resize surface: %d %d\n", + context->surface->geometry.width, + context->surface->geometry.height); + } +} + +static void +move(struct context *context, int x, int y) +{ + /* move the surface only if x or y is different */ + if (context->surface->geometry.x != x || + context->surface->geometry.y != y) { + + weston_surface_configure(context->surface, + x, y, + context->surface->geometry.width, + context->surface->geometry.height); + weston_surface_update_transform(context->surface); + weston_surface_damage(context->surface); + + fprintf(stderr, "move surface: %f %f\n", + context->surface->geometry.x, + context->surface->geometry.y); + } +} + +static int +contains(struct context *context, int x, int y) +{ + /* test whether a global x,y point is contained in the surface */ + int sx = context->surface->geometry.x; + int sy = context->surface->geometry.y; + int sw = context->surface->geometry.width; + int sh = context->surface->geometry.height; + return x >= sx && y >= sy && x < sx + sw && y < sy + sh; +} + +static void +move_pointer(struct context *context, int x, int y) +{ + if (contains(context, context->pointer_x, context->pointer_y)) { + /* pointer is currently on the surface */ + notify_motion(context->seat, 100, + wl_fixed_from_int(x), wl_fixed_from_int(y)); + } else { + /* pointer is not currently on the surface */ + notify_pointer_focus(context->seat, context->surface->output, + wl_fixed_from_int(x), + wl_fixed_from_int(y)); + } + + /* update server expected pointer location */ + context->pointer_x = x; + context->pointer_y = y; + + fprintf(stderr, "move pointer: %d %d\n", x, y); +} + +static void +check_pointer(struct context *context, int cx, int cy) +{ + /* + * Check whether the client reported pointer position matches + * the server expected pointer position. The client + * reports -1,-1 when the pointer is not on its surface and + * a surface relative x,y otherwise. + */ + int gx = context->surface->geometry.x + cx; + int gy = context->surface->geometry.y + cy; + if (!contains(context, gx, gy)) { + assert(!contains(context, context->pointer_x, + context->pointer_y)); + } else { + assert(gx == context->pointer_x); + assert(gy == context->pointer_y); + } +} + +static void +check_visible(struct context *context, int visible) +{ + /* + * Check whether the client reported surface visibility matches + * the servers expected surface visibility + */ + int ow = context->surface->output->width; + int oh = context->surface->output->height; + int sx = context->surface->geometry.x; + int sy = context->surface->geometry.y; + int sw = context->surface->geometry.width; + int sh = context->surface->geometry.height; + + const int expect = sx < ow && sy < oh && sx + sw > 0 && sy + sh > 0; + + assert(visible == expect); +} + +static void +handle_state(struct test_client *); + +static void +set_state(struct test_client *client) +{ + struct state* state; + struct context *context = client->data; + + if (context->index < context->states.size) { + state = context->states.data + context->index; + resize(context, state->sw, state->sh); + move(context, state->sx, state->sy); + move_pointer(context, state->px, state->py); + context->index += state_size; + + test_client_send(client, "send-state\n"); + client->handle = handle_state; + } else { + test_client_send(client, "bye\n"); + client->handle = NULL; + } +} + +static void +handle_state(struct test_client *client) +{ + struct context *context = client->data; + wl_fixed_t x, y; + int visible; + + assert(sscanf(client->buf, "%d %d %d", &x, &y, &visible) == 3); + + check_pointer(context, wl_fixed_to_int(x), wl_fixed_to_int(y)); + check_visible(context, visible); + + set_state(client); +} + +static void +add_state(struct context *context, int px, int py, int sx, int sy, + int sw, int sh) +{ + struct state *state = wl_array_add(&context->states, + sizeof(struct state)); + + assert(state); + + state->px = px; + state->py = py; + state->sx = sx; + state->sy = sy; + state->sw = sw; + state->sh = sh; +} + +static void +initialize_states(struct test_client *client) +{ + struct context *context = client->data; + struct weston_surface *surface = context->surface; + + int x = surface->geometry.x; + int y = surface->geometry.y; + int w = surface->geometry.width; + int h = surface->geometry.height; + + wl_array_init(&context->states); + + /* move pointer outside top left */ + add_state(context, x - 1, y - 1, x, y, w, h); + /* move pointer on top left */ + add_state(context, x, y, x, y, w, h); + /* move pointer outside bottom left */ + add_state(context, x - 1, y + h, x, y, w, h); + /* move pointer on bottom left */ + add_state(context, x, y + h - 1, x, y, w, h); + /* move pointer outside top right */ + add_state(context, x + w, y - 1, x, y, w, h); + /* move pointer on top right */ + add_state(context, x + w - 1, y, x, y, w, h); + /* move pointer outside bottom right */ + add_state(context, x + w, y + h, x, y, w, h); + /* move pointer on bottom right */ + add_state(context, x + w - 1, y + h - 1, x, y, w, h); + + /* move pointer outside top center */ + add_state(context, x + w/2, y - 1, x, y, w, h); + /* move pointer on top center */ + add_state(context, x + w/2, y, x, y, w, h); + /* move pointer outside bottom center */ + add_state(context, x + w/2, y + h, x, y, w, h); + /* move pointer on bottom center */ + add_state(context, x + w/2, y + h - 1, x, y, w, h); + /* move pointer outside left center */ + add_state(context, x - 1, y + h/2, x, y, w, h); + /* move pointer on left center */ + add_state(context, x, y + h/2, x, y, w, h); + /* move pointer outside right center */ + add_state(context, x + w, y + h/2, x, y, w, h); + /* move pointer on right center */ + add_state(context, x + w - 1, y + h/2, x, y, w, h); + + /* move pointer outside of client */ + add_state(context, 50, 50, x, y, w, h); + /* move client center to pointer */ + add_state(context, 50, 50, 0, 0, w, h); + + /* not visible */ + add_state(context, 0, 0, 0, -h, w, h); + /* visible */ + add_state(context, 0, 0, 0, -h+1, w, h); + /* not visible */ + add_state(context, 0, 0, 0, context->surface->output->height, w, h); + /* visible */ + add_state(context, 0, 0, 0, context->surface->output->height - 1, w, h); + /* not visible */ + add_state(context, 0, 0, -w, 0, w, h); + /* visible */ + add_state(context, 0, 0, -w+1, 0, w, h); + /* not visible */ + add_state(context, 0, 0, context->surface->output->width, 0, w, h); + /* visible */ + add_state(context, 0, 0, context->surface->output->width - 1, 0, w, h); + + set_state(client); +} + static void handle_surface(struct test_client *client) { uint32_t id; + struct context *context = client->data; struct wl_resource *resource; - struct weston_surface *surface; - struct weston_layer *layer = client->data; struct wl_list *seat_list; - struct weston_seat *seat; assert(sscanf(client->buf, "surface %u", &id) == 1); - fprintf(stderr, "got surface id %u\n", id); + fprintf(stderr, "server: got surface id %u\n", id); resource = wl_client_get_object(client->client, id); assert(resource); assert(strcmp(resource->object.interface->name, "wl_surface") == 0); - surface = (struct weston_surface *) resource; + context->surface = (struct weston_surface *) resource; + weston_surface_set_color(context->surface, 0.0, 0.0, 0.0, 1.0); - weston_surface_configure(surface, 100, 100, 200, 200); - weston_surface_update_transform(surface); - weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0); - wl_list_insert(&layer->surface_list, &surface->layer_link); - weston_surface_damage(surface); + context->layer = malloc(sizeof *context->layer); + assert(context->layer); + weston_layer_init(context->layer, + &client->compositor->cursor_layer.link); + wl_list_insert(&context->layer->surface_list, + &context->surface->layer_link); seat_list = &client->compositor->seat_list; assert(wl_list_length(seat_list) == 1); - seat = container_of(seat_list->next, struct weston_seat, link); + context->seat = container_of(seat_list->next, struct weston_seat, link); + client->compositor->focus = 1; /* Make it work even if pointer is * outside X window. */ - notify_motion(seat, 100, - wl_fixed_from_int(150), wl_fixed_from_int(150)); - test_client_send(client, "bye\n"); + resize(context, 100, 100); + move(context, 100, 100); + move_pointer(context, 150, 150); + + test_client_send(client, "send-state\n"); + client->handle = initialize_states; } TEST(event_test) { + struct context *context; struct test_client *client; - struct weston_layer *layer; client = test_client_launch(compositor, "test-client"); client->terminate = 1; @@ -76,8 +339,7 @@ TEST(event_test) test_client_send(client, "create-surface\n"); client->handle = handle_surface; - layer = malloc(sizeof *layer); - assert(layer); - weston_layer_init(layer, &compositor->cursor_layer.link); - client->data = layer; + context = calloc(1, sizeof *context); + assert(context); + client->data = context; } diff --git a/tests/test-client.c b/tests/test-client.c index 0009a8ef..fd54867f 100644 --- a/tests/test-client.c +++ b/tests/test-client.c @@ -35,6 +35,7 @@ struct display { struct wl_compositor *compositor; struct input *input; struct output *output; + struct surface *surface; }; struct input { @@ -68,6 +69,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer, input->pointer_focus = wl_surface_get_user_data(surface); input->x = wl_fixed_to_double(x); input->y = wl_fixed_to_double(y); + fprintf(stderr, "test-client: got pointer enter %f %f, surface %p\n", + input->x, input->y, surface); } static void @@ -77,6 +80,9 @@ pointer_handle_leave(void *data, struct wl_pointer *pointer, struct input *input = data; input->pointer_focus = NULL; + + fprintf(stderr, "test-client: got pointer leave, surface %p\n", + surface); } static void @@ -87,6 +93,9 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer, input->x = wl_fixed_to_double(x); input->y = wl_fixed_to_double(y); + + fprintf(stderr, "test-client: got pointer motion %f %f\n", + input->x, input->y); } static void @@ -103,12 +112,15 @@ pointer_handle_button(void *data, struct wl_pointer *pointer, input->button_mask |= bit; else input->button_mask &= ~bit; + fprintf(stderr, "test-client: got pointer button %u %u\n", + button, state_w); } static void pointer_handle_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { + fprintf(stderr, "test-client: got pointer axis %u %d\n", axis, value); } static void @@ -116,6 +128,7 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) { close(fd); + fprintf(stderr, "test-client: got keyboard keymap\n"); } static void @@ -126,6 +139,8 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, struct input *input = data; input->keyboard_focus = wl_surface_get_user_data(surface); + fprintf(stderr, "test-client: got keyboard enter, surface %p\n", + surface); } static void @@ -135,6 +150,8 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, struct input *input = data; input->keyboard_focus = NULL; + fprintf(stderr, "test-client: got keyboard leave, surface %p\n", + surface); } static void @@ -142,6 +159,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { + fprintf(stderr, "test-client: got keyboard key %u %u\n", key, state); } static void @@ -150,6 +168,7 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { + fprintf(stderr, "test-client: got keyboard modifier\n"); } static const struct wl_pointer_listener pointer_listener = { @@ -266,7 +285,8 @@ handle_global(struct wl_display *_display, uint32_t id, &output_listener, output); display->output = output; - fprintf(stderr, "created output global %p\n", display->output); + fprintf(stderr, "test-client: created output global %p\n", + display->output); } } @@ -278,7 +298,8 @@ surface_enter(void *data, surface->output = wl_output_get_user_data(output); - fprintf(stderr, "got surface enter, output %p\n", surface->output); + fprintf(stderr, "test-client: got surface enter, output %p\n", + surface->output); } static void @@ -288,6 +309,9 @@ surface_leave(void *data, 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 = { @@ -295,6 +319,33 @@ static const struct wl_surface_listener surface_listener = { surface_leave }; +static void +send_state(int fd, struct display* display) +{ + char buf[64]; + int len; + int visible = display->surface->output != NULL; + wl_fixed_t x = wl_fixed_from_int(-1); + wl_fixed_t y = wl_fixed_from_int(-1); + + if (display->input->pointer_focus == display->surface) { + x = wl_fixed_from_double(display->input->x); + y = wl_fixed_from_double(display->input->y); + } + + if (visible) { + /* FIXME: this fails on multi-display setup */ + /* assert(display->surface->output == display->output); */ + } + + wl_display_flush(display->display); + + len = snprintf(buf, sizeof buf, "%d %d %d\n", x, y, visible); + assert(write(fd, buf, len) == len); + + wl_display_roundtrip(display->display); +} + static void create_surface(int fd, struct display *display) { @@ -304,8 +355,10 @@ create_surface(int fd, struct display *display) surface = malloc(sizeof *surface); assert(surface); + display->surface = surface; surface->surface = wl_compositor_create_surface(display->compositor); wl_surface_add_listener(surface->surface, &surface_listener, surface); + wl_display_flush(display->display); len = snprintf(buf, sizeof buf, "surface %d\n", @@ -313,12 +366,8 @@ create_surface(int fd, struct display *display) assert(write(fd, buf, len) == len); poll(NULL, 0, 100); /* Wait for next frame where we'll get events. */ - wl_display_roundtrip(display->display); - assert(surface->output == display->output); - assert(display->input->pointer_focus == surface); - assert(display->input->x == 50); - assert(display->input->y == 50); + wl_display_roundtrip(display->display); } int main(int argc, char *argv[]) @@ -346,7 +395,8 @@ int main(int argc, char *argv[]) while (1) { ret = read(fd, buf, sizeof buf); if (ret == -1) { - fprintf(stderr, "read error: fd %d, %m\n", fd); + fprintf(stderr, "test-client: read error: fd %d, %m\n", + fd); return -1; } @@ -356,8 +406,11 @@ int main(int argc, char *argv[]) return 0; } else if (strncmp(buf, "create-surface\n", ret) == 0) { create_surface(fd, display); + } else if (strncmp(buf, "send-state\n", ret) == 0) { + send_state(fd, display); } else { - fprintf(stderr, "unknown command %.*s\n", ret, buf); + fprintf(stderr, "test-client: unknown command %.*s\n", + ret, buf); return -1; } } diff --git a/tests/test-runner.c b/tests/test-runner.c index 09c2b1f9..6ca087d3 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -40,7 +40,7 @@ test_client_cleanup(struct weston_process *proc, int status) struct test_client *client = container_of(proc, struct test_client, proc); - fprintf(stderr, "test client exited, status %d\n", status); + fprintf(stderr, "server: test client exited, status %d\n", status); client->status = status; client->done = 1; @@ -60,7 +60,7 @@ test_client_data(int fd, uint32_t mask, void *data) len = read(client->fd, client->buf, sizeof client->buf); assert(len >= 0); - fprintf(stderr, "got %.*s from client\n", len - 1, client->buf); + fprintf(stderr, "server: got %.*s from client\n", len - 1, client->buf); assert(client->buf[len - 1] == '\n'); client->buf[len - 1] = '\0'; @@ -88,7 +88,7 @@ test_client_launch(struct weston_compositor *compositor, const char *file_name) snprintf(buf, sizeof buf, "%d", client_fd); setenv("TEST_SOCKET", buf, 1); snprintf(buf, sizeof buf, "%s/%s", getenv("abs_builddir"), file_name); - fprintf(stderr, "launching %s\n", buf); + fprintf(stderr, "server: launching %s\n", buf); client->terminate = 0; client->compositor = compositor; @@ -117,6 +117,8 @@ test_client_send(struct test_client *client, const char *fmt, ...) len = vsnprintf(buf, sizeof buf, fmt, ap); va_end(ap); + fprintf(stderr, "server: sending %s", buf); + assert(write(client->fd, buf, len) == len); }