event-test: more aggressive event testing
[profile/ivi/weston.git] / tests / event-test.c
1 /*
2  * Copyright © 2012 Intel Corporation
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and
5  * its documentation for any purpose is hereby granted without fee, provided
6  * that the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of the copyright holders not be used in
9  * advertising or publicity pertaining to distribution of the software
10  * without specific, written prior permission.  The copyright holders make
11  * no representations about the suitability of this software for any
12  * purpose.  It is provided "as is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <sys/socket.h>
26 #include <assert.h>
27 #include <unistd.h>
28 #include <string.h>
29
30 #include "test-runner.h"
31
32 struct state {
33         int px; /* pointer x */
34         int py; /* pointer y */
35         int sx; /* surface x */
36         int sy; /* surface y */
37         int sw; /* surface width */
38         int sh; /* surface height */
39 };
40
41 static size_t state_size = sizeof(struct state);
42
43 struct context {
44         struct weston_layer *layer;
45         struct weston_seat *seat;
46         struct weston_surface *surface;
47         int pointer_x; /* server pointer x */
48         int pointer_y; /* server pointer y */
49         size_t index;
50         struct wl_array states;
51 };
52
53 static void
54 resize(struct context *context, int w, int h)
55 {
56         /* resize the surface only if the width or height is different */
57         if (context->surface->geometry.width != w ||
58             context->surface->geometry.height != h) {
59
60                 weston_surface_configure(context->surface,
61                                          context->surface->geometry.x,
62                                          context->surface->geometry.y,
63                                          w, h);
64                 weston_surface_update_transform(context->surface);
65                 weston_surface_damage(context->surface);
66
67                 fprintf(stderr, "resize surface: %d %d\n",
68                         context->surface->geometry.width,
69                         context->surface->geometry.height);
70         }
71 }
72
73 static void
74 move(struct context *context, int x, int y)
75 {
76         /* move the surface only if x or y is different */
77         if (context->surface->geometry.x != x ||
78             context->surface->geometry.y != y) {
79
80                 weston_surface_configure(context->surface,
81                                          x, y,
82                                          context->surface->geometry.width,
83                                          context->surface->geometry.height);
84                 weston_surface_update_transform(context->surface);
85                 weston_surface_damage(context->surface);
86
87                 fprintf(stderr, "move surface: %f %f\n",
88                         context->surface->geometry.x,
89                         context->surface->geometry.y);
90         }
91 }
92
93 static int
94 contains(struct context *context, int x, int y)
95 {
96         /* test whether a global x,y point is contained in the surface */
97         int sx = context->surface->geometry.x;
98         int sy = context->surface->geometry.y;
99         int sw = context->surface->geometry.width;
100         int sh = context->surface->geometry.height;
101         return x >= sx && y >= sy && x < sx + sw && y < sy + sh;
102 }
103
104 static void
105 move_pointer(struct context *context, int x, int y)
106 {
107         if (contains(context, context->pointer_x, context->pointer_y)) {
108                 /* pointer is currently on the surface */
109                 notify_motion(context->seat, 100,
110                               wl_fixed_from_int(x), wl_fixed_from_int(y));
111         } else {
112                 /* pointer is not currently on the surface */
113                 notify_pointer_focus(context->seat, context->surface->output,
114                                      wl_fixed_from_int(x),
115                                      wl_fixed_from_int(y));
116         }
117
118         /* update server expected pointer location */
119         context->pointer_x = x;
120         context->pointer_y = y;
121
122         fprintf(stderr, "move pointer: %d %d\n", x, y);
123 }
124
125 static void
126 check_pointer(struct context *context, int cx, int cy)
127 {
128         /*
129          * Check whether the client reported pointer position matches
130          * the server expected pointer position.  The client
131          * reports -1,-1 when the pointer is not on its surface and
132          * a surface relative x,y otherwise.
133          */
134         int gx = context->surface->geometry.x + cx;
135         int gy = context->surface->geometry.y + cy;
136         if (!contains(context, gx, gy)) {
137                 assert(!contains(context, context->pointer_x,
138                                  context->pointer_y));
139         } else {
140                 assert(gx == context->pointer_x);
141                 assert(gy == context->pointer_y);
142         }
143 }
144
145 static void
146 check_visible(struct context *context, int visible)
147 {
148         /*
149          * Check whether the client reported surface visibility matches
150          * the servers expected surface visibility
151          */
152         int ow = context->surface->output->width;
153         int oh = context->surface->output->height;
154         int sx = context->surface->geometry.x;
155         int sy = context->surface->geometry.y;
156         int sw = context->surface->geometry.width;
157         int sh = context->surface->geometry.height;
158
159         const int expect = sx < ow && sy < oh && sx + sw > 0 && sy + sh > 0;
160
161         assert(visible == expect);
162 }
163
164 static void
165 handle_state(struct test_client *);
166
167 static void
168 set_state(struct test_client *client)
169 {
170         struct state* state;
171         struct context *context = client->data;
172
173         if (context->index < context->states.size) {
174                 state = context->states.data + context->index;
175                 resize(context, state->sw, state->sh);
176                 move(context, state->sx, state->sy);
177                 move_pointer(context, state->px, state->py);
178                 context->index += state_size;
179
180                 test_client_send(client, "send-state\n");
181                 client->handle = handle_state;
182         } else {
183                 test_client_send(client, "bye\n");
184                 client->handle = NULL;
185         }
186 }
187
188 static void
189 handle_state(struct test_client *client)
190 {
191         struct context *context = client->data;
192         wl_fixed_t x, y;
193         int visible;
194
195         assert(sscanf(client->buf, "%d %d %d", &x, &y, &visible) == 3);
196
197         check_pointer(context, wl_fixed_to_int(x), wl_fixed_to_int(y));
198         check_visible(context, visible);
199
200         set_state(client);
201 }
202
203 static void
204 add_state(struct context *context, int px, int py, int sx, int sy,
205           int sw, int sh)
206 {
207         struct state *state = wl_array_add(&context->states,
208                                            sizeof(struct state));
209
210         assert(state);
211
212         state->px = px;
213         state->py = py;
214         state->sx = sx;
215         state->sy = sy;
216         state->sw = sw;
217         state->sh = sh;
218 }
219
220 static void
221 initialize_states(struct test_client *client)
222 {
223         struct context *context = client->data;
224         struct weston_surface *surface = context->surface;
225
226         int x = surface->geometry.x;
227         int y = surface->geometry.y;
228         int w = surface->geometry.width;
229         int h = surface->geometry.height;
230
231         wl_array_init(&context->states);
232
233         /* move pointer outside top left */
234         add_state(context, x - 1, y - 1, x, y, w, h);
235         /* move pointer on top left */
236         add_state(context, x, y, x, y, w, h);
237         /* move pointer outside bottom left */
238         add_state(context, x - 1, y + h, x, y, w, h);
239         /* move pointer on bottom left */
240         add_state(context, x, y + h - 1, x, y, w, h);
241         /* move pointer outside top right */
242         add_state(context, x + w, y - 1, x, y, w, h);
243         /* move pointer on top right */
244         add_state(context, x + w - 1, y, x, y, w, h);
245         /* move pointer outside bottom right */
246         add_state(context, x + w, y + h, x, y, w, h);
247         /* move pointer on bottom right */
248         add_state(context, x + w - 1, y + h - 1, x, y, w, h);
249
250         /* move pointer outside top center */
251         add_state(context, x + w/2, y - 1, x, y, w, h);
252         /* move pointer on top center */
253         add_state(context, x + w/2, y, x, y, w, h);
254         /* move pointer outside bottom center */
255         add_state(context, x + w/2, y + h, x, y, w, h);
256         /* move pointer on bottom center */
257         add_state(context, x + w/2, y + h - 1, x, y, w, h);
258         /* move pointer outside left center */
259         add_state(context, x - 1, y + h/2, x, y, w, h);
260         /* move pointer on left center */
261         add_state(context, x, y + h/2, x, y, w, h);
262         /* move pointer outside right center */
263         add_state(context, x + w, y + h/2, x, y, w, h);
264         /* move pointer on right center */
265         add_state(context, x + w - 1, y + h/2, x, y, w, h);
266
267         /* move pointer outside of client */
268         add_state(context, 50, 50, x, y, w, h);
269         /* move client center to pointer */
270         add_state(context, 50, 50, 0, 0, w, h);
271
272         /* not visible */
273         add_state(context, 0, 0, 0, -h, w, h);
274         /* visible */
275         add_state(context, 0, 0, 0, -h+1, w, h);
276         /* not visible */
277         add_state(context, 0, 0, 0, context->surface->output->height, w, h);
278         /* visible */
279         add_state(context, 0, 0, 0, context->surface->output->height - 1, w, h);
280         /* not visible */
281         add_state(context, 0, 0, -w, 0, w, h);
282         /* visible */
283         add_state(context, 0, 0, -w+1, 0, w, h);
284         /* not visible */
285         add_state(context, 0, 0, context->surface->output->width, 0, w, h);
286         /* visible */
287         add_state(context, 0, 0, context->surface->output->width - 1, 0, w, h);
288
289         set_state(client);
290 }
291
292 static void
293 handle_surface(struct test_client *client)
294 {
295         uint32_t id;
296         struct context *context = client->data;
297         struct wl_resource *resource;
298         struct wl_list *seat_list;
299
300         assert(sscanf(client->buf, "surface %u", &id) == 1);
301         fprintf(stderr, "server: got surface id %u\n", id);
302         resource = wl_client_get_object(client->client, id);
303         assert(resource);
304         assert(strcmp(resource->object.interface->name, "wl_surface") == 0);
305
306         context->surface = (struct weston_surface *) resource;
307         weston_surface_set_color(context->surface, 0.0, 0.0, 0.0, 1.0);
308
309         context->layer = malloc(sizeof *context->layer);
310         assert(context->layer);
311         weston_layer_init(context->layer,
312                           &client->compositor->cursor_layer.link);
313         wl_list_insert(&context->layer->surface_list,
314                        &context->surface->layer_link);
315
316         seat_list = &client->compositor->seat_list;
317         assert(wl_list_length(seat_list) == 1);
318         context->seat = container_of(seat_list->next, struct weston_seat, link);
319
320         client->compositor->focus = 1; /* Make it work even if pointer is
321                                         * outside X window. */
322
323         resize(context, 100, 100);
324         move(context, 100, 100);
325         move_pointer(context, 150, 150);
326
327         test_client_send(client, "send-state\n");
328         client->handle = initialize_states;
329 }
330
331 TEST(event_test)
332 {
333         struct context *context;
334         struct test_client *client;
335
336         client = test_client_launch(compositor, "test-client");
337         client->terminate = 1;
338
339         test_client_send(client, "create-surface\n");
340         client->handle = handle_surface;
341
342         context = calloc(1, sizeof *context);
343         assert(context);
344         client->data = context;
345 }