tests: check for NULL surface in keyboard and pointer handlers
[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->wl_buffer, 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 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 static void
451 shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
452 {
453         struct client *client = data;
454
455         if (format == WL_SHM_FORMAT_ARGB8888)
456                 client->has_argb = 1;
457 }
458
459 struct wl_shm_listener shm_listener = {
460         shm_format
461 };
462
463 static void
464 test_handle_pointer_position(void *data, struct weston_test *weston_test,
465                              wl_fixed_t x, wl_fixed_t y)
466 {
467         struct test *test = data;
468         test->pointer_x = wl_fixed_to_int(x);
469         test->pointer_y = wl_fixed_to_int(y);
470
471         fprintf(stderr, "test-client: got global pointer %d %d\n",
472                 test->pointer_x, test->pointer_y);
473 }
474
475 static void
476 test_handle_n_egl_buffers(void *data, struct weston_test *weston_test, uint32_t n)
477 {
478         struct test *test = data;
479
480         test->n_egl_buffers = n;
481 }
482
483 static void
484 test_handle_capture_screenshot_done(void *data, struct weston_test *weston_test)
485 {
486         struct test *test = data;
487
488         printf("Screenshot has been captured\n");
489         test->buffer_copy_done = 1;
490 }
491
492 static const struct weston_test_listener test_listener = {
493         test_handle_pointer_position,
494         test_handle_n_egl_buffers,
495         test_handle_capture_screenshot_done,
496 };
497
498 static void
499 input_update_devices(struct input *input)
500 {
501         struct pointer *pointer;
502         struct keyboard *keyboard;
503         struct touch *touch;
504
505         struct wl_seat *seat = input->wl_seat;
506         enum wl_seat_capability caps = input->caps;
507
508         if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->pointer) {
509                 pointer = xzalloc(sizeof *pointer);
510                 pointer->wl_pointer = wl_seat_get_pointer(seat);
511                 wl_pointer_set_user_data(pointer->wl_pointer, pointer);
512                 wl_pointer_add_listener(pointer->wl_pointer, &pointer_listener,
513                                         pointer);
514                 input->pointer = pointer;
515         } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->pointer) {
516                 wl_pointer_destroy(input->pointer->wl_pointer);
517                 free(input->pointer);
518                 input->pointer = NULL;
519         }
520
521         if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
522                 keyboard = xzalloc(sizeof *keyboard);
523                 keyboard->wl_keyboard = wl_seat_get_keyboard(seat);
524                 wl_keyboard_set_user_data(keyboard->wl_keyboard, keyboard);
525                 wl_keyboard_add_listener(keyboard->wl_keyboard, &keyboard_listener,
526                                          keyboard);
527                 input->keyboard = keyboard;
528         } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
529                 wl_keyboard_destroy(input->keyboard->wl_keyboard);
530                 free(input->keyboard);
531                 input->keyboard = NULL;
532         }
533
534         if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->touch) {
535                 touch = xzalloc(sizeof *touch);
536                 touch->wl_touch = wl_seat_get_touch(seat);
537                 wl_touch_set_user_data(touch->wl_touch, touch);
538                 wl_touch_add_listener(touch->wl_touch, &touch_listener,
539                                          touch);
540                 input->touch = touch;
541         } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->touch) {
542                 wl_touch_destroy(input->touch->wl_touch);
543                 free(input->touch);
544                 input->touch = NULL;
545         }
546 }
547
548 static void
549 seat_handle_capabilities(void *data, struct wl_seat *seat,
550                          enum wl_seat_capability caps)
551 {
552         struct input *input = data;
553
554         input->caps = caps;
555
556         /* we will create/update the devices only with the right (test) seat.
557          * If we haven't discovered which seat is the test seat, just
558          * store capabilities and bail out */
559         if (input->seat_name && strcmp(input->seat_name, "test-seat") == 0)
560                 input_update_devices(input);
561
562         fprintf(stderr, "test-client: got seat %p capabilities: %x\n",
563                 input, caps);
564 }
565
566 static void
567 seat_handle_name(void *data, struct wl_seat *seat, const char *name)
568 {
569         struct input *input = data;
570
571         input->seat_name = strdup(name);
572         assert(input->seat_name && "No memory");
573
574         fprintf(stderr, "test-client: got seat %p name: \'%s\'\n",
575                 input, name);
576 }
577
578 static const struct wl_seat_listener seat_listener = {
579         seat_handle_capabilities,
580         seat_handle_name,
581 };
582
583 static void
584 output_handle_geometry(void *data,
585                        struct wl_output *wl_output,
586                        int x, int y,
587                        int physical_width,
588                        int physical_height,
589                        int subpixel,
590                        const char *make,
591                        const char *model,
592                        int32_t transform)
593 {
594         struct output *output = data;
595
596         output->x = x;
597         output->y = y;
598 }
599
600 static void
601 output_handle_mode(void *data,
602                    struct wl_output *wl_output,
603                    uint32_t flags,
604                    int width,
605                    int height,
606                    int refresh)
607 {
608         struct output *output = data;
609
610         if (flags & WL_OUTPUT_MODE_CURRENT) {
611                 output->width = width;
612                 output->height = height;
613         }
614 }
615
616 static void
617 output_handle_scale(void *data,
618                     struct wl_output *wl_output,
619                     int scale)
620 {
621         struct output *output = data;
622
623         output->scale = scale;
624 }
625
626 static void
627 output_handle_done(void *data,
628                    struct wl_output *wl_output)
629 {
630         struct output *output = data;
631
632         output->initialized = 1;
633 }
634
635 static const struct wl_output_listener output_listener = {
636         output_handle_geometry,
637         output_handle_mode,
638         output_handle_done,
639         output_handle_scale,
640 };
641
642 static void
643 handle_global(void *data, struct wl_registry *registry,
644               uint32_t id, const char *interface, uint32_t version)
645 {
646         struct client *client = data;
647         struct output *output;
648         struct test *test;
649         struct global *global;
650         struct input *input;
651
652         global = xzalloc(sizeof *global);
653         global->name = id;
654         global->interface = strdup(interface);
655         assert(interface);
656         global->version = version;
657         wl_list_insert(client->global_list.prev, &global->link);
658
659         if (strcmp(interface, "wl_compositor") == 0) {
660                 client->wl_compositor =
661                         wl_registry_bind(registry, id,
662                                          &wl_compositor_interface, version);
663         } else if (strcmp(interface, "wl_seat") == 0) {
664                 input = xzalloc(sizeof *input);
665                 input->wl_seat =
666                         wl_registry_bind(registry, id,
667                                          &wl_seat_interface, version);
668                 wl_seat_add_listener(input->wl_seat, &seat_listener, input);
669                 wl_list_insert(&client->inputs, &input->link);
670         } else if (strcmp(interface, "wl_shm") == 0) {
671                 client->wl_shm =
672                         wl_registry_bind(registry, id,
673                                          &wl_shm_interface, version);
674                 wl_shm_add_listener(client->wl_shm, &shm_listener, client);
675         } else if (strcmp(interface, "wl_output") == 0) {
676                 output = xzalloc(sizeof *output);
677                 output->wl_output =
678                         wl_registry_bind(registry, id,
679                                          &wl_output_interface, version);
680                 wl_output_add_listener(output->wl_output,
681                                        &output_listener, output);
682                 client->output = output;
683         } else if (strcmp(interface, "weston_test") == 0) {
684                 test = xzalloc(sizeof *test);
685                 test->weston_test =
686                         wl_registry_bind(registry, id,
687                                          &weston_test_interface, version);
688                 weston_test_add_listener(test->weston_test, &test_listener, test);
689                 client->test = test;
690         } else if (strcmp(interface, "wl_drm") == 0) {
691                 client->has_wl_drm = true;
692         }
693 }
694
695 static const struct wl_registry_listener registry_listener = {
696         handle_global
697 };
698
699 void
700 skip(const char *fmt, ...)
701 {
702         va_list argp;
703
704         va_start(argp, fmt);
705         vfprintf(stderr, fmt, argp);
706         va_end(argp);
707
708         /* automake tests uses exit code 77. weston-test-runner will see
709          * this and use it, and then weston-test's sigchld handler (in the
710          * weston process) will use that as an exit status, which is what
711          * automake will see in the end. */
712         exit(77);
713 }
714
715 void
716 expect_protocol_error(struct client *client,
717                       const struct wl_interface *intf,
718                       uint32_t code)
719 {
720         int err;
721         uint32_t errcode, failed = 0;
722         const struct wl_interface *interface;
723         unsigned int id;
724
725         /* if the error has not come yet, make it happen */
726         wl_display_roundtrip(client->wl_display);
727
728         err = wl_display_get_error(client->wl_display);
729
730         assert(err && "Expected protocol error but nothing came");
731         assert(err == EPROTO && "Expected protocol error but got local error");
732
733         errcode = wl_display_get_protocol_error(client->wl_display,
734                                                 &interface, &id);
735
736         /* check error */
737         if (errcode != code) {
738                 fprintf(stderr, "Should get error code %d but got %d\n",
739                         code, errcode);
740                 failed = 1;
741         }
742
743         /* this should be definitely set */
744         assert(interface);
745
746         if (strcmp(intf->name, interface->name) != 0) {
747                 fprintf(stderr, "Should get interface '%s' but got '%s'\n",
748                         intf->name, interface->name);
749                 failed = 1;
750         }
751
752         if (failed) {
753                 fprintf(stderr, "Expected other protocol error\n");
754                 abort();
755         }
756
757         /* all OK */
758         fprintf(stderr, "Got expected protocol error on '%s' (object id: %d) "
759                         "with code %d\n", interface->name, id, errcode);
760 }
761
762 static void
763 log_handler(const char *fmt, va_list args)
764 {
765         fprintf(stderr, "libwayland: ");
766         vfprintf(stderr, fmt, args);
767 }
768
769 static void
770 input_destroy(struct input *inp)
771 {
772         wl_list_remove(&inp->link);
773         wl_seat_destroy(inp->wl_seat);
774         free(inp);
775 }
776
777 /* find the test-seat and set it in client.
778  * Destroy other inputs */
779 static void
780 client_set_input(struct client *cl)
781 {
782         struct input *inp, *inptmp;
783         wl_list_for_each_safe(inp, inptmp, &cl->inputs, link) {
784                 assert(inp->seat_name && "BUG: input with no name");
785                 if (strcmp(inp->seat_name, "test-seat") == 0) {
786                         cl->input = inp;
787                         input_update_devices(inp);
788                 } else {
789                         input_destroy(inp);
790                 }
791         }
792
793         /* we keep only one input */
794         assert(wl_list_length(&cl->inputs) == 1);
795 }
796
797 struct client *
798 create_client(void)
799 {
800         struct client *client;
801
802         wl_log_set_handler_client(log_handler);
803
804         /* connect to display */
805         client = xzalloc(sizeof *client);
806         client->wl_display = wl_display_connect(NULL);
807         assert(client->wl_display);
808         wl_list_init(&client->global_list);
809         wl_list_init(&client->inputs);
810
811         /* setup registry so we can bind to interfaces */
812         client->wl_registry = wl_display_get_registry(client->wl_display);
813         wl_registry_add_listener(client->wl_registry, &registry_listener,
814                                  client);
815
816         /* this roundtrip makes sure we have all globals and we bound to them */
817         client_roundtrip(client);
818         /* this roundtrip makes sure we got all wl_shm.format and wl_seat.*
819          * events */
820         client_roundtrip(client);
821
822         /* find the right input for us */
823         client_set_input(client);
824
825         /* must have WL_SHM_FORMAT_ARGB32 */
826         assert(client->has_argb);
827
828         /* must have weston_test interface */
829         assert(client->test);
830
831         /* must have an output */
832         assert(client->output);
833
834         /* the output must be initialized */
835         assert(client->output->initialized == 1);
836
837         /* must have seat set */
838         assert(client->input);
839
840         return client;
841 }
842
843 struct client *
844 create_client_and_test_surface(int x, int y, int width, int height)
845 {
846         struct client *client;
847         struct surface *surface;
848
849         client = create_client();
850
851         /* initialize the client surface */
852         surface = xzalloc(sizeof *surface);
853         surface->wl_surface =
854                 wl_compositor_create_surface(client->wl_compositor);
855         assert(surface->wl_surface);
856
857         wl_surface_add_listener(surface->wl_surface, &surface_listener,
858                                 surface);
859
860         client->surface = surface;
861         wl_surface_set_user_data(surface->wl_surface, surface);
862
863         surface->width = width;
864         surface->height = height;
865         surface->wl_buffer = create_shm_buffer(client, width, height,
866                                                &surface->data);
867
868         memset(surface->data, 64, width * height * 4);
869
870         move_client(client, x, y);
871
872         return client;
873 }
874
875 static const char*
876 output_path(void)
877 {
878         char *path = getenv("WESTON_TEST_OUTPUT_PATH");
879
880         if (!path)
881                 return ".";
882         return path;
883         }
884
885 char*
886 screenshot_output_filename(const char *basename, uint32_t seq)
887 {
888         char *filename;
889
890         if (asprintf(&filename, "%s/%s-%02d.png",
891                                  output_path(), basename, seq) < 0)
892                 return NULL;
893         return filename;
894 }
895
896 static const char*
897 reference_path(void)
898 {
899         char *path = getenv("WESTON_TEST_REFERENCE_PATH");
900
901         if (!path)
902                 return "./tests/reference";
903         return path;
904 }
905
906 char*
907 screenshot_reference_filename(const char *basename, uint32_t seq)
908 {
909         char *filename;
910
911         if (asprintf(&filename, "%s/%s-%02d.png",
912                                  reference_path(), basename, seq) < 0)
913                 return NULL;
914         return filename;
915 }
916
917 /**
918  * check_surfaces_geometry() - verifies two surfaces are same size
919  *
920  * @returns true if surfaces have the same width and height, or false
921  * if not, or if there is no actual data.
922  */
923 bool
924 check_surfaces_geometry(const struct surface *a, const struct surface *b)
925 {
926         if (a == NULL || b == NULL) {
927                 printf("Undefined surfaces\n");
928                 return false;
929         }
930         else if (a->data == NULL || b->data == NULL) {
931                 printf("Undefined data\n");
932                 return false;
933         }
934         else if (a->width != b->width || a->height != b->height) {
935                 printf("Mismatched dimensions:  %d,%d != %d,%d\n",
936                        a->width, a->height, b->width, b->height);
937                 return false;
938         }
939         return true;
940 }
941
942 /**
943  * check_surfaces_equal() - tests if two surfaces are pixel-identical
944  *
945  * Returns true if surface buffers have all the same byte values,
946  * false if the surfaces don't match or can't be compared due to
947  * different dimensions.
948  */
949 bool
950 check_surfaces_equal(const struct surface *a, const struct surface *b)
951 {
952         int bpp = 4;  /* Assumes ARGB */
953
954         if (!check_surfaces_geometry(a, b))
955                 return false;
956
957         return (memcmp(a->data, b->data, bpp * a->width * a->height) == 0);
958 }
959
960 /**
961  * check_surfaces_match_in_clip() - tests if a given region within two
962  * surfaces are pixel-identical.
963  *
964  * Returns true if the two surfaces have the same byte values within the
965  * given clipping region, or false if they don't match or the surfaces
966  * can't be compared.
967  */
968 bool
969 check_surfaces_match_in_clip(const struct surface *a, const struct surface *b, const struct rectangle *clip_rect)
970 {
971         int i, j;
972         int x0, y0, x1, y1;
973         void *p, *q;
974         int bpp = 4;  /* Assumes ARGB */
975
976         if (!check_surfaces_geometry(a, b) || clip_rect == NULL)
977                 return false;
978
979         if (clip_rect->x > a->width || clip_rect->y > a->height) {
980                 printf("Clip outside image boundaries\n");
981                 return true;
982         }
983
984         x0 = max(0, clip_rect->x);
985         y0 = max(0, clip_rect->y);
986         x1 = min(a->width,  clip_rect->x + clip_rect->width);
987         y1 = min(a->height, clip_rect->y + clip_rect->height);
988
989         if (x0 == x1 || y0 == y1) {
990                 printf("Degenerate comparison\n");
991                 return true;
992         }
993
994         printf("Bytewise comparison inside clip\n");
995         for (i=y0; i<y1; i++) {
996                 p = a->data + i * a->width * bpp + x0 * bpp;
997                 q = b->data + i * b->width * bpp + x0 * bpp;
998                 if (memcmp(p, q, (x1-x0)*bpp) != 0) {
999                         /* Dump the bad row */
1000                         printf("Mismatched image on row %d\n", i);
1001                         for (j=0; j<(x1-x0)*bpp; j++) {
1002                                 char a_char = *((char*)(p+j*bpp));
1003                                 char b_char = *((char*)(q+j*bpp));
1004                                 printf("%d,%d: %8x %8x %s\n", i, j, a_char, b_char,
1005                                        (a_char != b_char)? " <---": "");
1006                         }
1007                         return false;
1008                 }
1009         }
1010
1011         return true;
1012 }
1013
1014 /** write_surface_as_png()
1015  *
1016  * Writes out a given weston test surface to disk as a PNG image
1017  * using the provided filename (with path).
1018  *
1019  * @returns true if successfully saved file; false otherwise.
1020  */
1021 bool
1022 write_surface_as_png(const struct surface *weston_surface, const char *fname)
1023 {
1024         cairo_surface_t *cairo_surface;
1025         cairo_status_t status;
1026         int bpp = 4; /* Assume ARGB */
1027         int stride = bpp * weston_surface->width;
1028
1029         cairo_surface = cairo_image_surface_create_for_data(weston_surface->data,
1030                                                             CAIRO_FORMAT_ARGB32,
1031                                                             weston_surface->width,
1032                                                             weston_surface->height,
1033                                                             stride);
1034         printf("Writing PNG to disk\n");
1035         status = cairo_surface_write_to_png(cairo_surface, fname);
1036         if (status != CAIRO_STATUS_SUCCESS) {
1037                 printf("Failed to save screenshot: %s\n",
1038                        cairo_status_to_string(status));
1039                 return false;
1040         }
1041         cairo_surface_destroy(cairo_surface);
1042         return true;
1043 }
1044
1045 /** load_surface_from_png()
1046  *
1047  * Reads a PNG image from disk using the given filename (and path)
1048  * and returns as a freshly allocated weston test surface.
1049  *
1050  * @returns weston test surface with image, which should be free'd
1051  * when no longer used; or, NULL in case of error.
1052  */
1053 struct surface *
1054 load_surface_from_png(const char *fname)
1055 {
1056         struct surface *reference;
1057         cairo_surface_t *reference_cairo_surface;
1058         cairo_status_t status;
1059         size_t source_data_size;
1060         int bpp;
1061         int stride;
1062
1063         reference_cairo_surface = cairo_image_surface_create_from_png(fname);
1064         status = cairo_surface_status(reference_cairo_surface);
1065         if (status != CAIRO_STATUS_SUCCESS) {
1066                 printf("Could not open %s: %s\n", fname, cairo_status_to_string(status));
1067                 cairo_surface_destroy(reference_cairo_surface);
1068                 return NULL;
1069         }
1070
1071         /* Disguise the cairo surface in a weston test surface */
1072         reference = zalloc(sizeof *reference);
1073         if (reference == NULL) {
1074                 perror("zalloc reference");
1075                 cairo_surface_destroy(reference_cairo_surface);
1076                 return NULL;
1077         }
1078         reference->width = cairo_image_surface_get_width(reference_cairo_surface);
1079         reference->height = cairo_image_surface_get_height(reference_cairo_surface);
1080         stride = cairo_image_surface_get_stride(reference_cairo_surface);
1081         source_data_size = stride * reference->height;
1082
1083         /* Check that the file's stride matches our assumption */
1084         bpp = 4;
1085         if (stride != bpp * reference->width) {
1086                 printf("Mismatched stride for screenshot reference image %s\n", fname);
1087                 cairo_surface_destroy(reference_cairo_surface);
1088                 free(reference);
1089                 return NULL;
1090         }
1091
1092         /* Allocate new buffer for our weston reference, and copy the data from
1093            the cairo surface so we can destroy it */
1094         reference->data = zalloc(source_data_size);
1095         if (reference->data == NULL) {
1096                 perror("zalloc reference data");
1097                 cairo_surface_destroy(reference_cairo_surface);
1098                 free(reference);
1099                 return NULL;
1100         }
1101         memcpy(reference->data,
1102                cairo_image_surface_get_data(reference_cairo_surface),
1103                source_data_size);
1104
1105         cairo_surface_destroy(reference_cairo_surface);
1106         return reference;
1107 }
1108
1109 /** create_screenshot_surface()
1110  *
1111  *  Allocates and initializes a weston test surface for use in
1112  *  storing a screenshot of the client's output.  Establishes a
1113  *  shm backed wl_buffer for retrieving screenshot image data
1114  *  from the server, sized to match the client's output display.
1115  *
1116  *  @returns stack allocated surface image, which should be
1117  *  free'd when done using it.
1118  */
1119 struct surface *
1120 create_screenshot_surface(struct client *client)
1121 {
1122         struct surface *screenshot;
1123         screenshot = zalloc(sizeof *screenshot);
1124         if (screenshot == NULL)
1125                 return NULL;
1126         screenshot->wl_buffer = create_shm_buffer(client,
1127                                                   client->output->width,
1128                                                   client->output->height,
1129                                                   &screenshot->data);
1130         screenshot->height = client->output->height;
1131         screenshot->width = client->output->width;
1132
1133         return screenshot;
1134 }
1135
1136 /** capture_screenshot_of_output()
1137  *
1138  * Requests a screenshot from the server of the output that the
1139  * client appears on.  The image data returned from the server
1140  * can be accessed from the screenshot surface's data member.
1141  *
1142  * @returns a new surface object, which should be free'd when no
1143  * longer needed.
1144  */
1145 struct surface *
1146 capture_screenshot_of_output(struct client *client)
1147 {
1148         struct surface *screenshot;
1149
1150         /* Create a surface to hold the screenshot */
1151         screenshot = create_screenshot_surface(client);
1152
1153         client->test->buffer_copy_done = 0;
1154         weston_test_capture_screenshot(client->test->weston_test,
1155                                        client->output->wl_output,
1156                                        screenshot->wl_buffer);
1157         while (client->test->buffer_copy_done == 0)
1158                 if (wl_display_dispatch(client->wl_display) < 0)
1159                         break;
1160
1161         /* FIXME: Document somewhere the orientation the screenshot is taken
1162          * and how the clip coords are interpreted, in case of scaling/transform.
1163          * If we're using read_pixels() just make sure it is documented somewhere.
1164          * Protocol docs in the XML, comparison function docs in Doxygen style.
1165          */
1166
1167         return screenshot;
1168 }