compositor-x11: Rename the output make to "weston-X11"
[platform/upstream/weston.git] / clients / subsurfaces.c
1 /*
2  * Copyright © 2010 Intel Corporation
3  * Copyright © 2011 Benjamin Franzke
4  * Copyright © 2012-2013 Collabora, Ltd.
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 <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <cairo.h>
32 #include <math.h>
33 #include <assert.h>
34
35 #include <linux/input.h>
36 #include <wayland-client.h>
37
38 #include <wayland-egl.h>
39 #include <GLES2/gl2.h>
40 #include <EGL/egl.h>
41
42 #include "window.h"
43
44 #if 0
45 #define DBG(fmt, ...) \
46         fprintf(stderr, "%d:%s " fmt, __LINE__, __func__, ##__VA_ARGS__)
47 #else
48 #define DBG(...) do {} while (0)
49 #endif
50
51 static int32_t option_red_mode;
52 static int32_t option_triangle_mode;
53 static int32_t option_no_triangle;
54 static int32_t option_help;
55
56 static const struct weston_option options[] = {
57         { WESTON_OPTION_INTEGER, "red-mode", 'r', &option_red_mode },
58         { WESTON_OPTION_INTEGER, "triangle-mode", 't', &option_triangle_mode },
59         { WESTON_OPTION_BOOLEAN, "no-triangle", 'n', &option_no_triangle },
60         { WESTON_OPTION_BOOLEAN, "help", 'h', &option_help },
61 };
62
63 static enum subsurface_mode
64 int_to_mode(int32_t i)
65 {
66         switch (i) {
67         case 0:
68                 return SUBSURFACE_DESYNCHRONIZED;
69         case 1:
70                 return SUBSURFACE_SYNCHRONIZED;
71         default:
72                 fprintf(stderr, "error: %d is not a valid commit mode.\n", i);
73                 exit(1);
74         }
75 }
76
77 static const char help_text[] =
78 "Usage: %s [options]\n"
79 "\n"
80 "  -r, --red-mode=MODE\t\tthe commit mode for the red sub-surface (0)\n"
81 "  -t, --triangle-mode=MODE\tthe commit mode for the GL sub-surface (0)\n"
82 "  -n, --no-triangle\t\tDo not create the GL sub-surface.\n"
83 "\n"
84 "The MODE is the wl_subsurface commit mode used by default for the\n"
85 "given sub-surface. Valid values are the integers:\n"
86 "   0\tfor desynchronized, i.e. free-running\n"
87 "   1\tfor synchronized\n"
88 "\n"
89 "This program demonstrates sub-surfaces with the toytoolkit.\n"
90 "The main surface contains the decorations, a green canvas, and a\n"
91 "green spinner. One sub-surface is red with a red spinner. These\n"
92 "are rendered with Cairo. The other sub-surface contains a spinning\n"
93 "triangle rendered in EGL/GLESv2, without Cairo, i.e. it is a raw GL\n"
94 "widget.\n"
95 "\n"
96 "The GL widget animates on its own. The spinners follow wall clock\n"
97 "time and update only when their surface is repainted, so you see\n"
98 "which surfaces get redrawn. The red sub-surface animates on its own,\n"
99 "but can be toggled with the spacebar.\n"
100 "\n"
101 "Even though the sub-surfaces attempt to animate on their own, they\n"
102 "are subject to the commit mode. If commit mode is synchronized,\n"
103 "they will need a commit on the main surface to actually display.\n"
104 "You can trigger a main surface repaint, without a resize, by\n"
105 "hovering the pointer over the title bar buttons.\n"
106 "\n"
107 "Resizing will temporarily toggle the commit mode of all sub-surfaces\n"
108 "to guarantee synchronized rendering on size changes. It also forces\n"
109 "a repaint of all surfaces.\n"
110 "\n"
111 "Using -t1 -r1 is especially useful for trying to catch inconsistent\n"
112 "rendering and deadlocks, since free-running sub-surfaces would\n"
113 "immediately hide the problem.\n"
114 "\n"
115 "Key controls:\n"
116 "  space - toggle red sub-surface animation loop\n"
117 "  up    - step window size shorter\n"
118 "  down  - step window size taller\n"
119 "\n";
120
121 struct egl_state {
122         EGLDisplay dpy;
123         EGLContext ctx;
124         EGLConfig conf;
125 };
126
127 struct triangle_gl_state {
128         GLuint rotation_uniform;
129         GLuint pos;
130         GLuint col;
131 };
132
133 struct triangle {
134         struct egl_state *egl;
135
136         struct wl_surface *wl_surface;
137         struct wl_egl_window *egl_window;
138         EGLSurface egl_surface;
139         int width;
140         int height;
141
142         struct triangle_gl_state gl;
143
144         struct widget *widget;
145         uint32_t time;
146         struct wl_callback *frame_cb;
147 };
148
149 /******** Pure EGL/GLESv2/libwayland-client component: ***************/
150
151 static const char *vert_shader_text =
152         "uniform mat4 rotation;\n"
153         "attribute vec4 pos;\n"
154         "attribute vec4 color;\n"
155         "varying vec4 v_color;\n"
156         "void main() {\n"
157         "  gl_Position = rotation * pos;\n"
158         "  v_color = color;\n"
159         "}\n";
160
161 static const char *frag_shader_text =
162         "precision mediump float;\n"
163         "varying vec4 v_color;\n"
164         "void main() {\n"
165         "  gl_FragColor = v_color;\n"
166         "}\n";
167
168 static void
169 egl_print_config_info(struct egl_state *egl)
170 {
171         EGLint r, g, b, a;
172
173         printf("Chosen EGL config details:\n");
174
175         printf("\tRGBA bits");
176         if (eglGetConfigAttrib(egl->dpy, egl->conf, EGL_RED_SIZE, &r) &&
177             eglGetConfigAttrib(egl->dpy, egl->conf, EGL_GREEN_SIZE, &g) &&
178             eglGetConfigAttrib(egl->dpy, egl->conf, EGL_BLUE_SIZE, &b) &&
179             eglGetConfigAttrib(egl->dpy, egl->conf, EGL_ALPHA_SIZE, &a))
180                 printf(": %d %d %d %d\n", r, g, b, a);
181         else
182                 printf(" unknown\n");
183
184         printf("\tswap interval range");
185         if (eglGetConfigAttrib(egl->dpy, egl->conf, EGL_MIN_SWAP_INTERVAL, &a) &&
186             eglGetConfigAttrib(egl->dpy, egl->conf, EGL_MAX_SWAP_INTERVAL, &b))
187                 printf(": %d - %d\n", a, b);
188         else
189                 printf(" unknown\n");
190 }
191
192 static struct egl_state *
193 egl_state_create(struct wl_display *display)
194 {
195         struct egl_state *egl;
196
197         static const EGLint context_attribs[] = {
198                 EGL_CONTEXT_CLIENT_VERSION, 2,
199                 EGL_NONE
200         };
201
202         EGLint config_attribs[] = {
203                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
204                 EGL_RED_SIZE, 1,
205                 EGL_GREEN_SIZE, 1,
206                 EGL_BLUE_SIZE, 1,
207                 EGL_ALPHA_SIZE, 1,
208                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
209                 EGL_NONE
210         };
211
212         EGLint major, minor, n;
213         EGLBoolean ret;
214
215         egl = calloc(1, sizeof *egl);
216         assert(egl);
217
218         egl->dpy = eglGetDisplay(display);
219         assert(egl->dpy);
220
221         ret = eglInitialize(egl->dpy, &major, &minor);
222         assert(ret == EGL_TRUE);
223         ret = eglBindAPI(EGL_OPENGL_ES_API);
224         assert(ret == EGL_TRUE);
225
226         ret = eglChooseConfig(egl->dpy, config_attribs, &egl->conf, 1, &n);
227         assert(ret && n == 1);
228
229         egl->ctx = eglCreateContext(egl->dpy, egl->conf,
230                                     EGL_NO_CONTEXT, context_attribs);
231         assert(egl->ctx);
232         egl_print_config_info(egl);
233
234         return egl;
235 }
236
237 static void
238 egl_state_destroy(struct egl_state *egl)
239 {
240         /* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
241          * on eglReleaseThread(). */
242         eglMakeCurrent(egl->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
243                        EGL_NO_CONTEXT);
244
245         eglTerminate(egl->dpy);
246         eglReleaseThread();
247         free(egl);
248 }
249
250 static void
251 egl_make_swapbuffers_nonblock(struct egl_state *egl)
252 {
253         EGLint a = EGL_MIN_SWAP_INTERVAL;
254         EGLint b = EGL_MAX_SWAP_INTERVAL;
255
256         if (!eglGetConfigAttrib(egl->dpy, egl->conf, a, &a) ||
257             !eglGetConfigAttrib(egl->dpy, egl->conf, b, &b)) {
258                 fprintf(stderr, "warning: swap interval range unknown\n");
259         } else
260         if (a > 0) {
261                 fprintf(stderr, "warning: minimum swap interval is %d, "
262                         "while 0 is required to not deadlock on resize.\n", a);
263         }
264
265         /*
266          * We rely on the Wayland compositor to sync to vblank anyway.
267          * We just need to be able to call eglSwapBuffers() without the
268          * risk of waiting for a frame callback in it.
269          */
270         if (!eglSwapInterval(egl->dpy, 0)) {
271                 fprintf(stderr, "error: eglSwapInterval() failed.\n");
272         }
273 }
274
275 static GLuint
276 create_shader(const char *source, GLenum shader_type)
277 {
278         GLuint shader;
279         GLint status;
280
281         shader = glCreateShader(shader_type);
282         assert(shader != 0);
283
284         glShaderSource(shader, 1, (const char **) &source, NULL);
285         glCompileShader(shader);
286
287         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
288         if (!status) {
289                 char log[1000];
290                 GLsizei len;
291                 glGetShaderInfoLog(shader, 1000, &len, log);
292                 fprintf(stderr, "Error: compiling %s: %*s\n",
293                         shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
294                         len, log);
295                 exit(1);
296         }
297
298         return shader;
299 }
300
301 static void
302 triangle_init_gl(struct triangle_gl_state *trigl)
303 {
304         GLuint frag, vert;
305         GLuint program;
306         GLint status;
307
308         frag = create_shader(frag_shader_text, GL_FRAGMENT_SHADER);
309         vert = create_shader(vert_shader_text, GL_VERTEX_SHADER);
310
311         program = glCreateProgram();
312         glAttachShader(program, frag);
313         glAttachShader(program, vert);
314         glLinkProgram(program);
315
316         glGetProgramiv(program, GL_LINK_STATUS, &status);
317         if (!status) {
318                 char log[1000];
319                 GLsizei len;
320                 glGetProgramInfoLog(program, 1000, &len, log);
321                 fprintf(stderr, "Error: linking:\n%*s\n", len, log);
322                 exit(1);
323         }
324
325         glUseProgram(program);
326
327         trigl->pos = 0;
328         trigl->col = 1;
329
330         glBindAttribLocation(program, trigl->pos, "pos");
331         glBindAttribLocation(program, trigl->col, "color");
332         glLinkProgram(program);
333
334         trigl->rotation_uniform = glGetUniformLocation(program, "rotation");
335 }
336
337 static void
338 triangle_draw(const struct triangle_gl_state *trigl, uint32_t time)
339 {
340         static const GLfloat verts[3][2] = {
341                 { -0.5, -0.5 },
342                 {  0.5, -0.5 },
343                 {  0,    0.5 }
344         };
345         static const GLfloat colors[3][3] = {
346                 { 1, 0, 0 },
347                 { 0, 1, 0 },
348                 { 0, 0, 1 }
349         };
350         GLfloat angle;
351         GLfloat rotation[4][4] = {
352                 { 1, 0, 0, 0 },
353                 { 0, 1, 0, 0 },
354                 { 0, 0, 1, 0 },
355                 { 0, 0, 0, 1 }
356         };
357         static const int32_t speed_div = 5;
358
359         angle = (time / speed_div) % 360 * M_PI / 180.0;
360         rotation[0][0] =  cos(angle);
361         rotation[0][2] =  sin(angle);
362         rotation[2][0] = -sin(angle);
363         rotation[2][2] =  cos(angle);
364
365         glUniformMatrix4fv(trigl->rotation_uniform, 1, GL_FALSE,
366                            (GLfloat *) rotation);
367
368         glClearColor(0.0, 0.0, 0.0, 0.5);
369         glClear(GL_COLOR_BUFFER_BIT);
370
371         glVertexAttribPointer(trigl->pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
372         glVertexAttribPointer(trigl->col, 3, GL_FLOAT, GL_FALSE, 0, colors);
373         glEnableVertexAttribArray(trigl->pos);
374         glEnableVertexAttribArray(trigl->col);
375
376         glDrawArrays(GL_TRIANGLES, 0, 3);
377
378         glDisableVertexAttribArray(trigl->pos);
379         glDisableVertexAttribArray(trigl->col);
380 }
381
382 static void
383 triangle_frame_callback(void *data, struct wl_callback *callback,
384                         uint32_t time);
385
386 static const struct wl_callback_listener triangle_frame_listener = {
387         triangle_frame_callback
388 };
389
390 static void
391 triangle_frame_callback(void *data, struct wl_callback *callback,
392                         uint32_t time)
393 {
394         struct triangle *tri = data;
395
396         DBG("%stime %u\n", callback ? "" : "artificial ", time);
397         assert(callback == tri->frame_cb);
398         tri->time = time;
399
400         if (callback)
401                 wl_callback_destroy(callback);
402
403         eglMakeCurrent(tri->egl->dpy, tri->egl_surface,
404                                    tri->egl_surface, tri->egl->ctx);
405
406         glViewport(0, 0, tri->width, tri->height);
407
408         triangle_draw(&tri->gl, tri->time);
409
410         tri->frame_cb = wl_surface_frame(tri->wl_surface);
411         wl_callback_add_listener(tri->frame_cb, &triangle_frame_listener, tri);
412
413         eglSwapBuffers(tri->egl->dpy, tri->egl_surface);
414 }
415
416 static void
417 triangle_create_egl_surface(struct triangle *tri, int width, int height)
418 {
419         EGLBoolean ret;
420
421         tri->wl_surface = widget_get_wl_surface(tri->widget);
422         tri->egl_window = wl_egl_window_create(tri->wl_surface, width, height);
423         tri->egl_surface = eglCreateWindowSurface(tri->egl->dpy,
424                                                   tri->egl->conf,
425                                                   tri->egl_window, NULL);
426
427         ret = eglMakeCurrent(tri->egl->dpy, tri->egl_surface,
428                              tri->egl_surface, tri->egl->ctx);
429         assert(ret == EGL_TRUE);
430
431         egl_make_swapbuffers_nonblock(tri->egl);
432         triangle_init_gl(&tri->gl);
433 }
434
435 /********* The widget code interfacing the toolkit agnostic code: **********/
436
437 static void
438 triangle_resize_handler(struct widget *widget,
439                         int32_t width, int32_t height, void *data)
440 {
441         struct triangle *tri = data;
442
443         DBG("to %dx%d\n", width, height);
444         tri->width = width;
445         tri->height = height;
446
447         if (tri->egl_surface) {
448                 wl_egl_window_resize(tri->egl_window, width, height, 0, 0);
449         } else {
450                 triangle_create_egl_surface(tri, width, height);
451                 triangle_frame_callback(tri, NULL, 0);
452         }
453 }
454
455 static void
456 triangle_redraw_handler(struct widget *widget, void *data)
457 {
458         struct triangle *tri = data;
459         int w, h;
460
461         wl_egl_window_get_attached_size(tri->egl_window, &w, &h);
462
463         DBG("previous %dx%d, new %dx%d\n", w, h, tri->width, tri->height);
464
465         /* If size is not changing, do not redraw ahead of time.
466          * That would risk blocking in eglSwapbuffers().
467          */
468         if (w == tri->width && h == tri->height)
469                 return;
470
471         if (tri->frame_cb) {
472                 wl_callback_destroy(tri->frame_cb);
473                 tri->frame_cb = NULL;
474         }
475         triangle_frame_callback(tri, NULL, tri->time);
476 }
477
478 static void
479 set_empty_input_region(struct widget *widget, struct display *display)
480 {
481         struct wl_compositor *compositor;
482         struct wl_surface *surface;
483         struct wl_region *region;
484
485         compositor = display_get_compositor(display);
486         surface = widget_get_wl_surface(widget);
487         region = wl_compositor_create_region(compositor);
488         wl_surface_set_input_region(surface, region);
489         wl_region_destroy(region);
490 }
491
492 static struct triangle *
493 triangle_create(struct window *window, struct egl_state *egl)
494 {
495         struct triangle *tri;
496
497         tri = xmalloc(sizeof *tri);
498         memset(tri, 0, sizeof *tri);
499
500         tri->egl = egl;
501         tri->widget = window_add_subsurface(window, tri,
502                 int_to_mode(option_triangle_mode));
503         widget_set_use_cairo(tri->widget, 0);
504         widget_set_resize_handler(tri->widget, triangle_resize_handler);
505         widget_set_redraw_handler(tri->widget, triangle_redraw_handler);
506
507         set_empty_input_region(tri->widget, window_get_display(window));
508
509         return tri;
510 }
511
512 static void
513 triangle_destroy(struct triangle *tri)
514 {
515         if (tri->egl_surface)
516                 eglDestroySurface(tri->egl->dpy, tri->egl_surface);
517
518         if (tri->egl_window)
519                 wl_egl_window_destroy(tri->egl_window);
520
521         widget_destroy(tri->widget);
522         free(tri);
523 }
524
525 /************** The toytoolkit application code: *********************/
526
527 struct demoapp {
528         struct display *display;
529         struct window *window;
530         struct widget *widget;
531         struct widget *subsurface;
532
533         struct egl_state *egl;
534         struct triangle *triangle;
535
536         int animate;
537 };
538
539 static void
540 draw_spinner(cairo_t *cr, const struct rectangle *rect, uint32_t time)
541 {
542         double cx, cy, r, angle;
543         unsigned t;
544
545         cx = rect->x + rect->width / 2;
546         cy = rect->y + rect->height / 2;
547         r = (rect->width < rect->height ? rect->width : rect->height) * 0.3;
548         t = time % 2000;
549         angle = t * (M_PI / 500.0);
550
551         cairo_set_line_width(cr, 4.0);
552
553         if (t < 1000)
554                 cairo_arc(cr, cx, cy, r, 0.0, angle);
555         else
556                 cairo_arc(cr, cx, cy, r, angle, 0.0);
557
558         cairo_stroke(cr);
559 }
560
561 static void
562 sub_redraw_handler(struct widget *widget, void *data)
563 {
564         struct demoapp *app = data;
565         cairo_t *cr;
566         struct rectangle allocation;
567         uint32_t time;
568
569         widget_get_allocation(app->subsurface, &allocation);
570
571         cr = widget_cairo_create(widget);
572         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
573
574         /* debug: paint whole surface magenta; no magenta should show */
575         cairo_set_source_rgba(cr, 0.9, 0.0, 0.9, 1.0);
576         cairo_paint(cr);
577
578         cairo_rectangle(cr,
579                         allocation.x,
580                         allocation.y,
581                         allocation.width,
582                         allocation.height);
583         cairo_clip(cr);
584
585         cairo_set_source_rgba(cr, 0.8, 0, 0, 0.8);
586         cairo_paint(cr);
587
588         time = widget_get_last_time(widget);
589         cairo_set_source_rgba(cr, 1.0, 0.5, 0.5, 1.0);
590         draw_spinner(cr, &allocation, time);
591
592         cairo_destroy(cr);
593
594         if (app->animate)
595                 widget_schedule_redraw(app->subsurface);
596         DBG("%dx%d @ %d,%d, last time %u\n",
597             allocation.width, allocation.height,
598             allocation.x, allocation.y, time);
599 }
600
601 static void
602 sub_resize_handler(struct widget *widget,
603                    int32_t width, int32_t height, void *data)
604 {
605         DBG("%dx%d\n", width, height);
606         widget_input_region_add(widget, NULL);
607 }
608
609 static void
610 redraw_handler(struct widget *widget, void *data)
611 {
612         struct demoapp *app = data;
613         cairo_t *cr;
614         struct rectangle allocation;
615         uint32_t time;
616
617         widget_get_allocation(app->widget, &allocation);
618
619         cr = widget_cairo_create(widget);
620         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
621         cairo_rectangle(cr,
622                         allocation.x,
623                         allocation.y,
624                         allocation.width,
625                         allocation.height);
626         cairo_set_source_rgba(cr, 0, 0.8, 0, 0.8);
627         cairo_fill(cr);
628
629         time = widget_get_last_time(widget);
630         cairo_set_source_rgba(cr, 0.5, 1.0, 0.5, 1.0);
631         draw_spinner(cr, &allocation, time);
632
633         cairo_destroy(cr);
634
635         DBG("%dx%d @ %d,%d, last time %u\n",
636             allocation.width, allocation.height,
637             allocation.x, allocation.y, time);
638 }
639
640 static void
641 resize_handler(struct widget *widget,
642                int32_t width, int32_t height, void *data)
643 {
644         struct demoapp *app = data;
645         struct rectangle area;
646         int side, h;
647
648         widget_get_allocation(widget, &area);
649
650         side = area.width < area.height ? area.width / 2 : area.height / 2;
651         h = area.height - side;
652
653         widget_set_allocation(app->subsurface,
654                               area.x + area.width - side,
655                               area.y,
656                               side, h);
657
658         if (app->triangle) {
659                 widget_set_allocation(app->triangle->widget,
660                                       area.x + area.width - side,
661                                       area.y + h,
662                                       side, side);
663         }
664
665         DBG("green %dx%d, red %dx%d, GL %dx%d\n",
666             area.width, area.height, side, h, side, side);
667 }
668
669 static void
670 keyboard_focus_handler(struct window *window,
671                        struct input *device, void *data)
672 {
673         struct demoapp *app = data;
674
675         window_schedule_redraw(app->window);
676 }
677
678 static void
679 key_handler(struct window *window, struct input *input, uint32_t time,
680             uint32_t key, uint32_t sym,
681             enum wl_keyboard_key_state state, void *data)
682 {
683         struct demoapp *app = data;
684         struct rectangle winrect;
685
686         if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
687                 return;
688
689         switch (sym) {
690         case XKB_KEY_space:
691                 app->animate = !app->animate;
692                 window_schedule_redraw(window);
693                 break;
694         case XKB_KEY_Up:
695                 window_get_allocation(window, &winrect);
696                 winrect.height -= 100;
697                 if (winrect.height < 150)
698                         winrect.height = 150;
699                 window_schedule_resize(window, winrect.width, winrect.height);
700                 break;
701         case XKB_KEY_Down:
702                 window_get_allocation(window, &winrect);
703                 winrect.height += 100;
704                 if (winrect.height > 600)
705                         winrect.height = 600;
706                 window_schedule_resize(window, winrect.width, winrect.height);
707                 break;
708         case XKB_KEY_Escape:
709                 display_exit(app->display);
710                 break;
711         }
712 }
713
714 static struct demoapp *
715 demoapp_create(struct display *display)
716 {
717         struct demoapp *app;
718
719         app = xmalloc(sizeof *app);
720         memset(app, 0, sizeof *app);
721
722         app->egl = egl_state_create(display_get_display(display));
723
724         app->display = display;
725         display_set_user_data(app->display, app);
726
727         app->window = window_create(app->display);
728         app->widget = window_frame_create(app->window, app);
729         window_set_title(app->window, "Wayland Sub-surface Demo");
730
731         window_set_key_handler(app->window, key_handler);
732         window_set_user_data(app->window, app);
733         window_set_keyboard_focus_handler(app->window, keyboard_focus_handler);
734
735         widget_set_redraw_handler(app->widget, redraw_handler);
736         widget_set_resize_handler(app->widget, resize_handler);
737
738         app->subsurface = window_add_subsurface(app->window, app,
739                 int_to_mode(option_red_mode));
740         widget_set_redraw_handler(app->subsurface, sub_redraw_handler);
741         widget_set_resize_handler(app->subsurface, sub_resize_handler);
742
743         if (app->egl && !option_no_triangle)
744                 app->triangle = triangle_create(app->window, app->egl);
745
746         /* minimum size */
747         widget_schedule_resize(app->widget, 100, 100);
748
749         /* initial size */
750         widget_schedule_resize(app->widget, 400, 300);
751
752         app->animate = 1;
753
754         return app;
755 }
756
757 static void
758 demoapp_destroy(struct demoapp *app)
759 {
760         if (app->triangle)
761                 triangle_destroy(app->triangle);
762
763         if (app->egl)
764                 egl_state_destroy(app->egl);
765
766         widget_destroy(app->subsurface);
767         widget_destroy(app->widget);
768         window_destroy(app->window);
769         free(app);
770 }
771
772 int
773 main(int argc, char *argv[])
774 {
775         struct display *display;
776         struct demoapp *app;
777
778         if (parse_options(options, ARRAY_LENGTH(options), &argc, argv) > 1
779             || option_help) {
780                 printf(help_text, argv[0]);
781                 return 0;
782         }
783
784         display = display_create(&argc, argv);
785         if (display == NULL) {
786                 fprintf(stderr, "failed to create display: %m\n");
787                 return -1;
788         }
789
790         if (!display_has_subcompositor(display)) {
791                 fprintf(stderr, "compositor does not support "
792                         "the subcompositor extension\n");
793                 return -1;
794         }
795
796         app = demoapp_create(display);
797
798         display_run(display);
799
800         demoapp_destroy(app);
801         display_destroy(display);
802
803         return 0;
804 }