/* An input event callback that destroys its own surface. The app runner * must not touch the surface's entry after the callback, and must not * deliver the surface's remaining input. Needs a Wayland compositor. */ #include "platform/wayland/internal.h" #include "yasl/app.h" #include #include #include struct test_state { bool initialized; int keys; int buttons, motions, resets; int end; }; static void push_key(struct yasl_surface *s) { struct yasl_event ev = { .surface = s, .type = YASL_EVENT_KEY, .key = { .key = YASL_KEY_A, .action = YASL_KEY_PRESS }, }; assert(input_queue_push(&((struct wayland_surface *)s)->input, &ev)); } static enum yasl_app_result on_init(void *ud, struct yasl_display *d) { struct test_state *state = ud; state->initialized = true; if (state->end == 3) { /* With no event callback, a close request alone stops the runner. */ struct yasl_surface *s = yasl_surface_create_toplevel(d, &(struct yasl_window_spec){ .title = "App Close Test", .size = {64, 64} }); assert(s); yasl_surface_notify_close(s); return YASL_APP_CONTINUE; } if (state->end) { if (state->end == 1) yasl_display_notify_event(d, YASL_EVENT_DISPLAY_QUIT); else yasl_display_notify_event(d, YASL_EVENT_DISPLAY_LOST); return YASL_APP_CONTINUE; } struct yasl_surface *s = yasl_surface_create_toplevel(d, &(struct yasl_window_spec){ .title = "App Input Test", .size = {64, 64} }); assert(s); struct input_queue *queue = &((struct wayland_surface *)s)->input; input_queue_clear(queue); struct yasl_event event = {.surface = s, .type = YASL_EVENT_POINTER_DOWN, .pointer = {.device = YASL_PTR_DEV_ERASER, .button = YASL_BUTTON_PRIMARY, .pos = {12, 34}, .pen = {.pressure = 50000, .tilt_x = -20, .tilt_y = 30}}}; assert(input_queue_push(queue, &event)); event.type = YASL_EVENT_POINTER_MOTION; event.pointer.pos = (struct yasl_vector2i){15, 39}; assert(input_queue_push(queue, &event)); struct yasl_event reset = {.surface = s, .type = YASL_EVENT_INPUT_RESET}; assert(input_queue_push(queue, &reset)); event.pointer.device = YASL_PTR_DEV_PEN; event.pointer.pos = (struct yasl_vector2i){100, 200}; assert(input_queue_push(queue, &event)); push_key(s); push_key(s); return YASL_APP_CONTINUE; } static enum yasl_app_result on_event(void *ud, const struct yasl_event *ev) { struct test_state *state = ud; if (ev->type == YASL_EVENT_POINTER_DOWN) { assert(ev->pointer.device == YASL_PTR_DEV_ERASER); assert(ev->pointer.button == YASL_BUTTON_PRIMARY); assert(ev->pointer.pos.x == 12 && ev->pointer.pos.y == 34); assert(ev->pointer.pen.pressure == 50000); assert(ev->pointer.pen.tilt_x == -20 && ev->pointer.pen.tilt_y == 30); state->buttons++; } else if (ev->type == YASL_EVENT_POINTER_MOTION) { if (!state->motions) { assert(ev->pointer.device == YASL_PTR_DEV_ERASER); assert(ev->pointer.delta.x == 3 && ev->pointer.delta.y == 5); } else { assert(ev->pointer.device == YASL_PTR_DEV_PEN); assert(!ev->pointer.delta.x && !ev->pointer.delta.y); } assert(ev->pointer.pen.pressure == 50000); state->motions++; } else if (ev->type == YASL_EVENT_INPUT_RESET) { state->resets++; } else if (ev->type == YASL_EVENT_KEY) { state->keys++; yasl_surface_destroy(ev->surface); } return YASL_APP_CONTINUE; } int main(void) { if (!getenv("WAYLAND_DISPLAY")) return 77; struct test_state state = {0}; int res = yasl_run(&(struct yasl_app_desc){ .app_id = "org.yasl.test.app-input", .backend = YASL_BACKEND_WAYLAND, .userdata = &state, .init = on_init, .event = on_event, }); /* A display variable may exist even when the test sandbox cannot connect * to that compositor. Keep this as an integration test in that case. */ if (res < 0 && !state.initialized && (errno == EACCES || errno == EPERM || errno == ENOENT || errno == ECONNREFUSED || errno == ENODEV)) return 77; assert(res == 0); assert(state.keys == 1); assert(state.buttons == 1 && state.motions == 2 && state.resets == 1); for (int end = 1; end <= 2; end++) { state = (struct test_state){.end = end}; res = yasl_run(&(struct yasl_app_desc){ .backend = YASL_BACKEND_WAYLAND, .userdata = &state, .init = on_init, }); assert(end == 1 ? res == 0 : res < 0); } state = (struct test_state){.end = 3}; res = yasl_run(&(struct yasl_app_desc){ .backend = YASL_BACKEND_WAYLAND, .userdata = &state, .init = on_init, }); assert(res == 0); return 0; }