blob: 65a8880b24a08d937791a4af373618a17edaaf74 [file] [log] [blame]
U. Artie Eoff1ba9b382012-12-07 13:50:32 -08001/*
2 * Copyright © 2012 Intel Corporation
3 *
Bryce Harrington2cc92972015-06-11 15:39:40 -07004 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
U. Artie Eoff1ba9b382012-12-07 13:50:32 -080011 *
Bryce Harrington2cc92972015-06-11 15:39:40 -070012 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
U. Artie Eoff1ba9b382012-12-07 13:50:32 -080024 */
25
Bryce Harrington12cc4052014-11-19 17:18:33 -080026#include "config.h"
Kristian Høgsbergc7d2c4c2013-08-26 14:43:17 -070027
U. Artie Eoff1ba9b382012-12-07 13:50:32 -080028#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31#include <unistd.h>
Marek Chalupa4d06d462014-07-16 11:27:06 +020032#include <errno.h>
U. Artie Eoff1ba9b382012-12-07 13:50:32 -080033#include <sys/mman.h>
34
Jon Cruz4678bab2015-06-15 15:37:07 -070035#include "shared/os-compatibility.h"
U. Artie Eoff1ba9b382012-12-07 13:50:32 -080036#include "weston-test-client-helper.h"
37
Bryce Harrington273c2852014-12-15 15:51:25 -080038#define max(a, b) (((a) > (b)) ? (a) : (b))
39#define min(a, b) (((a) > (b)) ? (b) : (a))
40#define clip(x, a, b) min(max(x, a), b)
41
Bryce Harrington61a64362015-04-22 18:23:01 -070042void *
43fail_on_null(void *p)
44{
45 if (p == NULL) {
46 fprintf(stderr, "out of memory\n");
47 exit(EXIT_FAILURE);
48 }
49 return p;
50}
51
52
U. Artie Eoff1ba9b382012-12-07 13:50:32 -080053int
54surface_contains(struct surface *surface, int x, int y)
55{
56 /* test whether a global x,y point is contained in the surface */
57 int sx = surface->x;
58 int sy = surface->y;
59 int sw = surface->width;
60 int sh = surface->height;
61 return x >= sx && y >= sy && x < sx + sw && y < sy + sh;
62}
63
Kristian Høgsbergdb6dc7d2012-12-11 21:49:13 -050064static void
Pekka Paalanen8aaef7d2013-02-08 17:01:25 +020065frame_callback_handler(void *data, struct wl_callback *callback, uint32_t time)
Kristian Høgsbergdb6dc7d2012-12-11 21:49:13 -050066{
67 int *done = data;
68
69 *done = 1;
70
71 wl_callback_destroy(callback);
72}
73
74static const struct wl_callback_listener frame_listener = {
Pekka Paalanen8aaef7d2013-02-08 17:01:25 +020075 frame_callback_handler
Kristian Høgsbergdb6dc7d2012-12-11 21:49:13 -050076};
77
Pekka Paalanen8aaef7d2013-02-08 17:01:25 +020078struct wl_callback *
79frame_callback_set(struct wl_surface *surface, int *done)
80{
81 struct wl_callback *callback;
82
83 *done = 0;
84 callback = wl_surface_frame(surface);
85 wl_callback_add_listener(callback, &frame_listener, done);
86
87 return callback;
88}
89
Marek Chalupa1740aa82014-07-16 11:32:50 +020090int
91frame_callback_wait_nofail(struct client *client, int *done)
Pekka Paalanen8aaef7d2013-02-08 17:01:25 +020092{
93 while (!*done) {
Marek Chalupa1740aa82014-07-16 11:32:50 +020094 if (wl_display_dispatch(client->wl_display) < 0)
95 return 0;
Pekka Paalanen8aaef7d2013-02-08 17:01:25 +020096 }
Marek Chalupa1740aa82014-07-16 11:32:50 +020097
98 return 1;
Pekka Paalanen8aaef7d2013-02-08 17:01:25 +020099}
100
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800101void
102move_client(struct client *client, int x, int y)
103{
104 struct surface *surface = client->surface;
Kristian Høgsbergdb6dc7d2012-12-11 21:49:13 -0500105 int done;
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800106
107 client->surface->x = x;
108 client->surface->y = y;
Derek Foremanf6a65922015-02-24 09:32:14 -0600109 weston_test_move_surface(client->test->weston_test, surface->wl_surface,
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800110 surface->x, surface->y);
Bryce Harringtoncb50ed22014-12-10 18:33:47 -0800111 /* The attach here is necessary because commit() will call configure
Giulio Camuffo82cb5052013-02-28 18:44:54 +0100112 * only on surfaces newly attached, and the one that sets the surface
113 * position is the configure. */
114 wl_surface_attach(surface->wl_surface, surface->wl_buffer, 0, 0);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800115 wl_surface_damage(surface->wl_surface, 0, 0, surface->width,
116 surface->height);
Kristian Høgsbergdb6dc7d2012-12-11 21:49:13 -0500117
Pekka Paalanen8aaef7d2013-02-08 17:01:25 +0200118 frame_callback_set(surface->wl_surface, &done);
Kristian Høgsbergdb6dc7d2012-12-11 21:49:13 -0500119
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800120 wl_surface_commit(surface->wl_surface);
121
Pekka Paalanen8aaef7d2013-02-08 17:01:25 +0200122 frame_callback_wait(client, &done);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800123}
124
Neil Roberts40c0c3f2013-10-29 20:13:45 +0000125int
126get_n_egl_buffers(struct client *client)
127{
128 client->test->n_egl_buffers = -1;
129
Derek Foremanf6a65922015-02-24 09:32:14 -0600130 weston_test_get_n_egl_buffers(client->test->weston_test);
Neil Roberts40c0c3f2013-10-29 20:13:45 +0000131 wl_display_roundtrip(client->wl_display);
132
133 return client->test->n_egl_buffers;
134}
135
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800136static void
137pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
138 uint32_t serial, struct wl_surface *wl_surface,
139 wl_fixed_t x, wl_fixed_t y)
140{
141 struct pointer *pointer = data;
142
143 pointer->focus = wl_surface_get_user_data(wl_surface);
144 pointer->x = wl_fixed_to_int(x);
145 pointer->y = wl_fixed_to_int(y);
146
147 fprintf(stderr, "test-client: got pointer enter %d %d, surface %p\n",
148 pointer->x, pointer->y, pointer->focus);
149}
150
151static void
152pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
153 uint32_t serial, struct wl_surface *wl_surface)
154{
155 struct pointer *pointer = data;
156
157 pointer->focus = NULL;
158
159 fprintf(stderr, "test-client: got pointer leave, surface %p\n",
160 wl_surface_get_user_data(wl_surface));
161}
162
163static void
164pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
165 uint32_t time, wl_fixed_t x, wl_fixed_t y)
166{
167 struct pointer *pointer = data;
168
169 pointer->x = wl_fixed_to_int(x);
170 pointer->y = wl_fixed_to_int(y);
171
172 fprintf(stderr, "test-client: got pointer motion %d %d\n",
173 pointer->x, pointer->y);
174}
175
176static void
177pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
178 uint32_t serial, uint32_t time, uint32_t button,
179 uint32_t state)
180{
181 struct pointer *pointer = data;
182
183 pointer->button = button;
184 pointer->state = state;
185
186 fprintf(stderr, "test-client: got pointer button %u %u\n",
187 button, state);
188}
189
190static void
191pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
192 uint32_t time, uint32_t axis, wl_fixed_t value)
193{
Kristian Høgsberg4c8ce202013-10-09 14:23:00 -0700194 fprintf(stderr, "test-client: got pointer axis %u %f\n",
195 axis, wl_fixed_to_double(value));
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800196}
197
198static const struct wl_pointer_listener pointer_listener = {
199 pointer_handle_enter,
200 pointer_handle_leave,
201 pointer_handle_motion,
202 pointer_handle_button,
203 pointer_handle_axis,
204};
205
206static void
207keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
208 uint32_t format, int fd, uint32_t size)
209{
210 close(fd);
211
212 fprintf(stderr, "test-client: got keyboard keymap\n");
213}
214
215static void
216keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
217 uint32_t serial, struct wl_surface *wl_surface,
218 struct wl_array *keys)
219{
220 struct keyboard *keyboard = data;
221
222 keyboard->focus = wl_surface_get_user_data(wl_surface);
223
224 fprintf(stderr, "test-client: got keyboard enter, surface %p\n",
225 keyboard->focus);
226}
227
228static void
229keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
230 uint32_t serial, struct wl_surface *wl_surface)
231{
232 struct keyboard *keyboard = data;
233
234 keyboard->focus = NULL;
235
236 fprintf(stderr, "test-client: got keyboard leave, surface %p\n",
237 wl_surface_get_user_data(wl_surface));
238}
239
240static void
241keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
242 uint32_t serial, uint32_t time, uint32_t key,
243 uint32_t state)
244{
245 struct keyboard *keyboard = data;
246
247 keyboard->key = key;
248 keyboard->state = state;
249
250 fprintf(stderr, "test-client: got keyboard key %u %u\n", key, state);
251}
252
253static void
254keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
255 uint32_t serial, uint32_t mods_depressed,
256 uint32_t mods_latched, uint32_t mods_locked,
257 uint32_t group)
258{
259 struct keyboard *keyboard = data;
260
261 keyboard->mods_depressed = mods_depressed;
262 keyboard->mods_latched = mods_latched;
263 keyboard->mods_locked = mods_locked;
264 keyboard->group = group;
265
266 fprintf(stderr, "test-client: got keyboard modifiers %u %u %u %u\n",
267 mods_depressed, mods_latched, mods_locked, group);
268}
269
Marek Chalupa643d85f2015-03-30 06:37:56 -0400270static void
271keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
272 int32_t rate, int32_t delay)
273{
274 struct keyboard *keyboard = data;
275
276 keyboard->repeat_info.rate = rate;
277 keyboard->repeat_info.delay = delay;
278
279 fprintf(stderr, "test-client: got keyboard repeat_info %d %d\n",
280 rate, delay);
281}
282
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800283static const struct wl_keyboard_listener keyboard_listener = {
284 keyboard_handle_keymap,
285 keyboard_handle_enter,
286 keyboard_handle_leave,
287 keyboard_handle_key,
288 keyboard_handle_modifiers,
Marek Chalupa643d85f2015-03-30 06:37:56 -0400289 keyboard_handle_repeat_info,
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800290};
291
292static void
Marek Chalupa8a5523c2015-03-30 09:20:07 -0400293touch_handle_down(void *data, struct wl_touch *wl_touch,
294 uint32_t serial, uint32_t time, struct wl_surface *surface,
295 int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
296{
297 struct touch *touch = data;
298
299 touch->down_x = wl_fixed_to_int(x_w);
300 touch->down_y = wl_fixed_to_int(y_w);
301 touch->id = id;
302
303 fprintf(stderr, "test-client: got touch down %d %d, surf: %p, id: %d\n",
304 touch->down_x, touch->down_y, surface, id);
305}
306
307static void
308touch_handle_up(void *data, struct wl_touch *wl_touch,
309 uint32_t serial, uint32_t time, int32_t id)
310{
311 struct touch *touch = data;
312 touch->up_id = id;
313
314 fprintf(stderr, "test-client: got touch up, id: %d\n", id);
315}
316
317static void
318touch_handle_motion(void *data, struct wl_touch *wl_touch,
319 uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
320{
321 struct touch *touch = data;
322 touch->x = wl_fixed_to_int(x_w);
323 touch->y = wl_fixed_to_int(y_w);
324
325 fprintf(stderr, "test-client: got touch motion, %d %d, id: %d\n",
326 touch->x, touch->y, id);
327}
328
329static void
330touch_handle_frame(void *data, struct wl_touch *wl_touch)
331{
332 struct touch *touch = data;
333
334 ++touch->frame_no;
335
336 fprintf(stderr, "test-client: got touch frame (%d)\n", touch->frame_no);
337}
338
339static void
340touch_handle_cancel(void *data, struct wl_touch *wl_touch)
341{
342 struct touch *touch = data;
343
344 ++touch->cancel_no;
345
346 fprintf(stderr, "test-client: got touch cancel (%d)\n", touch->cancel_no);
347}
348
349static const struct wl_touch_listener touch_listener = {
350 touch_handle_down,
351 touch_handle_up,
352 touch_handle_motion,
353 touch_handle_frame,
354 touch_handle_cancel,
355};
356
357static void
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800358surface_enter(void *data,
359 struct wl_surface *wl_surface, struct wl_output *output)
360{
361 struct surface *surface = data;
362
363 surface->output = wl_output_get_user_data(output);
364
365 fprintf(stderr, "test-client: got surface enter output %p\n",
366 surface->output);
367}
368
369static void
370surface_leave(void *data,
371 struct wl_surface *wl_surface, struct wl_output *output)
372{
373 struct surface *surface = data;
374
375 surface->output = NULL;
376
377 fprintf(stderr, "test-client: got surface leave output %p\n",
378 wl_output_get_user_data(output));
379}
380
381static const struct wl_surface_listener surface_listener = {
382 surface_enter,
383 surface_leave
384};
385
Pekka Paalanen32ac9b92013-02-08 17:01:26 +0200386struct wl_buffer *
387create_shm_buffer(struct client *client, int width, int height, void **pixels)
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800388{
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800389 struct wl_shm *shm = client->wl_shm;
Pekka Paalanen32ac9b92013-02-08 17:01:26 +0200390 int stride = width * 4;
391 int size = stride * height;
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800392 struct wl_shm_pool *pool;
Pekka Paalanen32ac9b92013-02-08 17:01:26 +0200393 struct wl_buffer *buffer;
394 int fd;
395 void *data;
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800396
397 fd = os_create_anonymous_file(size);
398 assert(fd >= 0);
399
Pekka Paalanen32ac9b92013-02-08 17:01:26 +0200400 data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
401 if (data == MAP_FAILED) {
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800402 close(fd);
Pekka Paalanen32ac9b92013-02-08 17:01:26 +0200403 assert(data != MAP_FAILED);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800404 }
405
406 pool = wl_shm_create_pool(shm, fd, size);
Pekka Paalanen32ac9b92013-02-08 17:01:26 +0200407 buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
408 WL_SHM_FORMAT_ARGB8888);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800409 wl_shm_pool_destroy(pool);
410
411 close(fd);
Pekka Paalanen32ac9b92013-02-08 17:01:26 +0200412
413 if (pixels)
414 *pixels = data;
415
416 return buffer;
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800417}
418
419static void
420shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
421{
422 struct client *client = data;
423
424 if (format == WL_SHM_FORMAT_ARGB8888)
425 client->has_argb = 1;
426}
427
428struct wl_shm_listener shm_listener = {
429 shm_format
430};
431
432static void
Derek Foremanf6a65922015-02-24 09:32:14 -0600433test_handle_pointer_position(void *data, struct weston_test *weston_test,
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800434 wl_fixed_t x, wl_fixed_t y)
435{
436 struct test *test = data;
437 test->pointer_x = wl_fixed_to_int(x);
438 test->pointer_y = wl_fixed_to_int(y);
439
440 fprintf(stderr, "test-client: got global pointer %d %d\n",
441 test->pointer_x, test->pointer_y);
442}
443
Neil Roberts40c0c3f2013-10-29 20:13:45 +0000444static void
Derek Foremanf6a65922015-02-24 09:32:14 -0600445test_handle_n_egl_buffers(void *data, struct weston_test *weston_test, uint32_t n)
Neil Roberts40c0c3f2013-10-29 20:13:45 +0000446{
447 struct test *test = data;
448
449 test->n_egl_buffers = n;
450}
451
Bryce Harrington692275f2015-04-23 16:33:49 -0700452static void
453test_handle_capture_screenshot_done(void *data, struct weston_test *weston_test)
454{
455 struct test *test = data;
456
457 printf("Screenshot has been captured\n");
458 test->buffer_copy_done = 1;
459}
460
Derek Foremanf6a65922015-02-24 09:32:14 -0600461static const struct weston_test_listener test_listener = {
Neil Roberts40c0c3f2013-10-29 20:13:45 +0000462 test_handle_pointer_position,
463 test_handle_n_egl_buffers,
Bryce Harrington692275f2015-04-23 16:33:49 -0700464 test_handle_capture_screenshot_done,
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800465};
466
467static void
Marek Chalupac3c3fc42015-03-30 09:17:40 -0400468input_update_devices(struct input *input)
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800469{
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800470 struct pointer *pointer;
471 struct keyboard *keyboard;
Marek Chalupa8a5523c2015-03-30 09:20:07 -0400472 struct touch *touch;
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800473
Marek Chalupac3c3fc42015-03-30 09:17:40 -0400474 struct wl_seat *seat = input->wl_seat;
475 enum wl_seat_capability caps = input->caps;
476
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800477 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
Kristian Høgsbergc1b244f2013-10-09 14:01:23 -0700478 pointer = xzalloc(sizeof *pointer);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800479 pointer->wl_pointer = wl_seat_get_pointer(seat);
480 wl_pointer_set_user_data(pointer->wl_pointer, pointer);
481 wl_pointer_add_listener(pointer->wl_pointer, &pointer_listener,
482 pointer);
483 input->pointer = pointer;
484 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
485 wl_pointer_destroy(input->pointer->wl_pointer);
486 free(input->pointer);
487 input->pointer = NULL;
488 }
489
490 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
Kristian Høgsbergc1b244f2013-10-09 14:01:23 -0700491 keyboard = xzalloc(sizeof *keyboard);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800492 keyboard->wl_keyboard = wl_seat_get_keyboard(seat);
493 wl_keyboard_set_user_data(keyboard->wl_keyboard, keyboard);
494 wl_keyboard_add_listener(keyboard->wl_keyboard, &keyboard_listener,
495 keyboard);
496 input->keyboard = keyboard;
497 } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
498 wl_keyboard_destroy(input->keyboard->wl_keyboard);
499 free(input->keyboard);
500 input->keyboard = NULL;
501 }
Marek Chalupa8a5523c2015-03-30 09:20:07 -0400502
503 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
504 touch = xzalloc(sizeof *touch);
505 touch->wl_touch = wl_seat_get_touch(seat);
506 wl_touch_set_user_data(touch->wl_touch, touch);
507 wl_touch_add_listener(touch->wl_touch, &touch_listener,
508 touch);
509 input->touch = touch;
510 } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
511 wl_touch_destroy(input->touch->wl_touch);
512 free(input->touch);
513 input->touch = NULL;
514 }
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800515}
516
Marek Chalupa643d85f2015-03-30 06:37:56 -0400517static void
Marek Chalupac3c3fc42015-03-30 09:17:40 -0400518seat_handle_capabilities(void *data, struct wl_seat *seat,
519 enum wl_seat_capability caps)
520{
521 struct input *input = data;
522
523 input->caps = caps;
524
525 /* we will create/update the devices only with the right (test) seat.
526 * If we haven't discovered which seat is the test seat, just
527 * store capabilities and bail out */
Dawid Gajownik74a635b2015-08-06 17:12:19 -0300528 if (input->seat_name && strcmp(input->seat_name, "test-seat") == 0)
Marek Chalupac3c3fc42015-03-30 09:17:40 -0400529 input_update_devices(input);
530
531 fprintf(stderr, "test-client: got seat %p capabilities: %x\n",
532 input, caps);
533}
534
535static void
Marek Chalupa643d85f2015-03-30 06:37:56 -0400536seat_handle_name(void *data, struct wl_seat *seat, const char *name)
537{
538 struct input *input = data;
539
540 input->seat_name = strdup(name);
541 assert(input->seat_name && "No memory");
542
Marek Chalupac3c3fc42015-03-30 09:17:40 -0400543 fprintf(stderr, "test-client: got seat %p name: \'%s\'\n",
544 input, name);
Marek Chalupa643d85f2015-03-30 06:37:56 -0400545}
546
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800547static const struct wl_seat_listener seat_listener = {
548 seat_handle_capabilities,
Marek Chalupa643d85f2015-03-30 06:37:56 -0400549 seat_handle_name,
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800550};
551
552static void
553output_handle_geometry(void *data,
554 struct wl_output *wl_output,
555 int x, int y,
556 int physical_width,
557 int physical_height,
558 int subpixel,
559 const char *make,
560 const char *model,
561 int32_t transform)
562{
563 struct output *output = data;
564
565 output->x = x;
566 output->y = y;
567}
568
569static void
570output_handle_mode(void *data,
571 struct wl_output *wl_output,
572 uint32_t flags,
573 int width,
574 int height,
575 int refresh)
576{
577 struct output *output = data;
578
579 if (flags & WL_OUTPUT_MODE_CURRENT) {
580 output->width = width;
581 output->height = height;
582 }
583}
584
Marek Chalupa643d85f2015-03-30 06:37:56 -0400585static void
586output_handle_scale(void *data,
587 struct wl_output *wl_output,
588 int scale)
589{
590 struct output *output = data;
591
592 output->scale = scale;
593}
594
595static void
596output_handle_done(void *data,
597 struct wl_output *wl_output)
598{
599 struct output *output = data;
600
601 output->initialized = 1;
602}
603
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800604static const struct wl_output_listener output_listener = {
605 output_handle_geometry,
Marek Chalupa643d85f2015-03-30 06:37:56 -0400606 output_handle_mode,
607 output_handle_done,
608 output_handle_scale,
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800609};
610
611static void
612handle_global(void *data, struct wl_registry *registry,
613 uint32_t id, const char *interface, uint32_t version)
614{
615 struct client *client = data;
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800616 struct output *output;
617 struct test *test;
Kristian Høgsberg1cb3df42012-12-11 23:03:56 -0500618 struct global *global;
Marek Chalupac3c3fc42015-03-30 09:17:40 -0400619 struct input *input;
Kristian Høgsberg1cb3df42012-12-11 23:03:56 -0500620
Kristian Høgsbergc1b244f2013-10-09 14:01:23 -0700621 global = xzalloc(sizeof *global);
Kristian Høgsberg1cb3df42012-12-11 23:03:56 -0500622 global->name = id;
623 global->interface = strdup(interface);
624 assert(interface);
625 global->version = version;
626 wl_list_insert(client->global_list.prev, &global->link);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800627
628 if (strcmp(interface, "wl_compositor") == 0) {
629 client->wl_compositor =
630 wl_registry_bind(registry, id,
Marek Chalupa643d85f2015-03-30 06:37:56 -0400631 &wl_compositor_interface, version);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800632 } else if (strcmp(interface, "wl_seat") == 0) {
Kristian Høgsbergc1b244f2013-10-09 14:01:23 -0700633 input = xzalloc(sizeof *input);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800634 input->wl_seat =
635 wl_registry_bind(registry, id,
Marek Chalupa643d85f2015-03-30 06:37:56 -0400636 &wl_seat_interface, version);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800637 wl_seat_add_listener(input->wl_seat, &seat_listener, input);
Marek Chalupac3c3fc42015-03-30 09:17:40 -0400638 wl_list_insert(&client->inputs, &input->link);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800639 } else if (strcmp(interface, "wl_shm") == 0) {
640 client->wl_shm =
641 wl_registry_bind(registry, id,
Marek Chalupa643d85f2015-03-30 06:37:56 -0400642 &wl_shm_interface, version);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800643 wl_shm_add_listener(client->wl_shm, &shm_listener, client);
644 } else if (strcmp(interface, "wl_output") == 0) {
Kristian Høgsbergc1b244f2013-10-09 14:01:23 -0700645 output = xzalloc(sizeof *output);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800646 output->wl_output =
647 wl_registry_bind(registry, id,
Marek Chalupa643d85f2015-03-30 06:37:56 -0400648 &wl_output_interface, version);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800649 wl_output_add_listener(output->wl_output,
650 &output_listener, output);
651 client->output = output;
Derek Foremanf6a65922015-02-24 09:32:14 -0600652 } else if (strcmp(interface, "weston_test") == 0) {
Kristian Høgsbergc1b244f2013-10-09 14:01:23 -0700653 test = xzalloc(sizeof *test);
Derek Foremanf6a65922015-02-24 09:32:14 -0600654 test->weston_test =
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800655 wl_registry_bind(registry, id,
Marek Chalupa643d85f2015-03-30 06:37:56 -0400656 &weston_test_interface, version);
Derek Foremanf6a65922015-02-24 09:32:14 -0600657 weston_test_add_listener(test->weston_test, &test_listener, test);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800658 client->test = test;
Derek Foreman9bb13392015-01-23 12:12:36 -0600659 } else if (strcmp(interface, "wl_drm") == 0) {
660 client->has_wl_drm = true;
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800661 }
662}
663
664static const struct wl_registry_listener registry_listener = {
665 handle_global
666};
667
Kristian Høgsberg42284f52014-01-01 17:38:04 -0800668void
669skip(const char *fmt, ...)
670{
671 va_list argp;
672
673 va_start(argp, fmt);
674 vfprintf(stderr, fmt, argp);
675 va_end(argp);
676
Emilio Pozuelo Monfortdae8a4b2014-02-07 09:34:48 +0100677 /* automake tests uses exit code 77. weston-test-runner will see
678 * this and use it, and then weston-test's sigchld handler (in the
679 * weston process) will use that as an exit status, which is what
680 * automake will see in the end. */
681 exit(77);
Kristian Høgsberg42284f52014-01-01 17:38:04 -0800682}
683
Marek Chalupa4d06d462014-07-16 11:27:06 +0200684void
685expect_protocol_error(struct client *client,
686 const struct wl_interface *intf,
687 uint32_t code)
688{
689 int err;
690 uint32_t errcode, failed = 0;
691 const struct wl_interface *interface;
692 unsigned int id;
693
694 /* if the error has not come yet, make it happen */
695 wl_display_roundtrip(client->wl_display);
696
697 err = wl_display_get_error(client->wl_display);
698
699 assert(err && "Expected protocol error but nothing came");
700 assert(err == EPROTO && "Expected protocol error but got local error");
701
702 errcode = wl_display_get_protocol_error(client->wl_display,
703 &interface, &id);
704
705 /* check error */
706 if (errcode != code) {
707 fprintf(stderr, "Should get error code %d but got %d\n",
708 code, errcode);
709 failed = 1;
710 }
711
712 /* this should be definitely set */
713 assert(interface);
714
715 if (strcmp(intf->name, interface->name) != 0) {
716 fprintf(stderr, "Should get interface '%s' but got '%s'\n",
717 intf->name, interface->name);
718 failed = 1;
719 }
720
721 if (failed) {
722 fprintf(stderr, "Expected other protocol error\n");
723 abort();
724 }
725
726 /* all OK */
727 fprintf(stderr, "Got expected protocol error on '%s' (object id: %d) "
728 "with code %d\n", interface->name, id, errcode);
729}
730
Pekka Paalanen07921d72012-12-12 14:26:40 +0200731static void
732log_handler(const char *fmt, va_list args)
733{
734 fprintf(stderr, "libwayland: ");
735 vfprintf(stderr, fmt, args);
736}
737
Marek Chalupac3c3fc42015-03-30 09:17:40 -0400738static void
739input_destroy(struct input *inp)
740{
741 wl_list_remove(&inp->link);
742 wl_seat_destroy(inp->wl_seat);
743 free(inp);
744}
745
746/* find the test-seat and set it in client.
747 * Destroy other inputs */
748static void
749client_set_input(struct client *cl)
750{
751 struct input *inp, *inptmp;
752 wl_list_for_each_safe(inp, inptmp, &cl->inputs, link) {
753 assert(inp->seat_name && "BUG: input with no name");
754 if (strcmp(inp->seat_name, "test-seat") == 0) {
755 cl->input = inp;
756 input_update_devices(inp);
757 } else {
758 input_destroy(inp);
759 }
760 }
761
762 /* we keep only one input */
763 assert(wl_list_length(&cl->inputs) == 1);
764}
765
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800766struct client *
Pekka Paalanen1ffd4612015-03-26 12:49:35 +0200767create_client(void)
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800768{
769 struct client *client;
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800770
Pekka Paalanen07921d72012-12-12 14:26:40 +0200771 wl_log_set_handler_client(log_handler);
772
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800773 /* connect to display */
Kristian Høgsbergc1b244f2013-10-09 14:01:23 -0700774 client = xzalloc(sizeof *client);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800775 client->wl_display = wl_display_connect(NULL);
776 assert(client->wl_display);
Kristian Høgsberg1cb3df42012-12-11 23:03:56 -0500777 wl_list_init(&client->global_list);
Marek Chalupac3c3fc42015-03-30 09:17:40 -0400778 wl_list_init(&client->inputs);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800779
780 /* setup registry so we can bind to interfaces */
781 client->wl_registry = wl_display_get_registry(client->wl_display);
Pekka Paalanen1ffd4612015-03-26 12:49:35 +0200782 wl_registry_add_listener(client->wl_registry, &registry_listener,
783 client);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800784
Marek Chalupac3c3fc42015-03-30 09:17:40 -0400785 /* this roundtrip makes sure we have all globals and we bound to them */
786 client_roundtrip(client);
787 /* this roundtrip makes sure we got all wl_shm.format and wl_seat.*
788 * events */
789 client_roundtrip(client);
790
791 /* find the right input for us */
792 client_set_input(client);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800793
794 /* must have WL_SHM_FORMAT_ARGB32 */
795 assert(client->has_argb);
796
Derek Foremanf6a65922015-02-24 09:32:14 -0600797 /* must have weston_test interface */
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800798 assert(client->test);
799
800 /* must have an output */
801 assert(client->output);
802
Marek Chalupa643d85f2015-03-30 06:37:56 -0400803 /* the output must be initialized */
804 assert(client->output->initialized == 1);
805
Marek Chalupac3c3fc42015-03-30 09:17:40 -0400806 /* must have seat set */
807 assert(client->input);
808
Pekka Paalanen1ffd4612015-03-26 12:49:35 +0200809 return client;
810}
811
812struct client *
Pekka Paalanen4ac06ff2015-03-26 12:56:10 +0200813create_client_and_test_surface(int x, int y, int width, int height)
Pekka Paalanen1ffd4612015-03-26 12:49:35 +0200814{
815 struct client *client;
816 struct surface *surface;
817
818 client = create_client();
819
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800820 /* initialize the client surface */
Kristian Høgsbergc1b244f2013-10-09 14:01:23 -0700821 surface = xzalloc(sizeof *surface);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800822 surface->wl_surface =
823 wl_compositor_create_surface(client->wl_compositor);
824 assert(surface->wl_surface);
825
826 wl_surface_add_listener(surface->wl_surface, &surface_listener,
827 surface);
828
829 client->surface = surface;
830 wl_surface_set_user_data(surface->wl_surface, surface);
831
832 surface->width = width;
833 surface->height = height;
Pekka Paalanen32ac9b92013-02-08 17:01:26 +0200834 surface->wl_buffer = create_shm_buffer(client, width, height,
835 &surface->data);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800836
837 memset(surface->data, 64, width * height * 4);
U. Artie Eoff1ba9b382012-12-07 13:50:32 -0800838
839 move_client(client, x, y);
840
841 return client;
842}
Bryce Harringtonc1a1d6c2014-12-09 14:46:36 -0800843
844static const char*
Bryce Harrington3835d052015-05-18 17:47:13 -0700845output_path(void)
846{
Bryce Harringtonc1a1d6c2014-12-09 14:46:36 -0800847 char *path = getenv("WESTON_TEST_OUTPUT_PATH");
848
849 if (!path)
850 return ".";
851 return path;
852 }
853
854char*
Bryce Harrington3835d052015-05-18 17:47:13 -0700855screenshot_output_filename(const char *basename, uint32_t seq)
856{
Bryce Harringtonc1a1d6c2014-12-09 14:46:36 -0800857 char *filename;
858
859 if (asprintf(&filename, "%s/%s-%02d.png",
860 output_path(), basename, seq) < 0)
861 return NULL;
862 return filename;
863}
864
865static const char*
Bryce Harrington3835d052015-05-18 17:47:13 -0700866reference_path(void)
867{
Bryce Harringtonc1a1d6c2014-12-09 14:46:36 -0800868 char *path = getenv("WESTON_TEST_REFERENCE_PATH");
869
870 if (!path)
871 return "./tests/reference";
872 return path;
873}
874
875char*
Bryce Harrington3835d052015-05-18 17:47:13 -0700876screenshot_reference_filename(const char *basename, uint32_t seq)
877{
Bryce Harringtonc1a1d6c2014-12-09 14:46:36 -0800878 char *filename;
879
880 if (asprintf(&filename, "%s/%s-%02d.png",
881 reference_path(), basename, seq) < 0)
882 return NULL;
883 return filename;
884}
Bryce Harrington273c2852014-12-15 15:51:25 -0800885
886/**
Bryce Harrington39a5be22015-05-14 14:36:18 -0700887 * check_surfaces_geometry() - verifies two surfaces are same size
888 *
889 * @returns true if surfaces have the same width and height, or false
890 * if not, or if there is no actual data.
891 */
892bool
893check_surfaces_geometry(const struct surface *a, const struct surface *b)
894{
895 if (a == NULL || b == NULL) {
896 printf("Undefined surfaces\n");
897 return false;
898 }
899 else if (a->data == NULL || b->data == NULL) {
900 printf("Undefined data\n");
901 return false;
902 }
903 else if (a->width != b->width || a->height != b->height) {
904 printf("Mismatched dimensions: %d,%d != %d,%d\n",
905 a->width, a->height, b->width, b->height);
906 return false;
907 }
908 return true;
909}
910
911/**
Bryce Harrington273c2852014-12-15 15:51:25 -0800912 * check_surfaces_equal() - tests if two surfaces are pixel-identical
913 *
914 * Returns true if surface buffers have all the same byte values,
915 * false if the surfaces don't match or can't be compared due to
916 * different dimensions.
917 */
918bool
919check_surfaces_equal(const struct surface *a, const struct surface *b)
920{
921 int bpp = 4; /* Assumes ARGB */
922
Bryce Harrington39a5be22015-05-14 14:36:18 -0700923 if (!check_surfaces_geometry(a, b))
Bryce Harrington273c2852014-12-15 15:51:25 -0800924 return false;
925
926 return (memcmp(a->data, b->data, bpp * a->width * a->height) == 0);
927}
928
929/**
930 * check_surfaces_match_in_clip() - tests if a given region within two
931 * surfaces are pixel-identical.
932 *
933 * Returns true if the two surfaces have the same byte values within the
934 * given clipping region, or false if they don't match or the surfaces
935 * can't be compared.
936 */
937bool
938check_surfaces_match_in_clip(const struct surface *a, const struct surface *b, const struct rectangle *clip_rect)
939{
940 int i, j;
941 int x0, y0, x1, y1;
942 void *p, *q;
943 int bpp = 4; /* Assumes ARGB */
944
Bryce Harrington39a5be22015-05-14 14:36:18 -0700945 if (!check_surfaces_geometry(a, b) || clip_rect == NULL)
Bryce Harrington273c2852014-12-15 15:51:25 -0800946 return false;
947
Bryce Harrington273c2852014-12-15 15:51:25 -0800948 if (clip_rect->x > a->width || clip_rect->y > a->height) {
949 printf("Clip outside image boundaries\n");
950 return true;
951 }
952
953 x0 = max(0, clip_rect->x);
954 y0 = max(0, clip_rect->y);
955 x1 = min(a->width, clip_rect->x + clip_rect->width);
956 y1 = min(a->height, clip_rect->y + clip_rect->height);
957
958 if (x0 == x1 || y0 == y1) {
959 printf("Degenerate comparison\n");
960 return true;
961 }
962
963 printf("Bytewise comparison inside clip\n");
964 for (i=y0; i<y1; i++) {
965 p = a->data + i * a->width * bpp + x0 * bpp;
966 q = b->data + i * b->width * bpp + x0 * bpp;
967 if (memcmp(p, q, (x1-x0)*bpp) != 0) {
968 /* Dump the bad row */
969 printf("Mismatched image on row %d\n", i);
970 for (j=0; j<(x1-x0)*bpp; j++) {
971 char a_char = *((char*)(p+j*bpp));
972 char b_char = *((char*)(q+j*bpp));
973 printf("%d,%d: %8x %8x %s\n", i, j, a_char, b_char,
974 (a_char != b_char)? " <---": "");
975 }
976 return false;
977 }
978 }
979
980 return true;
981}