downstream: terminal: destroy display at the end.
[profile/ivi/weston-ivi-shell.git] / clients / simple-damage.c
1 /*
2  * Copyright © 2014 Jason Ekstrand
3  * Copyright © 2011 Benjamin Franzke
4  * Copyright © 2010 Intel Corporation
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that copyright
9  * notice and this permission notice appear in supporting documentation, and
10  * that the name of the copyright holders not be used in advertising or
11  * publicity pertaining to distribution of the software without specific,
12  * written prior permission.  The copyright holders make no representations
13  * about the suitability of this software for any purpose.  It is provided "as
14  * is" without express or implied warranty.
15  *
16  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22  * OF THIS SOFTWARE.
23  */
24
25 #include <config.h>
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdbool.h>
31 #include <assert.h>
32 #include <unistd.h>
33 #include <sys/mman.h>
34 #include <sys/time.h>
35 #include <signal.h>
36
37 #include <wayland-client.h>
38 #include "../shared/os-compatibility.h"
39 #include "xdg-shell-client-protocol.h"
40 #include "fullscreen-shell-client-protocol.h"
41 #include "scaler-client-protocol.h"
42
43 int print_debug = 0;
44
45 struct display {
46         struct wl_display *display;
47         struct wl_registry *registry;
48         int compositor_version;
49         struct wl_compositor *compositor;
50         struct wl_scaler *scaler;
51         struct xdg_shell *shell;
52         struct _wl_fullscreen_shell *fshell;
53         struct wl_shm *shm;
54         uint32_t formats;
55 };
56
57 struct buffer {
58         struct wl_buffer *buffer;
59         uint32_t *shm_data;
60         int busy;
61 };
62
63 enum window_flags {
64         WINDOW_FLAG_USE_VIEWPORT = 0x1,
65         WINDOW_FLAG_ROTATING_TRANSFORM = 0x2,
66 };
67
68 struct window {
69         struct display *display;
70         int width, height, border;
71         struct wl_surface *surface;
72         struct wl_viewport *viewport;
73         struct xdg_surface *xdg_surface;
74         struct wl_callback *callback;
75         struct buffer buffers[2];
76         struct buffer *prev_buffer;
77
78         enum window_flags flags;
79         int scale;
80         enum wl_output_transform transform;
81
82         struct {
83                 float x, y; /* position in pixels */
84                 float dx, dy; /* velocity in pixels/second */
85                 int radius; /* radius in pixels */
86                 uint32_t prev_time;
87         } ball;
88 };
89
90 static int running = 1;
91
92 static void
93 buffer_release(void *data, struct wl_buffer *buffer)
94 {
95         struct buffer *mybuf = data;
96
97         mybuf->busy = 0;
98 }
99
100 static const struct wl_buffer_listener buffer_listener = {
101         buffer_release
102 };
103
104 static int
105 create_shm_buffer(struct display *display, struct buffer *buffer,
106                   int width, int height, uint32_t format)
107 {
108         struct wl_shm_pool *pool;
109         int fd, size, pitch;
110         void *data;
111
112         pitch = width * 4;
113         size = pitch * height;
114
115         fd = os_create_anonymous_file(size);
116         if (fd < 0) {
117                 fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
118                         size);
119                 return -1;
120         }
121
122         data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
123         if (data == MAP_FAILED) {
124                 fprintf(stderr, "mmap failed: %m\n");
125                 close(fd);
126                 return -1;
127         }
128
129         pool = wl_shm_create_pool(display->shm, fd, size);
130         buffer->buffer = wl_shm_pool_create_buffer(pool, 0,
131                                                    width, height,
132                                                    pitch, format);
133         wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
134         wl_shm_pool_destroy(pool);
135         close(fd);
136
137         buffer->shm_data = data;
138
139         return 0;
140 }
141
142 static void
143 handle_configure(void *data, struct xdg_surface *surface,
144                  int32_t width, int32_t height, struct wl_array *states,
145                  uint32_t serial)
146 {
147 }
148
149 static void
150 handle_close(void *data, struct xdg_surface *xdg_surface)
151 {
152         running = 0;
153 }
154
155 static const struct xdg_surface_listener xdg_surface_listener = {
156         handle_configure,
157         handle_close,
158 };
159
160 static float
161 bounded_randf(float a, float b)
162 {
163         return a + ((float)rand() / (float)RAND_MAX) * (b - a);
164 }
165
166 static void
167 window_init_game(struct window *window)
168 {
169         int ax1, ay1, ax2, ay2; /* playable arena size */
170         struct timeval tv;
171
172         gettimeofday(&tv, NULL);
173         srand(tv.tv_usec);
174
175         window->ball.radius = 10;
176
177         ax1 = window->border + window->ball.radius;
178         ay1 = window->border + window->ball.radius;
179         ax2 = window->width - window->border - window->ball.radius;
180         ay2 = window->height - window->border - window->ball.radius;
181
182         window->ball.x = bounded_randf(ax1, ax2);
183         window->ball.y = bounded_randf(ay1, ay2);
184
185         window->ball.dx = bounded_randf(0, window->width);
186         window->ball.dy = bounded_randf(0, window->height);
187
188         window->ball.prev_time = 0;
189 }
190
191 static void
192 window_advance_game(struct window *window, uint32_t timestamp)
193 {
194         int ax1, ay1, ax2, ay2; /* Arena size */
195         float dt;
196
197         if (window->ball.prev_time == 0) {
198                 /* first pass, don't do anything */
199                 window->ball.prev_time = timestamp;
200                 return;
201         }
202
203         /* dt in seconds */
204         dt = (float)(timestamp - window->ball.prev_time) / 1000.0f;
205
206         ax1 = window->border + window->ball.radius;
207         ay1 = window->border + window->ball.radius;
208         ax2 = window->width - window->border - window->ball.radius;
209         ay2 = window->height - window->border - window->ball.radius;
210
211         window->ball.x += window->ball.dx * dt;
212         while (window->ball.x < ax1 || ax2 < window->ball.x) {
213                 if (window->ball.x < ax1)
214                         window->ball.x = 2 * ax1 - window->ball.x;
215                 if (ax2 <= window->ball.x)
216                         window->ball.x = 2 * ax2 - window->ball.x;
217
218                 window->ball.dx *= -1.0f;
219         }
220
221         window->ball.y += window->ball.dy * dt;
222         while (window->ball.y < ay1 || ay2 < window->ball.y) {
223                 if (window->ball.y < ay1)
224                         window->ball.y = 2 * ay1 - window->ball.y;
225                 if (ay2 <= window->ball.y)
226                         window->ball.y = 2 * ay2 - window->ball.y;
227
228                 window->ball.dy *= -1.0f;
229         }
230
231         window->ball.prev_time = timestamp;
232 }
233
234 static struct window *
235 create_window(struct display *display, int width, int height,
236               enum wl_output_transform transform, int scale,
237               enum window_flags flags)
238 {
239         struct window *window;
240
241         if (display->compositor_version < 2 &&
242             (transform != WL_OUTPUT_TRANSFORM_NORMAL ||
243              flags & WINDOW_FLAG_ROTATING_TRANSFORM)) {
244                 fprintf(stderr, "wl_surface.buffer_transform unsupported in "
245                                 "wl_surface version %d\n",
246                         display->compositor_version);
247                 exit(1);
248         }
249
250         if (display->compositor_version < 3 &&
251             (! (flags & WINDOW_FLAG_USE_VIEWPORT)) && scale != 1) {
252                 fprintf(stderr, "wl_surface.buffer_scale unsupported in "
253                                 "wl_surface version %d\n",
254                         display->compositor_version);
255                 exit(1);
256         }
257
258         if (display->scaler == NULL && (flags & WINDOW_FLAG_USE_VIEWPORT)) {
259                 fprintf(stderr, "Compositor does not support wl_viewport");
260                 exit(1);
261         }
262
263         window = calloc(1, sizeof *window);
264         if (!window)
265                 return NULL;
266
267         window->callback = NULL;
268         window->display = display;
269         window->width = width;
270         window->height = height;
271         window->border = 10;
272         window->flags = flags;
273         window->transform = transform;
274         window->scale = scale;
275
276         window_init_game(window);
277
278         window->surface = wl_compositor_create_surface(display->compositor);
279
280         if (window->flags & WINDOW_FLAG_USE_VIEWPORT)
281                 window->viewport = wl_scaler_get_viewport(display->scaler,
282                                                           window->surface);
283
284         if (display->shell) {
285                 window->xdg_surface =
286                         xdg_shell_get_xdg_surface(display->shell,
287                                                   window->surface);
288
289                 assert(window->xdg_surface);
290
291                 xdg_surface_add_listener(window->xdg_surface,
292                                          &xdg_surface_listener, window);
293
294                 xdg_surface_set_title(window->xdg_surface, "simple-damage");
295         } else if (display->fshell) {
296                 _wl_fullscreen_shell_present_surface(display->fshell,
297                                                      window->surface,
298                                                      _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT,
299                                                      NULL);
300         } else {
301                 assert(0);
302         }
303
304         /* Initialise damage to full surface, so the padding gets painted */
305         wl_surface_damage(window->surface, 0, 0, INT32_MAX, INT32_MAX);
306
307         return window;
308 }
309
310 static void
311 destroy_window(struct window *window)
312 {
313         if (window->callback)
314                 wl_callback_destroy(window->callback);
315
316         if (window->buffers[0].buffer)
317                 wl_buffer_destroy(window->buffers[0].buffer);
318         if (window->buffers[1].buffer)
319                 wl_buffer_destroy(window->buffers[1].buffer);
320
321         if (window->xdg_surface)
322                 xdg_surface_destroy(window->xdg_surface);
323         if (window->viewport)
324                 wl_viewport_destroy(window->viewport);
325         wl_surface_destroy(window->surface);
326         free(window);
327 }
328
329 static struct buffer *
330 window_next_buffer(struct window *window)
331 {
332         struct buffer *buffer;
333         int ret = 0, bwidth, bheight;
334
335         if (!window->buffers[0].busy)
336                 buffer = &window->buffers[0];
337         else if (!window->buffers[1].busy)
338                 buffer = &window->buffers[1];
339         else
340                 return NULL;
341
342         switch (window->transform) {
343         default:
344         case WL_OUTPUT_TRANSFORM_NORMAL:
345         case WL_OUTPUT_TRANSFORM_180:
346         case WL_OUTPUT_TRANSFORM_FLIPPED:
347         case WL_OUTPUT_TRANSFORM_FLIPPED_180:
348                 bwidth = window->width * window->scale;
349                 bheight = window->height * window->scale;
350                 break;
351         case WL_OUTPUT_TRANSFORM_90:
352         case WL_OUTPUT_TRANSFORM_270:
353         case WL_OUTPUT_TRANSFORM_FLIPPED_90:
354         case WL_OUTPUT_TRANSFORM_FLIPPED_270:
355                 bwidth = window->height * window->scale;
356                 bheight = window->width * window->scale;
357                 break;
358         }
359
360         if (!buffer->buffer) {
361                 ret = create_shm_buffer(window->display, buffer,
362                                         bwidth, bheight,
363                                         WL_SHM_FORMAT_ARGB8888);
364
365                 if (ret < 0)
366                         return NULL;
367         }
368
369         return buffer;
370 }
371
372 static void
373 paint_box(uint32_t *pixels, int pitch, int x, int y, int width, int height,
374           uint32_t color)
375 {
376         int i, j;
377
378         for (j = y; j < y + height; ++j)
379                 for (i = x; i < x + width; ++i)
380                         pixels[i + j * pitch] = color;
381 }
382
383 static void
384 paint_circle(uint32_t *pixels, int pitch, float x, float y, int radius,
385              uint32_t color)
386 {
387         int i, j;
388
389         for (j = y - radius; j <= (int)(y + radius); ++j)
390                 for (i = x - radius; i <= (int)(x + radius); ++i)
391                         if ((j+0.5f-y)*(j+0.5f-y) + (i+0.5f-x)*(i+0.5f-x) <= radius * radius)
392                                 pixels[i + j * pitch] = color;
393 }
394
395 static void
396 window_get_transformed_ball(struct window *window, float *bx, float *by)
397 {
398         float wx, wy;
399
400         wx = window->ball.x;
401         wy = window->ball.y;
402
403         switch (window->transform) {
404         default:
405         case WL_OUTPUT_TRANSFORM_NORMAL:
406                 *bx = wx;
407                 *by = wy;
408                 break;
409         case WL_OUTPUT_TRANSFORM_90:
410                 *bx = window->height - wy;
411                 *by = wx;
412                 break;
413         case WL_OUTPUT_TRANSFORM_180:
414                 *bx = window->width - wx;
415                 *by = window->height - wy;
416                 break;
417         case WL_OUTPUT_TRANSFORM_270:
418                 *bx = wy;
419                 *by = window->width - wx;
420                 break;
421         case WL_OUTPUT_TRANSFORM_FLIPPED:
422                 *bx = window->width - wx;
423                 *by = wy;
424                 break;
425         case WL_OUTPUT_TRANSFORM_FLIPPED_90:
426                 *bx = window->height - wy;
427                 *by = window->width - wx;
428                 break;
429         case WL_OUTPUT_TRANSFORM_FLIPPED_180:
430                 *bx = wx;
431                 *by = window->height - wy;
432                 break;
433         case WL_OUTPUT_TRANSFORM_FLIPPED_270:
434                 *bx = wy;
435                 *by = wx;
436                 break;
437         }
438
439         *bx *= window->scale;
440         *by *= window->scale;
441
442         if (window->viewport) {
443                 /* We're drawing half-size because of the viewport */
444                 *bx /= 2;
445                 *by /= 2;
446         }
447 }
448
449 static const struct wl_callback_listener frame_listener;
450
451 static void
452 redraw(void *data, struct wl_callback *callback, uint32_t time)
453 {
454         struct window *window = data;
455         struct buffer *buffer;
456         int off_x, off_y, bwidth, bheight, bborder, bpitch, bradius;
457         uint32_t *buffer_data;
458         float bx, by;
459
460         buffer = window_next_buffer(window);
461         if (!buffer) {
462                 fprintf(stderr,
463                         !callback ? "Failed to create the first buffer.\n" :
464                         "Both buffers busy at redraw(). Server bug?\n");
465                 abort();
466         }
467
468         /* Rotate the damage, but keep the even/odd parity so the
469          * dimensions of the buffers don't change */
470         if (window->flags & WINDOW_FLAG_ROTATING_TRANSFORM)
471                 window->transform = (window->transform + 2) % 8;
472
473         switch (window->transform) {
474         default:
475         case WL_OUTPUT_TRANSFORM_NORMAL:
476         case WL_OUTPUT_TRANSFORM_180:
477         case WL_OUTPUT_TRANSFORM_FLIPPED:
478         case WL_OUTPUT_TRANSFORM_FLIPPED_180:
479                 bwidth = window->width * window->scale;
480                 bheight = window->height * window->scale;
481                 break;
482         case WL_OUTPUT_TRANSFORM_90:
483         case WL_OUTPUT_TRANSFORM_270:
484         case WL_OUTPUT_TRANSFORM_FLIPPED_90:
485         case WL_OUTPUT_TRANSFORM_FLIPPED_270:
486                 bwidth = window->height * window->scale;
487                 bheight = window->width * window->scale;
488                 break;
489         }
490
491         bpitch = bwidth;
492
493         bborder = window->border * window->scale;
494         bradius = window->ball.radius * window->scale;
495
496         buffer_data = buffer->shm_data;
497         if (window->viewport) {
498                 /* Fill the whole thing with red to detect viewport errors */
499                 paint_box(buffer->shm_data, bpitch, 0, 0, bwidth, bheight,
500                           0xffff0000);
501
502                 /* The buffer is the same size.  However, we crop it
503                  * and scale it up by a factor of 2 */
504                 bborder /= 2;
505                 bradius /= 2;
506                 bwidth /= 2;
507                 bheight /= 2;
508
509                 /* Offset the drawing region */
510                 off_x = (window->width / 3) * window->scale;
511                 off_y = (window->height / 5) * window->scale;
512                 switch (window->transform) {
513                 default:
514                 case WL_OUTPUT_TRANSFORM_NORMAL:
515                         buffer_data += off_y * bpitch + off_x;
516                         break;
517                 case WL_OUTPUT_TRANSFORM_90:
518                         buffer_data += off_x * bpitch + (bwidth - off_y);
519                         break;
520                 case WL_OUTPUT_TRANSFORM_180:
521                         buffer_data += (bheight - off_y) * bpitch +
522                                        (bwidth - off_x);
523                         break;
524                 case WL_OUTPUT_TRANSFORM_270:
525                         buffer_data += (bheight - off_x) * bpitch + off_y;
526                         break;
527                 case WL_OUTPUT_TRANSFORM_FLIPPED:
528                         buffer_data += off_y * bpitch + (bwidth - off_x);
529                         break;
530                 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
531                         buffer_data += (bheight - off_x) * bpitch +
532                                        (bwidth - off_y);
533                         break;
534                 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
535                         buffer_data += (bheight - off_y) * bpitch + off_x;
536                         break;
537                 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
538                         buffer_data += off_x * bpitch + off_y;
539                         break;
540                 }
541                 wl_viewport_set_source(window->viewport,
542                                        wl_fixed_from_int(window->width / 3),
543                                        wl_fixed_from_int(window->height / 5),
544                                        wl_fixed_from_int(window->width / 2),
545                                        wl_fixed_from_int(window->height / 2));
546         }
547
548         /* Paint the border */
549         paint_box(buffer_data, bpitch, 0, 0, bwidth, bborder, 0xffffffff);
550         paint_box(buffer_data, bpitch, 0, 0, bborder, bheight, 0xffffffff);
551         paint_box(buffer_data, bpitch,
552                   bwidth - bborder, 0, bborder, bheight, 0xffffffff);
553         paint_box(buffer_data, bpitch,
554                   0, bheight - bborder, bwidth, bborder, 0xffffffff);
555
556         /* fill with translucent */
557         paint_box(buffer_data, bpitch, bborder, bborder,
558                   bwidth - 2 * bborder, bheight - 2 * bborder, 0x80000000);
559
560         /* Damage where the ball was */
561         wl_surface_damage(window->surface,
562                           window->ball.x - window->ball.radius,
563                           window->ball.y - window->ball.radius,
564                           window->ball.radius * 2 + 1,
565                           window->ball.radius * 2 + 1);
566
567         window_advance_game(window, time);
568
569         window_get_transformed_ball(window, &bx, &by);
570
571         /* Paint the ball */
572         paint_circle(buffer_data, bpitch, bx, by, bradius, 0xff00ff00);
573
574         if (print_debug) {
575                 printf("Ball now located at (%f, %f)\n",
576                        window->ball.x, window->ball.y);
577
578                 printf("Circle painted at (%f, %f), radius %d\n", bx, by,
579                        bradius);
580
581                 printf("Buffer damage rectangle: (%d, %d) @ %dx%d\n",
582                        (int)(bx - bradius), (int)(by - bradius),
583                        bradius * 2 + 1, bradius * 2 + 1);
584         }
585
586         /* Damage where the ball is now */
587         wl_surface_damage(window->surface,
588                           window->ball.x - window->ball.radius,
589                           window->ball.y - window->ball.radius,
590                           window->ball.radius * 2 + 1,
591                           window->ball.radius * 2 + 1);
592
593         wl_surface_attach(window->surface, buffer->buffer, 0, 0);
594
595         if (window->display->compositor_version >= 2 &&
596             (window->transform != WL_OUTPUT_TRANSFORM_NORMAL ||
597              window->flags & WINDOW_FLAG_ROTATING_TRANSFORM))
598                 wl_surface_set_buffer_transform(window->surface,
599                                                 window->transform);
600
601         if (window->viewport)
602                 wl_viewport_set_destination(window->viewport,
603                                             window->width,
604                                             window->height);
605
606         if (window->scale != 1)
607                 wl_surface_set_buffer_scale(window->surface,
608                                             window->scale);
609
610         if (callback)
611                 wl_callback_destroy(callback);
612
613         window->callback = wl_surface_frame(window->surface);
614         wl_callback_add_listener(window->callback, &frame_listener, window);
615         wl_surface_commit(window->surface);
616         buffer->busy = 1;
617 }
618
619 static const struct wl_callback_listener frame_listener = {
620         redraw
621 };
622
623 static void
624 shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
625 {
626         struct display *d = data;
627
628         d->formats |= (1 << format);
629 }
630
631 struct wl_shm_listener shm_listener = {
632         shm_format
633 };
634
635 static void
636 xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial)
637 {
638         xdg_shell_pong(shell, serial);
639 }
640
641 static const struct xdg_shell_listener xdg_shell_listener = {
642         xdg_shell_ping,
643 };
644
645 #define XDG_VERSION 4 /* The version of xdg-shell that we implement */
646 #ifdef static_assert
647 static_assert(XDG_VERSION == XDG_SHELL_VERSION_CURRENT,
648               "Interface version doesn't match implementation version");
649 #endif
650
651 static void
652 registry_handle_global(void *data, struct wl_registry *registry,
653                        uint32_t id, const char *interface, uint32_t version)
654 {
655         struct display *d = data;
656
657         if (strcmp(interface, "wl_compositor") == 0) {
658                 if (d->compositor_version > (int)version) {
659                         fprintf(stderr, "Compositor does not support "
660                                 "wl_surface version %d\n", d->compositor_version);
661                         exit(1);
662                 }
663
664                 if (d->compositor_version < 0)
665                         d->compositor_version = version;
666
667                 d->compositor =
668                         wl_registry_bind(registry,
669                                          id, &wl_compositor_interface,
670                                          d->compositor_version);
671         } else if (strcmp(interface, "wl_scaler") == 0 && version >= 2) {
672                 d->scaler = wl_registry_bind(registry,
673                                              id, &wl_scaler_interface, 2);
674         } else if (strcmp(interface, "xdg_shell") == 0) {
675                 d->shell = wl_registry_bind(registry,
676                                             id, &xdg_shell_interface, 1);
677                 xdg_shell_use_unstable_version(d->shell, XDG_VERSION);
678                 xdg_shell_add_listener(d->shell, &xdg_shell_listener, d);
679         } else if (strcmp(interface, "_wl_fullscreen_shell") == 0) {
680                 d->fshell = wl_registry_bind(registry,
681                                              id, &_wl_fullscreen_shell_interface, 1);
682         } else if (strcmp(interface, "wl_shm") == 0) {
683                 d->shm = wl_registry_bind(registry,
684                                           id, &wl_shm_interface, 1);
685                 wl_shm_add_listener(d->shm, &shm_listener, d);
686         }
687 }
688
689 static void
690 registry_handle_global_remove(void *data, struct wl_registry *registry,
691                               uint32_t name)
692 {
693 }
694
695 static const struct wl_registry_listener registry_listener = {
696         registry_handle_global,
697         registry_handle_global_remove
698 };
699
700 static struct display *
701 create_display(int version)
702 {
703         struct display *display;
704
705         display = malloc(sizeof *display);
706         if (display == NULL) {
707                 fprintf(stderr, "out of memory\n");
708                 exit(1);
709         }
710         display->display = wl_display_connect(NULL);
711         assert(display->display);
712
713         display->compositor_version = version;
714         display->formats = 0;
715         display->registry = wl_display_get_registry(display->display);
716         wl_registry_add_listener(display->registry,
717                                  &registry_listener, display);
718         wl_display_roundtrip(display->display);
719         if (display->shm == NULL) {
720                 fprintf(stderr, "No wl_shm global\n");
721                 exit(1);
722         }
723
724         wl_display_roundtrip(display->display);
725
726         if (!(display->formats & (1 << WL_SHM_FORMAT_XRGB8888))) {
727                 fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
728                 exit(1);
729         }
730
731         return display;
732 }
733
734 static void
735 destroy_display(struct display *display)
736 {
737         if (display->shm)
738                 wl_shm_destroy(display->shm);
739
740         if (display->shell)
741                 xdg_shell_destroy(display->shell);
742
743         if (display->fshell)
744                 _wl_fullscreen_shell_release(display->fshell);
745
746         if (display->scaler)
747                 wl_scaler_destroy(display->scaler);
748
749         if (display->compositor)
750                 wl_compositor_destroy(display->compositor);
751
752         wl_registry_destroy(display->registry);
753         wl_display_flush(display->display);
754         wl_display_disconnect(display->display);
755         free(display);
756 }
757
758 static void
759 signal_int(int signum)
760 {
761         running = 0;
762 }
763
764 static void
765 print_usage(int retval)
766 {
767         printf(
768                 "usage: weston-simple-damage [options]\n\n"
769                 "options:\n"
770                 "  -h, --help\t\tPring this help\n"
771                 "  --verbose\t\tPrint verbose log information\n"
772                 "  --version=VERSION\tVersion of wl_surface to use\n"
773                 "  --width=WIDTH\t\tWidth of the window\n"
774                 "  --height=HEIGHT\tHeight of the window\n"
775                 "  --scale=SCALE\t\tScale factor for the surface\n"
776                 "  --transform=TRANSFORM\tTransform for the surface\n"
777                 "  --rotating-transform\tUse a different buffer_transform for each frame\n"
778                 "  --use-viewport\tUse wl_viewport\n"
779         );
780
781         exit(retval);
782 }
783
784 static int
785 parse_transform(const char *str, enum wl_output_transform *transform)
786 {
787         int i;
788         static const struct {
789                 const char *name;
790                 enum wl_output_transform transform;
791         } names[] = {
792                 { "normal",     WL_OUTPUT_TRANSFORM_NORMAL },
793                 { "90",         WL_OUTPUT_TRANSFORM_90 },
794                 { "180",        WL_OUTPUT_TRANSFORM_180 },
795                 { "270",        WL_OUTPUT_TRANSFORM_270 },
796                 { "flipped",    WL_OUTPUT_TRANSFORM_FLIPPED },
797                 { "flipped-90", WL_OUTPUT_TRANSFORM_FLIPPED_90 },
798                 { "flipped-180", WL_OUTPUT_TRANSFORM_FLIPPED_180 },
799                 { "flipped-270", WL_OUTPUT_TRANSFORM_FLIPPED_270 },
800         };
801
802         for (i = 0; i < 8; i++) {
803                 if (strcmp(names[i].name, str) == 0) {
804                         *transform = names[i].transform;
805                         return 1;
806                 }
807         }
808
809         return 0;
810 }
811
812 int
813 main(int argc, char **argv)
814 {
815         struct sigaction sigint;
816         struct display *display;
817         struct window *window;
818         int i, ret = 0;
819         int version = -1;
820         int width = 300, height = 200, scale = 1;
821         enum wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
822         enum window_flags flags = 0;
823
824         for (i = 1; i < argc; ++i) {
825                 if (strcmp(argv[i], "--help") == 0 ||
826                     strcmp(argv[i], "-h") == 0) {
827                         print_usage(0);
828                 } else if (sscanf(argv[i], "--version=%d", &version) > 0) {
829                         if (version < 1 || version > 3) {
830                                 fprintf(stderr, "Unsupported wl_surface version: %d\n",
831                                         version);
832                                 return 1;
833                         }
834                         continue;
835                 } else if (strcmp(argv[i], "--verbose") == 0) {
836                         print_debug = 1;
837                         continue;
838                 } else if (sscanf(argv[i], "--width=%d", &width) > 0) {
839                         continue;
840                 } else if (sscanf(argv[i], "--height=%d", &height) > 0) {
841                         continue;
842                 } else if (strncmp(argv[i], "--transform=", 12) == 0 &&
843                            parse_transform(argv[i] + 12, &transform) > 0) {
844                         continue;
845                 } else if (strcmp(argv[i], "--rotating-transform") == 0) {
846                         flags |= WINDOW_FLAG_ROTATING_TRANSFORM;
847                         continue;
848                 } else if (sscanf(argv[i], "--scale=%d", &scale) > 0) {
849                         continue;
850                 } else if (strcmp(argv[i], "--use-viewport") == 0) {
851                         flags |= WINDOW_FLAG_USE_VIEWPORT;
852                         continue;
853                 } else {
854                         printf("Invalid option: %s\n", argv[i]);
855                         print_usage(255);
856                 }
857         }
858
859         display = create_display(version);
860
861         window = create_window(display, width, height, transform, scale, flags);
862         if (!window)
863                 return 1;
864
865         sigint.sa_handler = signal_int;
866         sigemptyset(&sigint.sa_mask);
867         sigint.sa_flags = SA_RESETHAND;
868         sigaction(SIGINT, &sigint, NULL);
869
870         redraw(window, NULL, 0);
871
872         while (running && ret != -1)
873                 ret = wl_display_dispatch(display->display);
874
875         fprintf(stderr, "simple-shm exiting\n");
876         destroy_window(window);
877         destroy_display(display);
878
879         return 0;
880 }