summaryrefslogtreecommitdiff
path: root/tests/wayland/test_app_input.c
blob: 7e0e9a07363f0d4dd5a7a2c1d6b09b0f39233c35 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* 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 <assert.h>
#include <errno.h>
#include <stdlib.h>

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;
}