Add debug message macros controlled by environment variable
[apps/agl-service-homescreen.git] / sample / simple-egl / src / simple-egl.cpp
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3  * Copyright © 2011 Benjamin Franzke
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24
25 #include <mutex>
26 #include <chrono>
27
28 #include <iostream>
29 #include <string>
30 #include <stdarg.h>
31 #include <sys/types.h>
32 #include <thread>
33 #include <exception>
34 #include <vector>
35 #include <sstream>
36
37 #include <assert.h>
38 #include <signal.h>
39
40 #include <wayland-client.h>
41 #include <wayland-egl.h>
42
43 #include <GLES2/gl2.h>
44 #include <EGL/egl.h>
45 #include <EGL/eglext.h>
46
47 #include "libwindowmanager.h"
48 #include <libhomescreen.hpp>
49
50 #include "ivi-application-client-protocol.h"
51 using namespace std;
52
53
54 uint32_t g_id_ivisurf = 9009;
55 long port = 1700;
56 string token = string("wm");
57 bool enable_debug = false;
58
59 string app_name = string("Navigation");
60
61 LibHomeScreen* hs;
62 LibWindowmanager *wm;
63
64 static const struct wl_interface *types[] = {
65         NULL,
66         NULL,
67         NULL,
68         &wl_surface_interface,
69         &ivi_surface_interface,
70 };
71
72 static const struct wl_message ivi_surface_requests[] = {
73         { "destroy", "", types + 0 },
74 };
75
76 static const struct wl_message ivi_surface_events[] = {
77         { "configure", "ii", types + 0 },
78 };
79
80 const struct wl_interface ivi_surface_interface = {
81         "ivi_surface", 1,
82         1, ivi_surface_requests,
83         1, ivi_surface_events,
84 };
85
86 static const struct wl_message ivi_application_requests[] = {
87         { "surface_create", "uon", types + 2 },
88 };
89
90 const struct wl_interface ivi_application_interface = {
91         "ivi_application", 1,
92         1, ivi_application_requests,
93         0, NULL,
94 };
95
96 #include "platform.h"
97
98 #ifndef EGL_EXT_swap_buffers_with_damage
99 #define EGL_EXT_swap_buffers_with_damage 1
100 typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
101 #endif
102
103 #ifndef EGL_EXT_buffer_age
104 #define EGL_EXT_buffer_age 1
105 #define EGL_BUFFER_AGE_EXT                      0x313D
106 #endif
107
108 struct window;
109 struct seat;
110
111 struct display {
112         struct wl_display *display;
113         struct wl_registry *registry;
114         struct wl_compositor *compositor;
115         struct wl_seat *seat;
116         struct {
117                 EGLDisplay dpy;
118                 EGLContext ctx;
119                 EGLConfig conf;
120         } egl;
121         struct window *window;
122         struct ivi_application *ivi_application;
123
124         PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
125 };
126
127 struct geometry {
128         int width, height;
129 };
130
131 struct window {
132         struct display *display;
133         struct geometry geometry, window_size;
134         struct {
135                 GLuint rotation_uniform;
136                 GLuint pos;
137                 GLuint col;
138         } gl;
139
140         uint32_t benchmark_time, frames;
141         struct wl_egl_window *native;
142         struct wl_surface *surface;
143         struct ivi_surface *ivi_surface;
144         EGLSurface egl_surface;
145         struct wl_callback *callback;
146         int fullscreen, opaque, buffer_size, frame_sync;
147 };
148
149 static const char *vert_shader_text =
150         "uniform mat4 rotation;\n"
151         "attribute vec4 pos;\n"
152         "attribute vec4 color;\n"
153         "varying vec4 v_color;\n"
154         "void main() {\n"
155         "  gl_Position = rotation * pos;\n"
156         "  v_color = color;\n"
157         "}\n";
158
159 static const char *frag_shader_text =
160         "precision mediump float;\n"
161         "varying vec4 v_color;\n"
162         "void main() {\n"
163         "  gl_FragColor = v_color;\n"
164         "}\n";
165
166 static int running = 1;
167
168 static void debug_out(const char* str, ...)
169 {
170         if(!enable_debug)
171                 return;
172         char *out;
173         va_list arg_ptr;
174         va_start(arg_ptr, str);
175         vasprintf(&out, str, arg_ptr);
176         cout << out;
177         va_end(arg_ptr);
178         // cout << endl;
179 }
180
181 static void
182 init_egl(struct display *display, struct window *window)
183 {
184         static const EGLint context_attribs[] = {
185                 EGL_CONTEXT_CLIENT_VERSION, 2,
186                 EGL_NONE
187         };
188         const char *extensions;
189
190         EGLint config_attribs[] = {
191                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
192                 EGL_RED_SIZE, 1,
193                 EGL_GREEN_SIZE, 1,
194                 EGL_BLUE_SIZE, 1,
195                 EGL_ALPHA_SIZE, 1,
196                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
197                 EGL_NONE
198         };
199
200         EGLint major, minor, n, count, i, size;
201         EGLConfig *configs;
202         EGLBoolean ret;
203
204         if (window->opaque || window->buffer_size == 16)
205                 config_attribs[9] = 0;
206         
207         display->egl.dpy = weston_platform_get_egl_display(EGL_PLATFORM_WAYLAND_KHR, display->display, NULL);
208         assert(display->egl.dpy);
209
210         ret = eglInitialize(display->egl.dpy, &major, &minor);
211         assert(ret == EGL_TRUE);
212         ret = eglBindAPI(EGL_OPENGL_ES_API);
213         assert(ret == EGL_TRUE);
214
215         if (!eglGetConfigs(display->egl.dpy, NULL, 0, &count) || count < 1)
216                 assert(0);
217
218         configs = calloc(count, sizeof *configs);
219         assert(configs);
220
221         ret = eglChooseConfig(display->egl.dpy, config_attribs,
222                               configs, count, &n);
223         assert(ret && n >= 1);
224
225         for (i = 0; i < n; i++) {
226                 eglGetConfigAttrib(display->egl.dpy,
227                                    configs[i], EGL_BUFFER_SIZE, &size);
228                 if (window->buffer_size == size) {
229                         display->egl.conf = configs[i];
230                         break;
231                 }
232         }
233         free(configs);
234         if (display->egl.conf == NULL) {
235                 debug_out("did not find config with buffer size %d\n",
236                         window->buffer_size);
237                 exit(EXIT_FAILURE);
238         }
239
240         display->egl.ctx = eglCreateContext(display->egl.dpy,
241                                             display->egl.conf,
242                                             EGL_NO_CONTEXT, context_attribs);
243         assert(display->egl.ctx);
244
245         display->swap_buffers_with_damage = NULL;
246         extensions = eglQueryString(display->egl.dpy, EGL_EXTENSIONS);
247         if (extensions &&
248             strstr(extensions, "EGL_EXT_swap_buffers_with_damage") &&
249             strstr(extensions, "EGL_EXT_buffer_age"))
250                 display->swap_buffers_with_damage =
251                         (PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)
252                         eglGetProcAddress("eglSwapBuffersWithDamageEXT");
253
254         if (display->swap_buffers_with_damage)
255                 debug_out("has EGL_EXT_buffer_age and EGL_EXT_swap_buffers_with_damage\n");
256
257 }
258
259 static void
260 fini_egl(struct display *display)
261 {
262         eglTerminate(display->egl.dpy);
263         eglReleaseThread();
264 }
265
266 static GLuint
267 create_shader(struct window *window, const char *source, GLenum shader_type)
268 {
269         GLuint shader;
270         GLint status;
271
272         shader = glCreateShader(shader_type);
273         assert(shader != 0);
274
275         glShaderSource(shader, 1, (const char **) &source, NULL);
276         glCompileShader(shader);
277
278         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
279         if (!status) {
280                 char log[1000];
281                 GLsizei len;
282                 glGetShaderInfoLog(shader, 1000, &len, log);
283                 debug_out("Error: compiling %s: %*s\n",
284                         shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
285                         len, log);
286                 exit(1);
287         }
288
289         return shader;
290 }
291
292 static void
293 init_gl(struct window *window)
294 {
295         GLuint frag, vert;
296         GLuint program;
297         GLint status;
298
299         frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
300         vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
301
302         program = glCreateProgram();
303         glAttachShader(program, frag);
304         glAttachShader(program, vert);
305         glLinkProgram(program);
306
307         glGetProgramiv(program, GL_LINK_STATUS, &status);
308         if (!status) {
309                 char log[1000];
310                 GLsizei len;
311                 glGetProgramInfoLog(program, 1000, &len, log);
312                 debug_out("Error: linking:\n%*s\n", len, log);
313                 exit(1);
314         }
315
316         glUseProgram(program);
317
318         window->gl.pos = 0;
319         window->gl.col = 1;
320
321         glBindAttribLocation(program, window->gl.pos, "pos");
322         glBindAttribLocation(program, window->gl.col, "color");
323         glLinkProgram(program);
324
325         window->gl.rotation_uniform =
326                 glGetUniformLocation(program, "rotation");
327 }
328
329 static void
330 handle_ivi_surface_configure(void *data, struct ivi_surface *ivi_surface,
331                              int32_t width, int32_t height)
332 {
333         struct window *window = data;
334
335         wl_egl_window_resize(window->native, width, height, 0, 0);
336
337         window->geometry.width = width;
338         window->geometry.height = height;
339
340         if (!window->fullscreen)
341                 window->window_size = window->geometry;
342 }
343
344 static const struct ivi_surface_listener ivi_surface_listener = {
345         handle_ivi_surface_configure,
346 };
347
348 static void
349 create_ivi_surface(struct window *window, struct display *display)
350 {
351         uint32_t id_ivisurf = g_id_ivisurf;
352         window->ivi_surface =
353                 ivi_application_surface_create(display->ivi_application,
354                                                id_ivisurf, window->surface);
355
356         if (window->ivi_surface == NULL) {
357                 debug_out("Failed to create ivi_client_surface\n");
358                 abort();
359         }
360
361         ivi_surface_add_listener(window->ivi_surface,
362                                  &ivi_surface_listener, window);
363 }
364
365 static void
366 create_surface(struct window *window)
367 {
368         struct display *display = window->display;
369         EGLBoolean ret;
370
371         window->surface = wl_compositor_create_surface(display->compositor);
372
373         window->native =
374                 wl_egl_window_create(window->surface,
375                                      window->geometry.width,
376                                      window->geometry.height);
377         window->egl_surface =
378                 weston_platform_create_egl_surface(display->egl.dpy,
379                                                    display->egl.conf,
380                                                    window->native, NULL);
381
382
383         if (display->ivi_application ) {
384                 create_ivi_surface(window, display);
385         } else {
386                 assert(0);
387         }
388
389         ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
390                              window->egl_surface, window->display->egl.ctx);
391         assert(ret == EGL_TRUE);
392
393         if (!window->frame_sync)
394                 eglSwapInterval(display->egl.dpy, 0);
395
396 }
397
398 static void
399 destroy_surface(struct window *window)
400 {
401         /* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
402          * on eglReleaseThread(). */
403         eglMakeCurrent(window->display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
404                        EGL_NO_CONTEXT);
405
406         eglDestroySurface(window->display->egl.dpy, window->egl_surface);
407         wl_egl_window_destroy(window->native);
408
409         if (window->display->ivi_application)
410                 ivi_surface_destroy(window->ivi_surface);
411         wl_surface_destroy(window->surface);
412
413         if (window->callback)
414                 wl_callback_destroy(window->callback);
415 }
416
417 static void
418 redraw(void *data, struct wl_callback *callback, uint32_t time)
419 {
420         struct window *window = data;
421         struct display *display = window->display;
422         static const GLfloat verts[3][2] = {
423                 { -0.5, -0.5 },
424                 {  0.5, -0.5 },
425                 {  0,    0.5 }
426         };
427
428         static const GLfloat colors_H[3][3] = {
429                 { 1, 1, 1 },
430                 { 1, 1, 1 },
431                 { 1, 1, 1 }
432         };
433
434         static const GLfloat colors_N[3][3] = {
435                 { 1, 0, 0 },
436                 { 0, 1, 0 },
437                 { 0, 0, 1 }
438         };
439
440         GLfloat angle;
441         GLfloat rotation[4][4] = {
442                 { 1, 0, 0, 0 },
443                 { 0, 1, 0, 0 },
444                 { 0, 0, 1, 0 },
445                 { 0, 0, 0, 1 }
446         };
447         static const uint32_t speed_div = 5, benchmark_interval = 5;
448         struct wl_region *region;
449         EGLint rect[4];
450         EGLint buffer_age = 0;
451         struct timeval tv;
452
453         assert(window->callback == callback);
454         window->callback = NULL;
455
456         if (callback)
457                 wl_callback_destroy(callback);
458
459         gettimeofday(&tv, NULL);
460         time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
461         if (window->frames == 0)
462                 window->benchmark_time = time;
463         if (time - window->benchmark_time > (benchmark_interval * 1000)) {
464                 debug_out("%d frames in %d seconds: %f fps\n",
465                        window->frames,
466                        benchmark_interval,
467                        (float) window->frames / benchmark_interval);
468                 window->benchmark_time = time;
469                 window->frames = 0;
470         }
471
472         angle = (time / speed_div) % 360 * M_PI / 180.0;
473         rotation[0][0] =  cos(angle);
474         rotation[0][2] =  sin(angle);
475         rotation[2][0] = -sin(angle);
476         rotation[2][2] =  cos(angle);
477
478         if (display->swap_buffers_with_damage)
479                 eglQuerySurface(display->egl.dpy, window->egl_surface,
480                                 EGL_BUFFER_AGE_EXT, &buffer_age);
481
482         glViewport(0, 0, window->geometry.width, window->geometry.height);
483
484         glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
485                            (GLfloat *) rotation);
486
487         glClearColor(0.0, 0.0, 0.0, 0.5);
488         glClear(GL_COLOR_BUFFER_BIT);
489
490         glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
491         if(app_name == string("HVAC")){
492                 glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors_H);
493         }
494         else{
495                 glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors_N);
496         }
497         glEnableVertexAttribArray(window->gl.pos);
498         glEnableVertexAttribArray(window->gl.col);
499
500         glDrawArrays(GL_TRIANGLES, 0, 3);
501
502         glDisableVertexAttribArray(window->gl.pos);
503         glDisableVertexAttribArray(window->gl.col);
504
505         if (window->opaque || window->fullscreen) {
506                 region = wl_compositor_create_region(window->display->compositor);
507                 wl_region_add(region, 0, 0,
508                               window->geometry.width,
509                               window->geometry.height);
510                 wl_surface_set_opaque_region(window->surface, region);
511                 wl_region_destroy(region);
512         } else {
513                 wl_surface_set_opaque_region(window->surface, NULL);
514         }
515
516         if (display->swap_buffers_with_damage && buffer_age > 0) {
517                 rect[0] = window->geometry.width / 4 - 1;
518                 rect[1] = window->geometry.height / 4 - 1;
519                 rect[2] = window->geometry.width / 2 + 2;
520                 rect[3] = window->geometry.height / 2 + 2;
521                 display->swap_buffers_with_damage(display->egl.dpy,
522                                                   window->egl_surface,
523                                                   rect, 1);
524         } else {
525                 eglSwapBuffers(display->egl.dpy, window->egl_surface);
526         }
527     
528         window->frames++;
529 }
530
531 static void
532 registry_handle_global(void *data, struct wl_registry *registry,
533                        uint32_t name, const char *interface, uint32_t version)
534 {
535         struct display *d = data;
536
537         if (strcmp(interface, "wl_compositor") == 0) {
538                 d->compositor =
539                         wl_registry_bind(registry, name,
540                                          &wl_compositor_interface, 1);
541         } else if (strcmp(interface, "ivi_application") == 0) {
542                 d->ivi_application =
543                         wl_registry_bind(registry, name,
544                                          &ivi_application_interface, 1);
545         }
546 }
547
548 static void
549 registry_handle_global_remove(void *data, struct wl_registry *registry,
550                               uint32_t name)
551 {
552 }
553
554 static const struct wl_registry_listener registry_listener = {
555         registry_handle_global,
556         registry_handle_global_remove
557 };
558
559 static void
560 signal_int(int signum)
561 {
562         running = 0;
563 }
564
565 int
566 init_wm(LibWindowmanager *wm)
567 {
568         char* surfaceIdStr;
569
570         if (wm->init(port, token.c_str()) != 0) {
571                 debug_out("************** [SIMPLE EGL] [WM SIMPLE >>>>] wm init failed. \n");
572                 return -1;
573         }
574
575         if (wm->requestSurface(app_name.c_str()) != 0) {
576                 debug_out("************** [SIMPLE EGL] [WM SIMPLE >>>>] wm request surface failed \n");
577                 return -1;
578         }
579
580         wm->set_event_handler(LibWindowmanager::Event_Active, [](char const *label) {
581                 debug_out("************** [SIMPLE EGL] [WM SIMPLE >>>>] Surface %s got activated! \n", label);
582         });
583
584         wm->set_event_handler(LibWindowmanager::Event_Inactive, [](char const *label) {
585                 debug_out("************** [SIMPLE EGL] [WM SIMPLE >>>>] Surface %s got inactivated!\n", label);
586         });
587
588         wm->set_event_handler(LibWindowmanager::Event_Visible, [wm](char const *label) {
589                 debug_out("************** [SIMPLE EGL] [WM SIMPLE >>>>] Surface %s got visibled!\n", label);
590         });
591
592         wm->set_event_handler(LibWindowmanager::Event_Invisible, [](char const *label) {
593                 debug_out("************** [SIMPLE EGL] [WM SIMPLE >>>>] Surface %s got invisibled!\n", label);
594         });
595
596         wm->set_event_handler(LibWindowmanager::Event_SyncDraw, [wm](char const *label) {
597                 debug_out("************** [SIMPLE EGL] [WM SIMPLE >>>>] Surface %s got syncdraw!\n", label);
598         debug_out("************** [SIMPLE EGL] [WM SIMPLE >>>>] try to endDraw %s \n", app_name.c_str());
599         wm->endDraw(app_name.c_str());
600         });
601
602         wm->set_event_handler(LibWindowmanager::Event_FlushDraw, [](char const *label) {
603                 debug_out("************** [SIMPLE EGL] [WM SIMPLE >>>>] Surface %s got flushdraw! \n", label);
604         });
605
606         do
607         {
608         surfaceIdStr = getenv("QT_IVI_SURFACE_ID");
609         } while (surfaceIdStr == NULL);  
610         
611         g_id_ivisurf = atoi(surfaceIdStr);
612         debug_out("************** [SIMPLE EGL] [WM SIMPLE >>>>] IVI_SURFACE_ID: %d \n", g_id_ivisurf);
613
614         return 0;
615 }
616
617 int
618 init_hs(LibHomeScreen* hs){
619         if(hs->init(port, token)!=0)
620         {
621                 debug_out("************** [SIMPLE EGL] [HS SIMPLE >>>>] homescreen init failed. \n");
622                 return -1;
623         }
624
625         hs->set_event_handler(LibHomeScreen::Event_TapShortcut, [](const char* application_name){
626                 debug_out("************** [SIMPLE EGL] [HS SIMPLE >>>>] Event_TapShortcut application_name = %s \n", application_name);
627                 if(strcmp(application_name, app_name.c_str()) == 0)
628                 {
629                         debug_out("************** [SIMPLE EGL] [HS SIMPLE] try to activesurface %s \n", app_name.c_str());
630                         wm->activateSurface(app_name.c_str());
631                 }
632         });
633
634         hs->set_event_handler(LibHomeScreen::Event_OnScreenMessage, [](const char* display_message){
635         debug_out("************** [SIMPLE EGL] [HS SIMPLE >>>>] Event_OnScreenMessage display_message = %s \n", display_message);
636         });
637
638         return 0;
639 }
640
641 int
642 main(int argc, char **argv)
643 {
644         struct sigaction sigint;
645     struct window  window  = { 0 };
646         struct display display = { 0 };
647
648         if(getenv("ENABLE_DEMO_DEBUG"))
649         {
650                 enable_debug = true;
651         }
652
653         window.display = &display;
654         display.window = &window;
655         window.geometry.width  = 1080;
656         window.geometry.height = 1488;
657         window.window_size = window.geometry;
658         window.buffer_size = 32;
659         window.frame_sync = 1;
660
661         if(argc > 2)
662         {
663                 if(string(argv[0]).find("hvac") != string::npos)
664                         app_name = string("HVAC");
665                 port = strtol(argv[1], NULL, 10);
666                 token = argv[2];
667         }
668
669         debug_out("************** [SIMPLE EGL] [MAIN] app_name: %s, port: %d, token: %s. \n", app_name.c_str(), port, token.c_str());
670
671         display.display = wl_display_connect(NULL);
672         assert(display.display);
673
674         display.registry = wl_display_get_registry(display.display);
675         wl_registry_add_listener(display.registry,
676                                  &registry_listener, &display);
677
678         wl_display_roundtrip(display.display);
679
680         init_egl(&display, &window);
681
682         wm = new LibWindowmanager();
683         hs = new LibHomeScreen();
684         
685         if(init_wm(wm)!=0){
686                 fini_egl(&display);
687                 if (display.ivi_application)
688                         ivi_application_destroy(display.ivi_application);
689                 if (display.compositor)
690                         wl_compositor_destroy(display.compositor);
691                 wl_registry_destroy(display.registry);
692                 wl_display_flush(display.display);
693                 return -1;
694         }
695
696         if(init_hs(hs)!=0){
697                 fini_egl(&display);
698                 if (display.ivi_application)
699                         ivi_application_destroy(display.ivi_application);
700                 if (display.compositor)
701                         wl_compositor_destroy(display.compositor);
702                 wl_registry_destroy(display.registry);
703                 wl_display_flush(display.display);
704                 return -1;
705         }
706
707         create_surface(&window);
708         init_gl(&window);
709         
710         //Ctrl+C
711         sigint.sa_handler = signal_int;
712         sigemptyset(&sigint.sa_mask);
713         sigint.sa_flags = SA_RESETHAND;
714         sigaction(SIGINT, &sigint, NULL);
715
716         eglSwapBuffers(display.egl.dpy, window.egl_surface);
717         wm->activateSurface(app_name.c_str());
718         
719         /* The mainloop here is a little subtle.  Redrawing will cause
720          * EGL to read events so we can just call
721          * wl_display_dispatch_pending() to handle any events that got
722          * queued up as a side effect. */
723         while (running) {
724                 wl_display_dispatch_pending(display.display);
725                 redraw(&window, NULL, 0);
726         }
727
728         debug_out("************** [SIMPLE EGL] [MAIN] simple-egl exiting! \n");
729
730         destroy_surface(&window);
731         fini_egl(&display);
732
733         if (display.ivi_application)
734                 ivi_application_destroy(display.ivi_application);
735
736         if (display.compositor)
737                 wl_compositor_destroy(display.compositor);
738
739         wl_registry_destroy(display.registry);
740         wl_display_flush(display.display);
741         wl_display_disconnect(display.display);
742
743         return 0;
744 }