Add an exception handling about raising the window
[platform/core/appfw/app-core.git] / src / ui_base / appcore_ui_base.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #define _GNU_SOURCE
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/un.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <stdarg.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <linux/limits.h>
28
29 #include <Ecore_Wl2.h>
30 #include <wayland-client.h>
31 #include <wayland-tbm-client.h>
32 #include <tizen-extension-client-protocol.h>
33
34 #include <Ecore.h>
35 #include <glib-object.h>
36 #include <malloc.h>
37 #include <glib.h>
38 #include <gio/gio.h>
39 #include <stdbool.h>
40 #include <aul.h>
41 #include <aul_svc.h>
42 #include <aul_rpc_port.h>
43 #include <bundle_internal.h>
44 #include <ttrace.h>
45
46 #include "appcore_base.h"
47 #include "appcore_ui_base.h"
48 #include "appcore_ui_base_private.h"
49 #include "appcore_ui_plugin.h"
50
51 enum app_state {
52         AS_NONE,
53         AS_CREATED,
54         AS_RUNNING,
55         AS_PAUSED,
56         AS_DYING,
57 };
58
59 enum win_status {
60         WS_NONE,
61         WS_PAUSE,
62         WS_RESUME,
63 };
64
65 enum visibility_type {
66         VT_NONE,
67         VT_UNOBSCURED,
68         VT_FULLY_OBSCURED,
69 };
70
71 typedef struct _appcore_ui_base_context {
72         appcore_ui_base_ops ops;
73         void *data;
74         int argc;
75         char **argv;
76         unsigned int hint;
77         char *below_app;
78         char *appid;
79         bool bg_state;
80         bool resource_reclaiming;
81
82         int state;
83         Ecore_Event_Handler *hshow;
84         Ecore_Event_Handler *hhide;
85         Ecore_Event_Handler *hvchange;
86         Ecore_Event_Handler *hlower;
87         Ecore_Event_Handler *hpvchange;
88         Ecore_Event_Handler *hauxmsg;
89 } appcore_ui_base_context;
90
91
92 static int w_status = WS_NONE;
93 static bool first_launch = true;
94
95 struct win_node {
96         unsigned int win;
97         unsigned int surf;
98         int vis;
99 };
100
101 static GSList *g_winnode_list;
102 static appcore_ui_base_context __context;
103 static struct wl_display *dsp;
104 static struct wl_registry *reg;
105 static struct tizen_policy *tz_policy;
106
107 static void _wl_cb_conformant(void *data,
108                 struct tizen_policy *tizen_policy,
109                 struct wl_surface *surface_resource,
110                 uint32_t is_conformant)
111 {
112         ; // nothing to do.
113 }
114
115 static void _wl_cb_conformant_area(void *data,
116                 struct tizen_policy *tizen_policy,
117                 struct wl_surface *surface_resource,
118                 uint32_t conformant_part,
119                 uint32_t state,
120                 int32_t x, int32_t y, int32_t w, int32_t h)
121 {
122         ; // nothing to do.
123 }
124
125 static void _wl_cb_notification_done(void *data,
126                 struct tizen_policy *tizen_policy,
127                 struct wl_surface *surface,
128                 int32_t level,
129                 uint32_t state)
130 {
131         ; // nothing to do.
132 }
133
134 static void _wl_cb_transient_for_done(void *data,
135                 struct tizen_policy *tizen_policy,
136                 uint32_t child_id)
137 {
138         ; // nothing to do.
139 }
140
141 static void _wl_cb_scr_mode_done(void *data,
142                 struct tizen_policy *tizen_policy,
143                 struct wl_surface *surface,
144                 uint32_t mode,
145                 uint32_t state)
146 {
147         ; // nothing to do.
148 }
149
150 static void _wl_cb_iconify_state_changed(void *data,
151                 struct tizen_policy *tizen_policy,
152                 struct wl_surface *surface_resource,
153                 uint32_t iconified,
154                 uint32_t force)
155 {
156         ; // nothing to do.
157 }
158
159 static void _wl_cb_supported_aux_hints(void *data,
160                 struct tizen_policy *tizen_policy,
161                 struct wl_surface *surface_resource,
162                 struct wl_array *hints,
163                 uint32_t num_hints)
164 {
165         ; // nothing to do.
166 }
167
168 static void _wl_cb_allowed_aux_hint(void *data,
169                 struct tizen_policy *tizen_policy,
170                 struct wl_surface *surface_resource,
171                 int id)
172 {
173         ; // nothing to do.
174 }
175
176 static void _wl_cb_aux_message(void *data,
177                 struct tizen_policy *tizen_policy,
178                 struct wl_surface *surface_resource,
179                 const char *key,
180                 const char *val,
181                 struct wl_array *options)
182 {
183         ; // nothing to do.
184 }
185
186 static void _wl_cb_conformant_region(void *data,
187                 struct tizen_policy *tizen_policy,
188                 struct wl_surface *surface,
189                 uint32_t conformant_part,
190                 uint32_t state,
191                 int32_t x, int32_t y, int32_t w, int32_t h,
192                 uint32_t serial)
193 {
194         ; // nothing to do.
195 }
196
197 static const struct tizen_policy_listener _tizen_policy_listener = {
198         _wl_cb_conformant,
199         _wl_cb_conformant_area,
200         _wl_cb_notification_done,
201         _wl_cb_transient_for_done,
202         _wl_cb_scr_mode_done,
203         _wl_cb_iconify_state_changed,
204         _wl_cb_supported_aux_hints,
205         _wl_cb_allowed_aux_hint,
206         _wl_cb_aux_message,
207         _wl_cb_conformant_region,
208 };
209
210 static void __wl_listener_cb(void *data, struct wl_registry *reg,
211                 uint32_t id, const char *interface, uint32_t ver)
212 {
213         if (interface && !strcmp(interface, "tizen_policy")) {
214                 if (!tz_policy)
215                         tz_policy = wl_registry_bind(reg, id,
216                                         &tizen_policy_interface, 7);
217                 if (tz_policy) {
218                         tizen_policy_add_listener(tz_policy, &_tizen_policy_listener, dsp);
219                 }
220         }
221 }
222
223 static void __wl_listener_remove_cb(void *data, struct wl_registry *reg,
224                 unsigned int id)
225 {
226         /* do nothing */
227 }
228
229 static const struct wl_registry_listener reg_listener = {
230         __wl_listener_cb,
231         __wl_listener_remove_cb
232 };
233
234 static Eina_Bool __stub_show_cb(void *data, int type, void *event)
235 {
236         if (__context.ops.window.show)
237                 __context.ops.window.show(type, event, __context.data);
238
239         return ECORE_CALLBACK_RENEW;
240 }
241
242 static Eina_Bool __stub_hide_cb(void *data, int type, void *event)
243 {
244         if (__context.ops.window.hide)
245                 __context.ops.window.hide(type, event, __context.data);
246
247         return ECORE_CALLBACK_RENEW;
248 }
249
250 static Eina_Bool __stub_visibility_cb(void *data, int type, void *event)
251 {
252         if (__context.ops.window.visibility)
253                 __context.ops.window.visibility(type, event, __context.data);
254
255         return ECORE_CALLBACK_RENEW;
256 }
257
258 static Eina_Bool __stub_lower_cb(void *data, int type, void *event)
259 {
260         if (__context.ops.window.lower)
261                 __context.ops.window.lower(type, event, __context.data);
262
263         return ECORE_CALLBACK_RENEW;
264 }
265
266 static Eina_Bool __stub_pre_visibility_cb(void *data, int type, void *event)
267 {
268         if (__context.ops.window.pre_visibility)
269                 __context.ops.window.pre_visibility(type, event, __context.data);
270
271         return ECORE_CALLBACK_RENEW;
272 }
273
274 static Eina_Bool __stub_aux_message_cb(void *data, int type, void *event)
275 {
276         if (__context.ops.window.aux_message)
277                 __context.ops.window.aux_message(type, event, __context.data);
278
279         return ECORE_CALLBACK_RENEW;
280 }
281
282 static void __prepare_to_suspend(void)
283 {
284         int suspend = APPCORE_BASE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
285
286         if (appcore_base_is_bg_allowed() && !appcore_base_is_suspended()) {
287                 appcore_base_raise_event((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
288                 appcore_base_toggle_suspended_state();
289         }
290 }
291
292 static void __exit_from_suspend(void)
293 {
294         int suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
295
296         if (appcore_base_is_suspended()) {
297                 appcore_base_raise_event((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
298                 appcore_base_toggle_suspended_state();
299         }
300 }
301
302 static void __do_pause(void)
303 {
304         int r = -1;
305
306         if (__context.state == AS_RUNNING) {
307                 if (__context.ops.pause) {
308                         traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:PAUSE");
309                         _DBG("Call pause callback");
310                         r = __context.ops.pause(__context.data);
311                         traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
312                 }
313
314                 if (r >= 0 && __context.resource_reclaiming)
315                         appcore_base_add_suspend_timer();
316
317                 __context.state = AS_PAUSED;
318                 __prepare_to_suspend();
319         }
320         aul_status_update(STATUS_BG);
321 }
322
323 static void __do_resume(void)
324 {
325         if (__context.state == AS_PAUSED || __context.state == AS_CREATED) {
326                 __exit_from_suspend();
327                 if (__context.ops.resume) {
328                         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:start]", __context.appid);
329                         traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESUME");
330                         _DBG("Call resume callback");
331                         __context.ops.resume(__context.data);
332                         traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
333                         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:done]", __context.appid);
334                 }
335                 __context.state = AS_RUNNING;
336         }
337
338         aul_status_update(STATUS_VISIBLE);
339 }
340
341 static GSList *__find_win(unsigned int win)
342 {
343         GSList *iter;
344         struct win_node *t;
345
346         for (iter = g_winnode_list; iter; iter = g_slist_next(iter)) {
347                 t = iter->data;
348                 if (t && t->win == win)
349                         return iter;
350         }
351
352         return NULL;
353 }
354
355 static int __get_main_window(void)
356 {
357         struct win_node *entry = NULL;
358
359         if (g_winnode_list != NULL) {
360                 entry = g_winnode_list->data;
361                 return (unsigned int) entry->win;
362         }
363
364         return 0;
365 }
366
367 static int __get_main_surface(void)
368 {
369         struct win_node *entry = NULL;
370
371         if (g_winnode_list != NULL) {
372                 entry = g_winnode_list->data;
373                 return (unsigned int) entry->surf;
374         }
375
376         return 0;
377 }
378
379 static bool __add_win(unsigned int win, unsigned int surf)
380 {
381         struct win_node *t;
382         GSList *f;
383
384         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
385
386         f = __find_win(win);
387         if (f) {
388                 errno = ENOENT;
389                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
390                 return FALSE;
391         }
392
393         t = calloc(1, sizeof(struct win_node));
394         if (t == NULL)
395                 return FALSE;
396
397         t->win = win;
398         t->surf = surf;
399         t->vis = VT_NONE;
400
401         g_winnode_list = g_slist_append(g_winnode_list, t);
402
403         return TRUE;
404 }
405
406 static bool __delete_win(unsigned int win)
407 {
408         GSList *f;
409
410         f = __find_win(win);
411         if (!f) {
412                 errno = ENOENT;
413                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
414                                 win);
415                 return FALSE;
416         }
417
418         free(f->data);
419         g_winnode_list = g_slist_delete_link(g_winnode_list, f);
420
421         return TRUE;
422 }
423
424 static bool __update_win(unsigned int win, unsigned int surf, int vis)
425 {
426         GSList *f;
427         struct win_node *t;
428
429         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x visibility %d\n",
430                         win, vis);
431
432         f = __find_win(win);
433         if (!f) {
434                 errno = ENOENT;
435                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
436                 return FALSE;
437         }
438
439         t = (struct win_node *)f->data;
440         t->win = win;
441         if (surf != 0)
442                 t->surf = surf;
443         if (vis != VT_NONE)
444                 t->vis = vis;
445
446         return TRUE;
447 }
448
449 static void __raise_win(void)
450 {
451         Ecore_Wl2_Window *win;
452         unsigned int win_id;
453
454         if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL))
455                 return;
456
457         win_id = __get_main_window();
458
459         _DBG("Raise window: %d", win_id);
460         win = ecore_wl2_display_window_find(ecore_wl2_connected_display_get(NULL), win_id);
461         ecore_wl2_window_activate(win);
462 }
463
464 static void __pause_win(void)
465 {
466         Ecore_Wl2_Window *win;
467         GSList *wlist = g_winnode_list;
468         struct win_node *entry = NULL;
469
470         if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL))
471                 return;
472
473         _DBG("Pause window");
474
475         while (wlist) {
476                 entry = wlist->data;
477
478                 _DBG("Pause window: %d", entry->win);
479                 win = ecore_wl2_display_window_find(ecore_wl2_connected_display_get(NULL), entry->win);
480                 ecore_wl2_window_iconified_set(win, EINA_TRUE);
481
482                 wlist = wlist->next;
483         }
484 }
485
486 static int __init_wl(void)
487 {
488         _DBG("initialize wayland");
489         dsp = wl_display_connect(NULL);
490         if (dsp == NULL) {
491                 _ERR("Failed to connect wl display");
492                 return -1;
493         }
494
495         reg = wl_display_get_registry(dsp);
496         if (reg == NULL) {
497                 _ERR("Failed to get registry");
498                 wl_display_disconnect(dsp);
499                 return -1;
500         }
501
502         wl_registry_add_listener(reg, &reg_listener, NULL);
503         wl_display_roundtrip(dsp);
504
505         if (!tz_policy) {
506                 _ERR("Failed to get tizen policy interface");
507                 wl_registry_destroy(reg);
508                 wl_display_disconnect(dsp);
509                 return -1;
510         }
511
512         return 0;
513 }
514
515 static void __finish_wl(void)
516 {
517         if (tz_policy) {
518                 tizen_policy_destroy(tz_policy);
519                 tz_policy = NULL;
520         }
521
522         if (reg) {
523                 wl_registry_destroy(reg);
524                 reg = NULL;
525         }
526
527         if (dsp) {
528                 wl_display_disconnect(dsp);
529                 dsp = NULL;
530         }
531 }
532
533 static void __set_bg_state(void)
534 {
535         if (!tz_policy && __init_wl() < 0)
536                 return;
537
538         tizen_policy_set_background_state(tz_policy, getpid());
539         wl_display_roundtrip(dsp);
540         __context.bg_state = true;
541         _DBG("bg state: %d", __context.bg_state);
542 }
543
544 static void __unset_bg_state(void)
545 {
546         if (!tz_policy)
547                 return;
548
549         tizen_policy_unset_background_state(tz_policy, getpid());
550         wl_display_roundtrip(dsp);
551         __context.bg_state = false;
552         _DBG("bg state: %d", __context.bg_state);
553 }
554
555 static void __do_start(bundle *b)
556 {
557         const char *bg_launch;
558         const char *below_app;
559         const char *rpc_port;
560
561         if (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL) {
562                 if (__context.below_app) {
563                         free(__context.below_app);
564                         __context.below_app = NULL;
565                 }
566
567                 below_app = bundle_get_val(b, AUL_SVC_K_RELOCATE_BELOW);
568                 if (below_app)
569                         __context.below_app = strdup(below_app);
570         }
571
572         if (first_launch) {
573                 first_launch = FALSE;
574                 return;
575         }
576
577         if (__context.hint & APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL) {
578                 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
579                 if (bg_launch && strcmp(bg_launch, "enable") == 0) {
580                         if (!__context.bg_state &&
581                                         __context.state != AS_RUNNING)
582                                 __set_bg_state();
583                 } else {
584                         if (__context.bg_state)
585                                 __unset_bg_state();
586                 }
587         }
588
589         if (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_AUTO_CONTROL) {
590                 if (!__context.bg_state) {
591                         rpc_port = bundle_get_val(b, AUL_K_RPC_PORT);
592                         if (!rpc_port)
593                                 __raise_win();
594                 }
595         }
596 }
597
598 static int __is_legacy_lifecycle(void)
599 {
600         static int is_legacy = -1;
601         const char *api_version;
602
603         if (is_legacy != -1)
604                 return is_legacy;
605
606         api_version = getenv("TIZEN_API_VERSION");
607         if (api_version) {
608                 if (strverscmp("2.4", api_version) > 0 &&
609                                 strverscmp("2.2.1", api_version) < 0)
610                         is_legacy = 1;
611                 else
612                         is_legacy = 0;
613         } else {
614                 is_legacy = 0;
615         }
616
617         return is_legacy;
618 }
619
620 EXPORT_API int appcore_ui_base_on_receive(aul_type type, bundle *b)
621 {
622         if (__context.state == AS_DYING) {
623                 _ERR("Skip the event in dying state");
624                 return 0;
625         }
626
627         if (type == AUL_TERMINATE_BGAPP && __context.state != AS_PAUSED)
628                 return 0;
629
630         if (type == AUL_START)
631                 __exit_from_suspend();
632
633         appcore_base_on_receive(type, b);
634
635         switch (type) {
636         case AUL_START:
637                 __do_start(b);
638                 if (__context.hint & APPCORE_UI_BASE_HINT_LEGACY_CONTROL) {
639                         if (!__context.bg_state && __is_legacy_lifecycle()) {
640                                 _DBG("Legacy lifecycle");
641                                 __do_resume();
642                         }
643                 }
644                 break;
645         case AUL_RESUME:
646                 if (__context.bg_state)
647                         __unset_bg_state();
648                 __raise_win();
649                 break;
650         case AUL_TERMINATE:
651                 break;
652         case AUL_TERMINATE_BGAPP:
653                 _DBG("[APP %d] is paused. TERMINATE", getpid());
654                 __context.state = AS_DYING;
655                 aul_status_update(STATUS_DYING);
656                 if (__context.ops.base.exit)
657                         __context.ops.base.exit(__context.data);
658                 break;
659         case AUL_PAUSE:
660                 __pause_win();
661                 break;
662         default:
663                 break;
664         }
665
666         return 0;
667 }
668
669 static void __add_ecore_events(void)
670 {
671         __context.hshow = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_SHOW,
672                         __stub_show_cb, NULL);
673         if (!__context.hshow)
674                 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_SHOW event");
675
676         __context.hhide = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_HIDE,
677                         __stub_hide_cb, NULL);
678         if (!__context.hhide)
679                 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_HIDE event");
680
681         __context.hvchange = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE,
682                         __stub_visibility_cb, NULL);
683         if (!__context.hvchange)
684                 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE event");
685
686         __context.hlower = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_LOWER,
687                         __stub_lower_cb, NULL);
688         if (!__context.hlower)
689                 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_LOWER event");
690
691         __context.hpvchange = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_PRE_VISIBILITY_CHANGE,
692                         __stub_pre_visibility_cb, NULL);
693         if (!__context.hpvchange)
694                 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_PRE_VISIBILITY_CHANGE event");
695
696         __context.hauxmsg = ecore_event_handler_add(ECORE_WL2_EVENT_AUX_MESSAGE,
697                         __stub_aux_message_cb, NULL);
698         if (!__context.hauxmsg)
699                 _ERR("Failed to add ECORE_WL2_EVENT_AUX_MESSAGE event");
700 }
701
702 static void __del_ecore_events(void)
703 {
704         if (__context.hshow) {
705                 ecore_event_handler_del(__context.hshow);
706                 __context.hshow = NULL;
707         }
708
709         if (__context.hhide) {
710                 ecore_event_handler_del(__context.hhide);
711                 __context.hhide = NULL;
712         }
713
714         if (__context.hvchange) {
715                 ecore_event_handler_del(__context.hvchange);
716                 __context.hvchange = NULL;
717         }
718
719         if (__context.hlower) {
720                 ecore_event_handler_del(__context.hlower);
721                 __context.hlower = NULL;
722         }
723
724         if (__context.hpvchange) {
725                 ecore_event_handler_del(__context.hpvchange);
726                 __context.hpvchange = NULL;
727         }
728
729         if (__context.hauxmsg) {
730                 ecore_event_handler_del(__context.hauxmsg);
731                 __context.hauxmsg = NULL;
732         }
733 }
734
735 EXPORT_API int appcore_ui_base_on_create(void)
736 {
737         __add_ecore_events();
738         appcore_base_on_create();
739         __context.state = AS_CREATED;
740         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]", __context.appid);
741
742         return 0;
743 }
744
745 EXPORT_API int appcore_ui_base_on_terminate(void)
746 {
747         if (__context.state == AS_RUNNING) {
748                 if (__context.ops.pause) {
749                         _DBG("Call pause callback");
750                         __context.ops.pause(__context.data);
751                 }
752         }
753
754         __context.state = AS_DYING;
755
756         appcore_base_on_terminate();
757
758         return 0;
759 }
760
761 EXPORT_API int appcore_ui_base_on_pause(void)
762 {
763         return 0;
764 }
765
766 EXPORT_API int appcore_ui_base_on_resume(void)
767 {
768         return 0;
769 }
770
771 EXPORT_API int appcore_ui_base_on_control(bundle *b)
772 {
773         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]", __context.appid);
774         appcore_base_on_control(b);
775         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]", __context.appid);
776
777         return 0;
778 }
779
780 EXPORT_API int appcore_ui_base_on_trim_memory(void)
781 {
782         return appcore_base_on_trim_memory();
783 }
784
785 static void __group_attach()
786 {
787         if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL))
788                 return;
789
790         appcore_ui_base_group_add();
791 }
792
793 static void __group_lower()
794 {
795         if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL))
796                 return;
797         appcore_ui_base_group_remove();
798 }
799
800 EXPORT_API void appcore_ui_base_group_add()
801 {
802         static bool attached = false;
803
804         _DBG("__group_attach");
805         if (attached)
806                 return;
807
808         int wid = __get_main_surface();
809         if (wid == 0) {
810                 _ERR("window wasn't ready");
811                 return;
812         }
813
814         aul_app_group_set_window(wid);
815         attached = true;
816 }
817
818 EXPORT_API void appcore_ui_base_group_remove()
819 {
820         int exit = 0;
821
822         _DBG("__group_lower");
823         aul_app_group_lower(&exit);
824         if (exit) {
825                 _DBG("__group_lower : sub-app!");
826                 if (__context.ops.base.exit)
827                         __context.ops.base.exit(__context.data);
828         }
829 }
830
831 EXPORT_API void appcore_ui_base_window_on_show(int type, void *event)
832 {
833         Ecore_Wl2_Event_Window_Show *ev;
834
835         ev = event;
836         if (ev->parent_win != 0) {
837                 /* This is child window. Skip!!! */
838                 return;
839         }
840
841         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x, %d\n",
842                         ev->win, ev->data[0]);
843
844         if (!__find_win((unsigned int)ev->win)) {
845                 __add_win((unsigned int)ev->win, (unsigned int)ev->data[0]);
846         } else {
847                 __update_win((unsigned int)ev->win, (unsigned int)ev->data[0],
848                                 VT_NONE);
849         }
850
851         if (ev->data[0] != 0)
852                 __group_attach();
853 }
854
855 static bool __check_visible(void)
856 {
857         GSList *iter = NULL;
858         struct win_node *entry = NULL;
859
860         _DBG("[EVENT_TEST][EVENT] __check_visible\n");
861
862         for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
863                 entry = iter->data;
864                 _DBG("win : %x visibility : %d\n", entry->win, entry->vis);
865                 if (entry->vis == VT_UNOBSCURED)
866                         return true;
867         }
868
869         return false;
870 }
871
872 EXPORT_API void appcore_ui_base_window_on_hide(int type, void *event)
873 {
874         Ecore_Wl2_Event_Window_Hide *ev;
875         int bvisibility;
876
877         ev = event;
878         _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
879
880         if (__find_win((unsigned int)ev->win)) {
881                 __delete_win((unsigned int)ev->win);
882                 bvisibility = __check_visible();
883                 if (!bvisibility && w_status != WS_PAUSE) {
884                         _DBG(" Go to Pasue state \n");
885                         w_status = WS_PAUSE;
886                         __do_pause();
887                 }
888         }
889 }
890
891 EXPORT_API void appcore_ui_base_window_on_lower(int type, void *event)
892 {
893         Ecore_Wl2_Event_Window_Lower *ev;
894
895         ev = event;
896         if (!ev)
897                 return;
898         _DBG("ECORE_WL2_EVENT_WINDOW_LOWER window id:%u\n", ev->win);
899         __group_lower();
900 }
901
902 EXPORT_API void appcore_ui_base_window_on_visibility(int type, void *event)
903 {
904         Ecore_Wl2_Event_Window_Visibility_Change *ev;
905         int bvisibility;
906
907         ev = event;
908         __update_win((unsigned int)ev->win, 0,
909                         ev->fully_obscured ? VT_FULLY_OBSCURED : VT_UNOBSCURED);
910         bvisibility = __check_visible();
911
912         _DBG("bvisibility %d, w_status %d", bvisibility, w_status);
913
914         if (bvisibility && (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL) &&
915                         __context.below_app) {
916                 aul_app_group_activate_below(__context.below_app);
917                 free(__context.below_app);
918                 __context.below_app = NULL;
919         }
920
921         if (bvisibility && w_status != WS_RESUME) {
922                 _DBG(" Go to Resume state\n");
923                 w_status = WS_RESUME;
924                 __do_resume();
925         } else if (!bvisibility && w_status != WS_PAUSE) {
926                 _DBG(" Go to Pasue state \n");
927                 w_status = WS_PAUSE;
928                 __do_pause();
929         } else {
930                 _DBG(" No change state \n");
931         }
932
933 }
934
935 EXPORT_API void appcore_ui_base_window_on_pre_visibility(int type, void *event)
936 {
937         Ecore_Wl2_Event_Window_Pre_Visibility_Change *ev = event;
938         bool bvisibility;
939
940         if (ev && ev->type == ECORE_WL2_WINDOW_VISIBILITY_TYPE_PRE_UNOBSCURED) {
941                 __update_win((unsigned int)ev->win, 0, VT_UNOBSCURED);
942                 bvisibility = __check_visible();
943
944                 _DBG("bvisibility %d, w_status %d", bvisibility, w_status);
945                 if (bvisibility && w_status != WS_RESUME) {
946                         _DBG(" Go to Resume state\n");
947                         w_status = WS_RESUME;
948                         __do_resume();
949                 }
950         }
951 }
952
953 EXPORT_API void appcore_ui_base_window_on_aux_message(int type, void *event)
954 {
955         Ecore_Wl2_Event_Aux_Message *ev = event;
956
957         if (ev->key && !strcmp(ev->key, "dpms_wm")) {
958                 if (ev->val && !strcmp(ev->val, "on")) {
959                         _DBG("Display state: on");
960                         appcore_base_set_display_state(
961                                         APPCORE_BASE_DISPLAY_STATE_ON);
962                 } else if (ev->val && !strcmp(ev->val, "off")) {
963                         _DBG("Display state: off");
964                         appcore_base_set_display_state(
965                                         APPCORE_BASE_DISPLAY_STATE_OFF);
966                 } else {
967                         _ERR("Unknown state: %s", ev->val);
968                 }
969         }
970 }
971
972 EXPORT_API int appcore_ui_base_init(appcore_ui_base_ops ops, int argc, char **argv,
973                 void *data, unsigned int hint)
974 {
975         const char *bg_launch;
976         bundle *b;
977         char appid[PATH_MAX] = {0, };
978         int ret;
979
980         if (!ecore_wl2_init()) {
981                 _ERR("could not wl2 init");
982                 return -1;
983         }
984
985         ecore_wl2_display_connect(NULL);
986         appcore_ui_plugin_init(&ops, argc, argv, &hint);
987         ret = aul_app_get_appid_bypid(getpid(), appid, sizeof(appid));
988         if (ret != 0) {
989                 _ERR("Fail to get appid (%d)", getpid());
990         }
991         __context.ops = ops;
992         __context.data = data;
993         __context.argc = argc;
994         __context.argv = argv;
995         __context.hint = hint;
996         __context.state = AS_NONE;
997         __context.appid = strdup(appid);
998         __context.resource_reclaiming = true;
999
1000         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", appid);
1001         if (__context.hint & APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL) {
1002                 b = bundle_import_from_argv(argc, argv);
1003                 if (b) {
1004                         bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
1005                         if (bg_launch && strcmp(bg_launch, "enable") == 0)
1006                                 __set_bg_state();
1007
1008                         bundle_free(b);
1009                 }
1010         }
1011
1012         return appcore_base_init(ops.base, argc, argv, data);
1013 }
1014
1015 EXPORT_API void appcore_ui_base_fini(void)
1016 {
1017         __del_ecore_events();
1018         __finish_wl();
1019
1020         free(__context.appid);
1021         __context.appid = NULL;
1022
1023         appcore_base_fini();
1024         appcore_ui_plugin_fini();
1025         _ERR("disconnect wl2_display");
1026         ecore_wl2_display_disconnect(ecore_wl2_connected_display_get(NULL));
1027         ecore_wl2_shutdown();
1028 }
1029
1030 EXPORT_API void appcore_ui_base_pause(void)
1031 {
1032         __do_pause();
1033 }
1034
1035 EXPORT_API void appcore_ui_base_resume(void)
1036 {
1037         __do_resume();
1038 }
1039
1040 EXPORT_API bool appcore_ui_base_is_resumed(void)
1041 {
1042         return __context.state == AS_RUNNING;
1043 }
1044
1045 EXPORT_API void appcore_ui_base_exit(void)
1046 {
1047         if (__context.ops.base.exit)
1048                 __context.ops.base.exit(__context.data);
1049 }
1050
1051 EXPORT_API unsigned int appcore_ui_base_get_main_window(void)
1052 {
1053         return __get_main_window();
1054 }
1055
1056 EXPORT_API unsigned int appcore_ui_base_get_main_surface(void)
1057 {
1058         return __get_main_surface();
1059 }
1060
1061 EXPORT_API int appcore_ui_base_get_hint(void)
1062 {
1063         return __context.hint;
1064 }
1065
1066 EXPORT_API bool appcore_ui_base_get_bg_state(void)
1067 {
1068         return __context.bg_state;
1069 }
1070
1071 EXPORT_API void appcore_ui_base_set_bg_state(bool bg_state)
1072 {
1073         __context.bg_state = bg_state;
1074 }
1075
1076 EXPORT_API void appcore_ui_base_set_system_resource_reclaiming(bool enable)
1077 {
1078         __context.resource_reclaiming = enable;
1079 }
1080
1081 static int __on_receive(aul_type type, bundle *b, void *data)
1082 {
1083         return appcore_ui_base_on_receive(type, b);
1084 }
1085
1086 static int __on_create(void *data)
1087 {
1088         return appcore_ui_base_on_create();
1089 }
1090
1091 static int __on_terminate(void *data)
1092 {
1093         return appcore_ui_base_on_terminate();
1094 }
1095
1096 static int __on_pause(void *data)
1097 {
1098         return appcore_ui_base_on_pause();
1099 }
1100
1101 static int __on_resume(void *data)
1102 {
1103         return appcore_ui_base_on_resume();
1104 }
1105
1106 static void __window_on_show(int type, void *event, void *data)
1107 {
1108         appcore_ui_base_window_on_show(type, event);
1109 }
1110
1111 static void __window_on_hide(int type, void *event, void *data)
1112 {
1113         appcore_ui_base_window_on_hide(type, event);
1114 }
1115
1116 static void __window_on_lower(int type, void *event, void *data)
1117 {
1118         appcore_ui_base_window_on_lower(type, event);
1119 }
1120
1121 static void __window_on_visibility(int type, void *event, void *data)
1122 {
1123         appcore_ui_base_window_on_visibility(type, event);
1124 }
1125
1126 static void __window_on_pre_visibility(int type, void *event, void *data)
1127 {
1128         appcore_ui_base_window_on_pre_visibility(type, event);
1129 }
1130
1131 static void __window_on_aux_message(int type, void *event, void *data)
1132 {
1133         appcore_ui_base_window_on_aux_message(type, event);
1134 }
1135
1136 EXPORT_API appcore_ui_base_ops appcore_ui_base_get_default_ops(void)
1137 {
1138         appcore_ui_base_ops ops;
1139
1140         ops.base = appcore_base_get_default_ops();
1141
1142         /* override methods */
1143         ops.base.create = __on_create;
1144         ops.base.terminate = __on_terminate;
1145         ops.base.receive = __on_receive;
1146         ops.base.init = NULL;
1147         ops.base.finish = NULL;
1148         ops.base.run = NULL;
1149         ops.base.exit = NULL;
1150
1151         ops.pause = __on_pause;
1152         ops.resume = __on_resume;
1153         ops.window.show = __window_on_show;
1154         ops.window.hide = __window_on_hide;
1155         ops.window.lower = __window_on_lower;
1156         ops.window.visibility = __window_on_visibility;
1157         ops.window.pre_visibility = __window_on_pre_visibility;
1158         ops.window.aux_message = __window_on_aux_message;
1159
1160         return ops;
1161 }
1162
1163