tests: make create_shm_buffer() static
[platform/upstream/weston.git] / tests / weston-test-client-helper.c
1 /*
2  * Copyright © 2012 Intel Corporation
3  *
4  * 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:
11  *
12  * 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.
24  */
25
26 #include "config.h"
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <sys/mman.h>
34 #include <cairo.h>
35
36 #include "shared/os-compatibility.h"
37 #include "shared/xalloc.h"
38 #include "shared/zalloc.h"
39 #include "weston-test-client-helper.h"
40
41 #define max(a, b) (((a) > (b)) ? (a) : (b))
42 #define min(a, b) (((a) > (b)) ? (b) : (a))
43 #define clip(x, a, b)  min(max(x, a), b)
44
45 int
46 surface_contains(struct surface *surface, int x, int y)
47 {
48         /* test whether a global x,y point is contained in the surface */
49         int sx = surface->x;
50         int sy = surface->y;
51         int sw = surface->width;
52         int sh = surface->height;
53         return x >= sx && y >= sy && x < sx + sw && y < sy + sh;
54 }
55
56 static void
57 frame_callback_handler(void *data, struct wl_callback *callback, uint32_t time)
58 {
59         int *done = data;
60
61         *done = 1;
62
63         wl_callback_destroy(callback);
64 }
65
66 static const struct wl_callback_listener frame_listener = {
67         frame_callback_handler
68 };
69
70 struct wl_callback *
71 frame_callback_set(struct wl_surface *surface, int *done)
72 {
73         struct wl_callback *callback;
74
75         *done = 0;
76         callback = wl_surface_frame(surface);
77         wl_callback_add_listener(callback, &frame_listener, done);
78
79         return callback;
80 }
81
82 int
83 frame_callback_wait_nofail(struct client *client, int *done)
84 {
85         while (!*done) {
86                 if (wl_display_dispatch(client->wl_display) < 0)
87                         return 0;
88         }
89
90         return 1;
91 }
92
93 void
94 move_client(struct client *client, int x, int y)
95 {
96         struct surface *surface = client->surface;
97         int done;
98
99         client->surface->x = x;
100         client->surface->y = y;
101         weston_test_move_surface(client->test->weston_test, surface->wl_surface,
102                              surface->x, surface->y);
103         /* The attach here is necessary because commit() will call configure
104          * only on surfaces newly attached, and the one that sets the surface
105          * position is the configure. */
106         wl_surface_attach(surface->wl_surface, surface->buffer->proxy, 0, 0);
107         wl_surface_damage(surface->wl_surface, 0, 0, surface->width,
108                           surface->height);
109
110         frame_callback_set(surface->wl_surface, &done);
111
112         wl_surface_commit(surface->wl_surface);
113
114         frame_callback_wait(client, &done);
115 }
116
117 int
118 get_n_egl_buffers(struct client *client)
119 {
120         client->test->n_egl_buffers = -1;
121
122         weston_test_get_n_egl_buffers(client->test->weston_test);
123         wl_display_roundtrip(client->wl_display);
124
125         return client->test->n_egl_buffers;
126 }
127
128 static void
129 pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
130                      uint32_t serial, struct wl_surface *wl_surface,
131                      wl_fixed_t x, wl_fixed_t y)
132 {
133         struct pointer *pointer = data;
134
135         if (wl_surface)
136                 pointer->focus = wl_surface_get_user_data(wl_surface);
137         else
138                 pointer->focus = NULL;
139
140         pointer->x = wl_fixed_to_int(x);
141         pointer->y = wl_fixed_to_int(y);
142
143         fprintf(stderr, "test-client: got pointer enter %d %d, surface %p\n",
144                 pointer->x, pointer->y, pointer->focus);
145 }
146
147 static void
148 pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
149                      uint32_t serial, struct wl_surface *wl_surface)
150 {
151         struct pointer *pointer = data;
152
153         pointer->focus = NULL;
154
155         fprintf(stderr, "test-client: got pointer leave, surface %p\n",
156                 wl_surface ? wl_surface_get_user_data(wl_surface) : NULL);
157 }
158
159 static void
160 pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
161                       uint32_t time, wl_fixed_t x, wl_fixed_t y)
162 {
163         struct pointer *pointer = data;
164
165         pointer->x = wl_fixed_to_int(x);
166         pointer->y = wl_fixed_to_int(y);
167
168         fprintf(stderr, "test-client: got pointer motion %d %d\n",
169                 pointer->x, pointer->y);
170 }
171
172 static void
173 pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
174                       uint32_t serial, uint32_t time, uint32_t button,
175                       uint32_t state)
176 {
177         struct pointer *pointer = data;
178
179         pointer->button = button;
180         pointer->state = state;
181
182         fprintf(stderr, "test-client: got pointer button %u %u\n",
183                 button, state);
184 }
185
186 static void
187 pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
188                     uint32_t time, uint32_t axis, wl_fixed_t value)
189 {
190         fprintf(stderr, "test-client: got pointer axis %u %f\n",
191                 axis, wl_fixed_to_double(value));
192 }
193
194 static void
195 pointer_handle_frame(void *data, struct wl_pointer *wl_pointer)
196 {
197         fprintf(stderr, "test-client: got pointer frame\n");
198 }
199
200 static void
201 pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer,
202                              uint32_t source)
203 {
204         fprintf(stderr, "test-client: got pointer axis source %u\n", source);
205 }
206
207 static void
208 pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer,
209                          uint32_t time, uint32_t axis)
210 {
211         fprintf(stderr, "test-client: got pointer axis stop\n");
212 }
213
214 static void
215 pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer,
216                              uint32_t axis, int32_t value)
217 {
218         fprintf(stderr, "test-client: got pointer axis discrete %u %d\n",
219                 axis, value);
220 }
221
222 static const struct wl_pointer_listener pointer_listener = {
223         pointer_handle_enter,
224         pointer_handle_leave,
225         pointer_handle_motion,
226         pointer_handle_button,
227         pointer_handle_axis,
228         pointer_handle_frame,
229         pointer_handle_axis_source,
230         pointer_handle_axis_stop,
231         pointer_handle_axis_discrete,
232 };
233
234 static void
235 keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
236                        uint32_t format, int fd, uint32_t size)
237 {
238         close(fd);
239
240         fprintf(stderr, "test-client: got keyboard keymap\n");
241 }
242
243 static void
244 keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
245                       uint32_t serial, struct wl_surface *wl_surface,
246                       struct wl_array *keys)
247 {
248         struct keyboard *keyboard = data;
249
250         if (wl_surface)
251                 keyboard->focus = wl_surface_get_user_data(wl_surface);
252         else
253                 keyboard->focus = NULL;
254
255         fprintf(stderr, "test-client: got keyboard enter, surface %p\n",
256                 keyboard->focus);
257 }
258
259 static void
260 keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
261                       uint32_t serial, struct wl_surface *wl_surface)
262 {
263         struct keyboard *keyboard = data;
264
265         keyboard->focus = NULL;
266
267         fprintf(stderr, "test-client: got keyboard leave, surface %p\n",
268                 wl_surface ? wl_surface_get_user_data(wl_surface) : NULL);
269 }
270
271 static void
272 keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
273                     uint32_t serial, uint32_t time, uint32_t key,
274                     uint32_t state)
275 {
276         struct keyboard *keyboard = data;
277
278         keyboard->key = key;
279         keyboard->state = state;
280
281         fprintf(stderr, "test-client: got keyboard key %u %u\n", key, state);
282 }
283
284 static void
285 keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
286                           uint32_t serial, uint32_t mods_depressed,
287                           uint32_t mods_latched, uint32_t mods_locked,
288                           uint32_t group)
289 {
290         struct keyboard *keyboard = data;
291
292         keyboard->mods_depressed = mods_depressed;
293         keyboard->mods_latched = mods_latched;
294         keyboard->mods_locked = mods_locked;
295         keyboard->group = group;
296
297         fprintf(stderr, "test-client: got keyboard modifiers %u %u %u %u\n",
298                 mods_depressed, mods_latched, mods_locked, group);
299 }
300
301 static void
302 keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
303                             int32_t rate, int32_t delay)
304 {
305         struct keyboard *keyboard = data;
306
307         keyboard->repeat_info.rate = rate;
308         keyboard->repeat_info.delay = delay;
309
310         fprintf(stderr, "test-client: got keyboard repeat_info %d %d\n",
311                 rate, delay);
312 }
313
314 static const struct wl_keyboard_listener keyboard_listener = {
315         keyboard_handle_keymap,
316         keyboard_handle_enter,
317         keyboard_handle_leave,
318         keyboard_handle_key,
319         keyboard_handle_modifiers,
320         keyboard_handle_repeat_info,
321 };
322
323 static void
324 touch_handle_down(void *data, struct wl_touch *wl_touch,
325                   uint32_t serial, uint32_t time, struct wl_surface *surface,
326                   int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
327 {
328         struct touch *touch = data;
329
330         touch->down_x = wl_fixed_to_int(x_w);
331         touch->down_y = wl_fixed_to_int(y_w);
332         touch->id = id;
333
334         fprintf(stderr, "test-client: got touch down %d %d, surf: %p, id: %d\n",
335                 touch->down_x, touch->down_y, surface, id);
336 }
337
338 static void
339 touch_handle_up(void *data, struct wl_touch *wl_touch,
340                 uint32_t serial, uint32_t time, int32_t id)
341 {
342         struct touch *touch = data;
343         touch->up_id = id;
344
345         fprintf(stderr, "test-client: got touch up, id: %d\n", id);
346 }
347
348 static void
349 touch_handle_motion(void *data, struct wl_touch *wl_touch,
350                     uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
351 {
352         struct touch *touch = data;
353         touch->x = wl_fixed_to_int(x_w);
354         touch->y = wl_fixed_to_int(y_w);
355
356         fprintf(stderr, "test-client: got touch motion, %d %d, id: %d\n",
357                 touch->x, touch->y, id);
358 }
359
360 static void
361 touch_handle_frame(void *data, struct wl_touch *wl_touch)
362 {
363         struct touch *touch = data;
364
365         ++touch->frame_no;
366
367         fprintf(stderr, "test-client: got touch frame (%d)\n", touch->frame_no);
368 }
369
370 static void
371 touch_handle_cancel(void *data, struct wl_touch *wl_touch)
372 {
373         struct touch *touch = data;
374
375         ++touch->cancel_no;
376
377         fprintf(stderr, "test-client: got touch cancel (%d)\n", touch->cancel_no);
378 }
379
380 static const struct wl_touch_listener touch_listener = {
381         touch_handle_down,
382         touch_handle_up,
383         touch_handle_motion,
384         touch_handle_frame,
385         touch_handle_cancel,
386 };
387
388 static void
389 surface_enter(void *data,
390               struct wl_surface *wl_surface, struct wl_output *output)
391 {
392         struct surface *surface = data;
393
394         surface->output = wl_output_get_user_data(output);
395
396         fprintf(stderr, "test-client: got surface enter output %p\n",
397                 surface->output);
398 }
399
400 static void
401 surface_leave(void *data,
402               struct wl_surface *wl_surface, struct wl_output *output)
403 {
404         struct surface *surface = data;
405
406         surface->output = NULL;
407
408         fprintf(stderr, "test-client: got surface leave output %p\n",
409                 wl_output_get_user_data(output));
410 }
411
412 static const struct wl_surface_listener surface_listener = {
413         surface_enter,
414         surface_leave
415 };
416
417 static struct wl_buffer *
418 create_shm_buffer(struct client *client, int width, int height, void **pixels)
419 {
420         struct wl_shm *shm = client->wl_shm;
421         int stride = width * 4;
422         int size = stride * height;
423         struct wl_shm_pool *pool;
424         struct wl_buffer *buffer;
425         int fd;
426         void *data;
427
428         fd = os_create_anonymous_file(size);
429         assert(fd >= 0);
430
431         data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
432         if (data == MAP_FAILED) {
433                 close(fd);
434                 assert(data != MAP_FAILED);
435         }
436
437         pool = wl_shm_create_pool(shm, fd, size);
438         buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride,
439                                            WL_SHM_FORMAT_ARGB8888);
440         wl_shm_pool_destroy(pool);
441
442         close(fd);
443
444         if (pixels)
445                 *pixels = data;
446
447         return buffer;
448 }
449
450 struct buffer *
451 create_shm_buffer_a8r8g8b8(struct client *client, int width, int height)
452 {
453         struct buffer *buf;
454         void *pixels;
455
456         buf = xzalloc(sizeof *buf);
457         buf->proxy = create_shm_buffer(client, width, height, &pixels);
458         buf->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height,
459                                               pixels, width * 4);
460         buf->len = width * height * 4;
461
462         assert(buf->proxy);
463         assert(buf->image);
464
465         return buf;
466 }
467
468 void
469 buffer_destroy(struct buffer *buf)
470 {
471         void *pixels;
472
473         pixels = pixman_image_get_data(buf->image);
474
475         if (buf->proxy) {
476                 wl_buffer_destroy(buf->proxy);
477                 assert(munmap(pixels, buf->len) == 0);
478         }
479
480         assert(pixman_image_unref(buf->image));
481
482         free(buf);
483 }
484
485 static void
486 shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
487 {
488         struct client *client = data;
489
490         if (format == WL_SHM_FORMAT_ARGB8888)
491                 client->has_argb = 1;
492 }
493
494 struct wl_shm_listener shm_listener = {
495         shm_format
496 };
497
498 static void
499 test_handle_pointer_position(void *data, struct weston_test *weston_test,
500                              wl_fixed_t x, wl_fixed_t y)
501 {
502         struct test *test = data;
503         test->pointer_x = wl_fixed_to_int(x);
504         test->pointer_y = wl_fixed_to_int(y);
505
506         fprintf(stderr, "test-client: got global pointer %d %d\n",
507                 test->pointer_x, test->pointer_y);
508 }
509
510 static void
511 test_handle_n_egl_buffers(void *data, struct weston_test *weston_test, uint32_t n)
512 {
513         struct test *test = data;
514
515         test->n_egl_buffers = n;
516 }
517
518 static void
519 test_handle_capture_screenshot_done(void *data, struct weston_test *weston_test)
520 {
521         struct test *test = data;
522
523         printf("Screenshot has been captured\n");
524         test->buffer_copy_done = 1;
525 }
526
527 static const struct weston_test_listener test_listener = {
528         test_handle_pointer_position,
529         test_handle_n_egl_buffers,
530         test_handle_capture_screenshot_done,
531 };
532
533 static void
534 input_update_devices(struct input *input)
535 {
536         struct pointer *pointer;
537         struct keyboard *keyboard;
538         struct touch *touch;
539
540         struct wl_seat *seat = input->wl_seat;
541         enum wl_seat_capability caps = input->caps;
542
543         if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
544                 pointer = xzalloc(sizeof *pointer);
545                 pointer->wl_pointer = wl_seat_get_pointer(seat);
546                 wl_pointer_set_user_data(pointer->wl_pointer, pointer);
547                 wl_pointer_add_listener(pointer->wl_pointer, &pointer_listener,
548                                         pointer);
549                 input->pointer = pointer;
550         } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
551                 wl_pointer_destroy(input->pointer->wl_pointer);
552                 free(input->pointer);
553                 input->pointer = NULL;
554         }
555
556         if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
557                 keyboard = xzalloc(sizeof *keyboard);
558                 keyboard->wl_keyboard = wl_seat_get_keyboard(seat);
559                 wl_keyboard_set_user_data(keyboard->wl_keyboard, keyboard);
560                 wl_keyboard_add_listener(keyboard->wl_keyboard, &keyboard_listener,
561                                          keyboard);
562                 input->keyboard = keyboard;
563         } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
564                 wl_keyboard_destroy(input->keyboard->wl_keyboard);
565                 free(input->keyboard);
566                 input->keyboard = NULL;
567         }
568
569         if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
570                 touch = xzalloc(sizeof *touch);
571                 touch->wl_touch = wl_seat_get_touch(seat);
572                 wl_touch_set_user_data(touch->wl_touch, touch);
573                 wl_touch_add_listener(touch->wl_touch, &touch_listener,
574                                          touch);
575                 input->touch = touch;
576         } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
577                 wl_touch_destroy(input->touch->wl_touch);
578                 free(input->touch);
579                 input->touch = NULL;
580         }
581 }
582
583 static void
584 seat_handle_capabilities(void *data, struct wl_seat *seat,
585                          enum wl_seat_capability caps)
586 {
587         struct input *input = data;
588
589         input->caps = caps;
590
591         /* we will create/update the devices only with the right (test) seat.
592          * If we haven't discovered which seat is the test seat, just
593          * store capabilities and bail out */
594         if (input->seat_name && strcmp(input->seat_name, "test-seat") == 0)
595                 input_update_devices(input);
596
597         fprintf(stderr, "test-client: got seat %p capabilities: %x\n",
598                 input, caps);
599 }
600
601 static void
602 seat_handle_name(void *data, struct wl_seat *seat, const char *name)
603 {
604         struct input *input = data;
605
606         input->seat_name = strdup(name);
607         assert(input->seat_name && "No memory");
608
609         fprintf(stderr, "test-client: got seat %p name: \'%s\'\n",
610                 input, name);
611 }
612
613 static const struct wl_seat_listener seat_listener = {
614         seat_handle_capabilities,
615         seat_handle_name,
616 };
617
618 static void
619 output_handle_geometry(void *data,
620                        struct wl_output *wl_output,
621                        int x, int y,
622                        int physical_width,
623                        int physical_height,
624                        int subpixel,
625                        const char *make,
626                        const char *model,
627                        int32_t transform)
628 {
629         struct output *output = data;
630
631         output->x = x;
632         output->y = y;
633 }
634
635 static void
636 output_handle_mode(void *data,
637                    struct wl_output *wl_output,
638                    uint32_t flags,
639                    int width,
640                    int height,
641                    int refresh)
642 {
643         struct output *output = data;
644
645         if (flags & WL_OUTPUT_MODE_CURRENT) {
646                 output->width = width;
647                 output->height = height;
648         }
649 }
650
651 static void
652 output_handle_scale(void *data,
653                     struct wl_output *wl_output,
654                     int scale)
655 {
656         struct output *output = data;
657
658         output->scale = scale;
659 }
660
661 static void
662 output_handle_done(void *data,
663                    struct wl_output *wl_output)
664 {
665         struct output *output = data;
666
667         output->initialized = 1;
668 }
669
670 static const struct wl_output_listener output_listener = {
671         output_handle_geometry,
672         output_handle_mode,
673         output_handle_done,
674         output_handle_scale,
675 };
676
677 static void
678 handle_global(void *data, struct wl_registry *registry,
679               uint32_t id, const char *interface, uint32_t version)
680 {
681         struct client *client = data;
682         struct output *output;
683         struct test *test;
684         struct global *global;
685         struct input *input;
686
687         global = xzalloc(sizeof *global);
688         global->name = id;
689         global->interface = strdup(interface);
690         assert(interface);
691         global->version = version;
692         wl_list_insert(client->global_list.prev, &global->link);
693
694         if (strcmp(interface, "wl_compositor") == 0) {
695                 client->wl_compositor =
696                         wl_registry_bind(registry, id,
697                                          &wl_compositor_interface, version);
698         } else if (strcmp(interface, "wl_seat") == 0) {
699                 input = xzalloc(sizeof *input);
700                 input->wl_seat =
701                         wl_registry_bind(registry, id,
702                                          &wl_seat_interface, version);
703                 wl_seat_add_listener(input->wl_seat, &seat_listener, input);
704                 wl_list_insert(&client->inputs, &input->link);
705         } else if (strcmp(interface, "wl_shm") == 0) {
706                 client->wl_shm =
707                         wl_registry_bind(registry, id,
708                                          &wl_shm_interface, version);
709                 wl_shm_add_listener(client->wl_shm, &shm_listener, client);
710         } else if (strcmp(interface, "wl_output") == 0) {
711                 output = xzalloc(sizeof *output);
712                 output->wl_output =
713                         wl_registry_bind(registry, id,
714                                          &wl_output_interface, version);
715                 wl_output_add_listener(output->wl_output,
716                                        &output_listener, output);
717                 client->output = output;
718         } else if (strcmp(interface, "weston_test") == 0) {
719                 test = xzalloc(sizeof *test);
720                 test->weston_test =
721                         wl_registry_bind(registry, id,
722                                          &weston_test_interface, version);
723                 weston_test_add_listener(test->weston_test, &test_listener, test);
724                 client->test = test;
725         } else if (strcmp(interface, "wl_drm") == 0) {
726                 client->has_wl_drm = true;
727         }
728 }
729
730 static const struct wl_registry_listener registry_listener = {
731         handle_global
732 };
733
734 void
735 skip(const char *fmt, ...)
736 {
737         va_list argp;
738
739         va_start(argp, fmt);
740         vfprintf(stderr, fmt, argp);
741         va_end(argp);
742
743         /* automake tests uses exit code 77. weston-test-runner will see
744          * this and use it, and then weston-test's sigchld handler (in the
745          * weston process) will use that as an exit status, which is what
746          * automake will see in the end. */
747         exit(77);
748 }
749
750 void
751 expect_protocol_error(struct client *client,
752                       const struct wl_interface *intf,
753                       uint32_t code)
754 {
755         int err;
756         uint32_t errcode, failed = 0;
757         const struct wl_interface *interface;
758         unsigned int id;
759
760         /* if the error has not come yet, make it happen */
761         wl_display_roundtrip(client->wl_display);
762
763         err = wl_display_get_error(client->wl_display);
764
765         assert(err && "Expected protocol error but nothing came");
766         assert(err == EPROTO && "Expected protocol error but got local error");
767
768         errcode = wl_display_get_protocol_error(client->wl_display,
769                                                 &interface, &id);
770
771         /* check error */
772         if (errcode != code) {
773                 fprintf(stderr, "Should get error code %d but got %d\n",
774                         code, errcode);
775                 failed = 1;
776         }
777
778         /* this should be definitely set */
779         assert(interface);
780
781         if (strcmp(intf->name, interface->name) != 0) {
782                 fprintf(stderr, "Should get interface '%s' but got '%s'\n",
783                         intf->name, interface->name);
784                 failed = 1;
785         }
786
787         if (failed) {
788                 fprintf(stderr, "Expected other protocol error\n");
789                 abort();
790         }
791
792         /* all OK */
793         fprintf(stderr, "Got expected protocol error on '%s' (object id: %d) "
794                         "with code %d\n", interface->name, id, errcode);
795 }
796
797 static void
798 log_handler(const char *fmt, va_list args)
799 {
800         fprintf(stderr, "libwayland: ");
801         vfprintf(stderr, fmt, args);
802 }
803
804 static void
805 input_destroy(struct input *inp)
806 {
807         wl_list_remove(&inp->link);
808         wl_seat_destroy(inp->wl_seat);
809         free(inp);
810 }
811
812 /* find the test-seat and set it in client.
813  * Destroy other inputs */
814 static void
815 client_set_input(struct client *cl)
816 {
817         struct input *inp, *inptmp;
818         wl_list_for_each_safe(inp, inptmp, &cl->inputs, link) {
819                 assert(inp->seat_name && "BUG: input with no name");
820                 if (strcmp(inp->seat_name, "test-seat") == 0) {
821                         cl->input = inp;
822                         input_update_devices(inp);
823                 } else {
824                         input_destroy(inp);
825                 }
826         }
827
828         /* we keep only one input */
829         assert(wl_list_length(&cl->inputs) == 1);
830 }
831
832 struct client *
833 create_client(void)
834 {
835         struct client *client;
836
837         wl_log_set_handler_client(log_handler);
838
839         /* connect to display */
840         client = xzalloc(sizeof *client);
841         client->wl_display = wl_display_connect(NULL);
842         assert(client->wl_display);
843         wl_list_init(&client->global_list);
844         wl_list_init(&client->inputs);
845
846         /* setup registry so we can bind to interfaces */
847         client->wl_registry = wl_display_get_registry(client->wl_display);
848         wl_registry_add_listener(client->wl_registry, &registry_listener,
849                                  client);
850
851         /* this roundtrip makes sure we have all globals and we bound to them */
852         client_roundtrip(client);
853         /* this roundtrip makes sure we got all wl_shm.format and wl_seat.*
854          * events */
855         client_roundtrip(client);
856
857         /* find the right input for us */
858         client_set_input(client);
859
860         /* must have WL_SHM_FORMAT_ARGB32 */
861         assert(client->has_argb);
862
863         /* must have weston_test interface */
864         assert(client->test);
865
866         /* must have an output */
867         assert(client->output);
868
869         /* the output must be initialized */
870         assert(client->output->initialized == 1);
871
872         /* must have seat set */
873         assert(client->input);
874
875         return client;
876 }
877
878 struct client *
879 create_client_and_test_surface(int x, int y, int width, int height)
880 {
881         struct client *client;
882         struct surface *surface;
883         pixman_color_t color = { 16384, 16384, 16384, 16384 }; /* uint16_t */
884         pixman_image_t *solid;
885
886         client = create_client();
887
888         /* initialize the client surface */
889         surface = xzalloc(sizeof *surface);
890         surface->wl_surface =
891                 wl_compositor_create_surface(client->wl_compositor);
892         assert(surface->wl_surface);
893
894         wl_surface_add_listener(surface->wl_surface, &surface_listener,
895                                 surface);
896
897         client->surface = surface;
898         wl_surface_set_user_data(surface->wl_surface, surface);
899
900         surface->width = width;
901         surface->height = height;
902         surface->buffer = create_shm_buffer_a8r8g8b8(client, width, height);
903
904         solid = pixman_image_create_solid_fill(&color);
905         pixman_image_composite32(PIXMAN_OP_SRC,
906                                  solid, /* src */
907                                  NULL, /* mask */
908                                  surface->buffer->image, /* dst */
909                                  0, 0, /* src x,y */
910                                  0, 0, /* mask x,y */
911                                  0, 0, /* dst x,y */
912                                  width, height);
913         pixman_image_unref(solid);
914
915         move_client(client, x, y);
916
917         return client;
918 }
919
920 static const char*
921 output_path(void)
922 {
923         char *path = getenv("WESTON_TEST_OUTPUT_PATH");
924
925         if (!path)
926                 return ".";
927         return path;
928         }
929
930 char*
931 screenshot_output_filename(const char *basename, uint32_t seq)
932 {
933         char *filename;
934
935         if (asprintf(&filename, "%s/%s-%02d.png",
936                                  output_path(), basename, seq) < 0)
937                 return NULL;
938         return filename;
939 }
940
941 static const char*
942 reference_path(void)
943 {
944         char *path = getenv("WESTON_TEST_REFERENCE_PATH");
945
946         if (!path)
947                 return "./tests/reference";
948         return path;
949 }
950
951 char*
952 screenshot_reference_filename(const char *basename, uint32_t seq)
953 {
954         char *filename;
955
956         if (asprintf(&filename, "%s/%s-%02d.png",
957                                  reference_path(), basename, seq) < 0)
958                 return NULL;
959         return filename;
960 }
961
962 /**
963  * check_surfaces_geometry() - verifies two surfaces are same size
964  *
965  * @returns true if surfaces have the same width and height, or false
966  * if not, or if there is no actual data.
967  */
968 bool
969 check_surfaces_geometry(const struct surface *a, const struct surface *b)
970 {
971         if (a == NULL || b == NULL) {
972                 printf("Undefined surfaces\n");
973                 return false;
974         }
975         else if (a->buffer == NULL || b->buffer == NULL) {
976                 printf("Undefined data\n");
977                 return false;
978         }
979         else if (a->width != b->width || a->height != b->height) {
980                 printf("Mismatched dimensions:  %d,%d != %d,%d\n",
981                        a->width, a->height, b->width, b->height);
982                 return false;
983         }
984         return true;
985 }
986
987 /**
988  * check_surfaces_equal() - tests if two surfaces are pixel-identical
989  *
990  * Returns true if surface buffers have all the same byte values,
991  * false if the surfaces don't match or can't be compared due to
992  * different dimensions.
993  */
994 bool
995 check_surfaces_equal(const struct surface *a, const struct surface *b)
996 {
997         int bpp = 4;  /* Assumes ARGB */
998         void *data_a;
999         void *data_b;
1000
1001         if (!check_surfaces_geometry(a, b))
1002                 return false;
1003
1004         data_a = pixman_image_get_data(a->buffer->image);
1005         data_b = pixman_image_get_data(b->buffer->image);
1006
1007         return (memcmp(data_a, data_b, bpp * a->width * a->height) == 0);
1008 }
1009
1010 /**
1011  * check_surfaces_match_in_clip() - tests if a given region within two
1012  * surfaces are pixel-identical.
1013  *
1014  * Returns true if the two surfaces have the same byte values within the
1015  * given clipping region, or false if they don't match or the surfaces
1016  * can't be compared.
1017  */
1018 bool
1019 check_surfaces_match_in_clip(const struct surface *a, const struct surface *b, const struct rectangle *clip_rect)
1020 {
1021         int i, j;
1022         int x0, y0, x1, y1;
1023         void *p, *q;
1024         int bpp = 4;  /* Assumes ARGB */
1025         void *data_a;
1026         void *data_b;
1027
1028         if (!check_surfaces_geometry(a, b) || clip_rect == NULL)
1029                 return false;
1030
1031         if (clip_rect->x > a->width || clip_rect->y > a->height) {
1032                 printf("Clip outside image boundaries\n");
1033                 return true;
1034         }
1035
1036         x0 = max(0, clip_rect->x);
1037         y0 = max(0, clip_rect->y);
1038         x1 = min(a->width,  clip_rect->x + clip_rect->width);
1039         y1 = min(a->height, clip_rect->y + clip_rect->height);
1040
1041         if (x0 == x1 || y0 == y1) {
1042                 printf("Degenerate comparison\n");
1043                 return true;
1044         }
1045
1046         data_a = pixman_image_get_data(a->buffer->image);
1047         data_b = pixman_image_get_data(b->buffer->image);
1048
1049         printf("Bytewise comparison inside clip\n");
1050         for (i=y0; i<y1; i++) {
1051                 p = data_a + i * a->width * bpp + x0 * bpp;
1052                 q = data_b + i * b->width * bpp + x0 * bpp;
1053                 if (memcmp(p, q, (x1-x0)*bpp) != 0) {
1054                         /* Dump the bad row */
1055                         printf("Mismatched image on row %d\n", i);
1056                         for (j=0; j<(x1-x0)*bpp; j++) {
1057                                 char a_char = *((char*)(p+j*bpp));
1058                                 char b_char = *((char*)(q+j*bpp));
1059                                 printf("%d,%d: %8x %8x %s\n", i, j, a_char, b_char,
1060                                        (a_char != b_char)? " <---": "");
1061                         }
1062                         return false;
1063                 }
1064         }
1065
1066         return true;
1067 }
1068
1069 /** write_surface_as_png()
1070  *
1071  * Writes out a given weston test surface to disk as a PNG image
1072  * using the provided filename (with path).
1073  *
1074  * @returns true if successfully saved file; false otherwise.
1075  */
1076 bool
1077 write_surface_as_png(const struct surface *weston_surface, const char *fname)
1078 {
1079         cairo_surface_t *cairo_surface;
1080         cairo_status_t status;
1081         int bpp = 4; /* Assume ARGB */
1082         int stride = bpp * weston_surface->width;
1083         void *pixels;
1084
1085         pixels = pixman_image_get_data(weston_surface->buffer->image);
1086         cairo_surface = cairo_image_surface_create_for_data(pixels,
1087                                                             CAIRO_FORMAT_ARGB32,
1088                                                             weston_surface->width,
1089                                                             weston_surface->height,
1090                                                             stride);
1091         printf("Writing PNG to disk\n");
1092         status = cairo_surface_write_to_png(cairo_surface, fname);
1093         if (status != CAIRO_STATUS_SUCCESS) {
1094                 printf("Failed to save screenshot: %s\n",
1095                        cairo_status_to_string(status));
1096                 return false;
1097         }
1098         cairo_surface_destroy(cairo_surface);
1099         return true;
1100 }
1101
1102 /** load_surface_from_png()
1103  *
1104  * Reads a PNG image from disk using the given filename (and path)
1105  * and returns as a freshly allocated weston test surface.
1106  *
1107  * @returns weston test surface with image, which should be free'd
1108  * when no longer used; or, NULL in case of error.
1109  */
1110 struct surface *
1111 load_surface_from_png(const char *fname)
1112 {
1113         struct surface *reference;
1114         cairo_surface_t *reference_cairo_surface;
1115         cairo_status_t status;
1116         size_t source_data_size;
1117         int bpp;
1118         int stride;
1119
1120         reference_cairo_surface = cairo_image_surface_create_from_png(fname);
1121         status = cairo_surface_status(reference_cairo_surface);
1122         if (status != CAIRO_STATUS_SUCCESS) {
1123                 printf("Could not open %s: %s\n", fname, cairo_status_to_string(status));
1124                 cairo_surface_destroy(reference_cairo_surface);
1125                 return NULL;
1126         }
1127
1128         /* Disguise the cairo surface in a weston test surface */
1129         reference = zalloc(sizeof *reference);
1130         if (reference == NULL) {
1131                 perror("zalloc reference");
1132                 cairo_surface_destroy(reference_cairo_surface);
1133                 return NULL;
1134         }
1135         reference->width = cairo_image_surface_get_width(reference_cairo_surface);
1136         reference->height = cairo_image_surface_get_height(reference_cairo_surface);
1137         stride = cairo_image_surface_get_stride(reference_cairo_surface);
1138         source_data_size = stride * reference->height;
1139
1140         /* Check that the file's stride matches our assumption */
1141         bpp = 4;
1142         if (stride != bpp * reference->width) {
1143                 printf("Mismatched stride for screenshot reference image %s\n", fname);
1144                 cairo_surface_destroy(reference_cairo_surface);
1145                 free(reference);
1146                 return NULL;
1147         }
1148
1149         /* Allocate new buffer for our weston reference, and copy the data from
1150            the cairo surface so we can destroy it */
1151
1152         reference->buffer = xzalloc(sizeof *reference->buffer);
1153         reference->buffer->image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
1154                                                             reference->width,
1155                                                             reference->height,
1156                                                             NULL, 0);
1157         assert(reference->buffer->image);
1158
1159         memcpy(pixman_image_get_data(reference->buffer->image),
1160                cairo_image_surface_get_data(reference_cairo_surface),
1161                source_data_size);
1162
1163         cairo_surface_destroy(reference_cairo_surface);
1164         return reference;
1165 }
1166
1167 /** create_screenshot_surface()
1168  *
1169  *  Allocates and initializes a weston test surface for use in
1170  *  storing a screenshot of the client's output.  Establishes a
1171  *  shm backed wl_buffer for retrieving screenshot image data
1172  *  from the server, sized to match the client's output display.
1173  *
1174  *  @returns stack allocated surface image, which should be
1175  *  free'd when done using it.
1176  */
1177 struct surface *
1178 create_screenshot_surface(struct client *client)
1179 {
1180         struct surface *screenshot;
1181         screenshot = zalloc(sizeof *screenshot);
1182         if (screenshot == NULL)
1183                 return NULL;
1184
1185         screenshot->buffer = create_shm_buffer_a8r8g8b8(client,
1186                                                         client->output->width,
1187                                                         client->output->height);
1188         screenshot->height = client->output->height;
1189         screenshot->width = client->output->width;
1190
1191         return screenshot;
1192 }
1193
1194 /** capture_screenshot_of_output()
1195  *
1196  * Requests a screenshot from the server of the output that the
1197  * client appears on.  The image data returned from the server
1198  * can be accessed from the screenshot surface's data member.
1199  *
1200  * @returns a new surface object, which should be free'd when no
1201  * longer needed.
1202  */
1203 struct surface *
1204 capture_screenshot_of_output(struct client *client)
1205 {
1206         struct surface *screenshot;
1207
1208         /* Create a surface to hold the screenshot */
1209         screenshot = create_screenshot_surface(client);
1210
1211         client->test->buffer_copy_done = 0;
1212         weston_test_capture_screenshot(client->test->weston_test,
1213                                        client->output->wl_output,
1214                                        screenshot->buffer->proxy);
1215         while (client->test->buffer_copy_done == 0)
1216                 if (wl_display_dispatch(client->wl_display) < 0)
1217                         break;
1218
1219         /* FIXME: Document somewhere the orientation the screenshot is taken
1220          * and how the clip coords are interpreted, in case of scaling/transform.
1221          * If we're using read_pixels() just make sure it is documented somewhere.
1222          * Protocol docs in the XML, comparison function docs in Doxygen style.
1223          */
1224
1225         return screenshot;
1226 }