Remove suspend timer when resuming app
[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                         appcore_base_remove_suspend_timer();
332                         __context.ops.resume(__context.data);
333                         traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
334                         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:done]", __context.appid);
335                 }
336                 __context.state = AS_RUNNING;
337         }
338
339         aul_status_update(STATUS_VISIBLE);
340 }
341
342 static GSList *__find_win(unsigned int win)
343 {
344         GSList *iter;
345         struct win_node *t;
346
347         for (iter = g_winnode_list; iter; iter = g_slist_next(iter)) {
348                 t = iter->data;
349                 if (t && t->win == win)
350                         return iter;
351         }
352
353         return NULL;
354 }
355
356 static int __get_main_window(void)
357 {
358         struct win_node *entry = NULL;
359
360         if (g_winnode_list != NULL) {
361                 entry = g_winnode_list->data;
362                 return (unsigned int) entry->win;
363         }
364
365         return 0;
366 }
367
368 static int __get_main_surface(void)
369 {
370         struct win_node *entry = NULL;
371
372         if (g_winnode_list != NULL) {
373                 entry = g_winnode_list->data;
374                 return (unsigned int) entry->surf;
375         }
376
377         return 0;
378 }
379
380 static bool __add_win(unsigned int win, unsigned int surf)
381 {
382         struct win_node *t;
383         GSList *f;
384
385         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
386
387         f = __find_win(win);
388         if (f) {
389                 errno = ENOENT;
390                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
391                 return FALSE;
392         }
393
394         t = calloc(1, sizeof(struct win_node));
395         if (t == NULL)
396                 return FALSE;
397
398         t->win = win;
399         t->surf = surf;
400         t->vis = VT_NONE;
401
402         g_winnode_list = g_slist_append(g_winnode_list, t);
403
404         return TRUE;
405 }
406
407 static bool __delete_win(unsigned int win)
408 {
409         GSList *f;
410
411         f = __find_win(win);
412         if (!f) {
413                 errno = ENOENT;
414                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
415                                 win);
416                 return FALSE;
417         }
418
419         free(f->data);
420         g_winnode_list = g_slist_delete_link(g_winnode_list, f);
421
422         return TRUE;
423 }
424
425 static bool __update_win(unsigned int win, unsigned int surf, int vis)
426 {
427         GSList *f;
428         struct win_node *t;
429
430         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x visibility %d\n",
431                         win, vis);
432
433         f = __find_win(win);
434         if (!f) {
435                 errno = ENOENT;
436                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
437                 return FALSE;
438         }
439
440         t = (struct win_node *)f->data;
441         t->win = win;
442         if (surf != 0)
443                 t->surf = surf;
444         if (vis != VT_NONE)
445                 t->vis = vis;
446
447         return TRUE;
448 }
449
450 static void __raise_win(void)
451 {
452         Ecore_Wl2_Window *win;
453         unsigned int win_id;
454
455         if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL))
456                 return;
457
458         win_id = __get_main_window();
459
460         _INFO("Raise window: %d", win_id);
461         win = ecore_wl2_display_window_find(ecore_wl2_connected_display_get(NULL), win_id);
462         ecore_wl2_window_activate(win);
463 }
464
465 static void __pause_win(void)
466 {
467         Ecore_Wl2_Window *win;
468         GSList *wlist = g_winnode_list;
469         struct win_node *entry = NULL;
470
471         if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL))
472                 return;
473
474         _DBG("Pause window");
475
476         while (wlist) {
477                 entry = wlist->data;
478
479                 _DBG("Pause window: %d", entry->win);
480                 win = ecore_wl2_display_window_find(ecore_wl2_connected_display_get(NULL), entry->win);
481                 ecore_wl2_window_iconified_set(win, EINA_TRUE);
482
483                 wlist = wlist->next;
484         }
485 }
486
487 static int __init_wl(void)
488 {
489         _DBG("initialize wayland");
490         dsp = wl_display_connect(NULL);
491         if (dsp == NULL) {
492                 _ERR("Failed to connect wl display");
493                 return -1;
494         }
495
496         reg = wl_display_get_registry(dsp);
497         if (reg == NULL) {
498                 _ERR("Failed to get registry");
499                 wl_display_disconnect(dsp);
500                 return -1;
501         }
502
503         wl_registry_add_listener(reg, &reg_listener, NULL);
504         wl_display_roundtrip(dsp);
505
506         if (!tz_policy) {
507                 _ERR("Failed to get tizen policy interface");
508                 wl_registry_destroy(reg);
509                 wl_display_disconnect(dsp);
510                 return -1;
511         }
512
513         return 0;
514 }
515
516 static void __finish_wl(void)
517 {
518         if (tz_policy) {
519                 tizen_policy_destroy(tz_policy);
520                 tz_policy = NULL;
521         }
522
523         if (reg) {
524                 wl_registry_destroy(reg);
525                 reg = NULL;
526         }
527
528         if (dsp) {
529                 wl_display_disconnect(dsp);
530                 dsp = NULL;
531         }
532 }
533
534 static void __set_bg_state(void)
535 {
536         if (!tz_policy && __init_wl() < 0)
537                 return;
538
539         tizen_policy_set_background_state(tz_policy, getpid());
540         wl_display_roundtrip(dsp);
541         __context.bg_state = true;
542         _DBG("bg state: %d", __context.bg_state);
543 }
544
545 static void __unset_bg_state(void)
546 {
547         if (!tz_policy)
548                 return;
549
550         tizen_policy_unset_background_state(tz_policy, getpid());
551         wl_display_roundtrip(dsp);
552         __context.bg_state = false;
553         _DBG("bg state: %d", __context.bg_state);
554 }
555
556 static void __set_app_id(void)
557 {
558         if (!tz_policy && __init_wl() < 0)
559                 return;
560
561         tizen_policy_set_appid(tz_policy, getpid(), __context.appid);
562         wl_display_roundtrip(dsp);
563         _DBG("set appid: %s", __context.appid);
564 }
565
566 static void __do_start(bundle *b)
567 {
568         const char *bg_launch;
569         const char *below_app;
570         const char *rpc_port;
571
572         if (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL) {
573                 if (__context.below_app) {
574                         free(__context.below_app);
575                         __context.below_app = NULL;
576                 }
577
578                 below_app = bundle_get_val(b, AUL_SVC_K_RELOCATE_BELOW);
579                 if (below_app)
580                         __context.below_app = strdup(below_app);
581         }
582
583         if (first_launch) {
584                 first_launch = FALSE;
585                 return;
586         }
587
588         if (__context.hint & APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL) {
589                 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
590                 if (bg_launch && strcmp(bg_launch, "enable") == 0) {
591                         if (!__context.bg_state &&
592                                         __context.state != AS_RUNNING)
593                                 __set_bg_state();
594                 } else {
595                         if (__context.bg_state)
596                                 __unset_bg_state();
597                 }
598         }
599
600         if (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_AUTO_CONTROL) {
601                 if (!__context.bg_state) {
602                         rpc_port = bundle_get_val(b, AUL_K_RPC_PORT);
603                         if (!rpc_port)
604                                 __raise_win();
605                 }
606         }
607 }
608
609 static int __is_legacy_lifecycle(void)
610 {
611         static int is_legacy = -1;
612         const char *api_version;
613
614         if (is_legacy != -1)
615                 return is_legacy;
616
617         api_version = getenv("TIZEN_API_VERSION");
618         if (api_version) {
619                 if (strverscmp("2.4", api_version) > 0 &&
620                                 strverscmp("2.2.1", api_version) < 0)
621                         is_legacy = 1;
622                 else
623                         is_legacy = 0;
624         } else {
625                 is_legacy = 0;
626         }
627
628         return is_legacy;
629 }
630
631 EXPORT_API int appcore_ui_base_on_receive(aul_type type, bundle *b)
632 {
633         if (__context.state == AS_DYING) {
634                 _ERR("Skip the event in dying state");
635                 return 0;
636         }
637
638         if ((type == AUL_TERMINATE_BGAPP || type == AUL_TERMINATE_BG_INST) &&
639                         __context.state != AS_PAUSED)
640                 return 0;
641
642         if (type == AUL_START)
643                 __exit_from_suspend();
644
645         appcore_base_on_receive(type, b);
646
647         switch (type) {
648         case AUL_START:
649                 __do_start(b);
650                 if (__context.hint & APPCORE_UI_BASE_HINT_LEGACY_CONTROL) {
651                         if (!__context.bg_state && __is_legacy_lifecycle()) {
652                                 _DBG("Legacy lifecycle");
653                                 __do_resume();
654                         }
655                 }
656                 break;
657         case AUL_RESUME:
658                 if (__context.bg_state)
659                         __unset_bg_state();
660                 __raise_win();
661                 break;
662         case AUL_TERMINATE:
663                 __context.state = AS_DYING;
664                 break;
665         case AUL_TERMINATE_BG_INST:
666         case AUL_TERMINATE_INST:
667         case AUL_TERMINATE_BGAPP:
668                 _DBG("[APP %d] TERMINATE", getpid());
669                 __context.state = AS_DYING;
670                 aul_status_update(STATUS_DYING);
671                 if (__context.ops.base.exit)
672                         __context.ops.base.exit(__context.data);
673                 break;
674         case AUL_PAUSE:
675                 __pause_win();
676                 break;
677         default:
678                 break;
679         }
680
681         return 0;
682 }
683
684 static void __add_ecore_events(void)
685 {
686         __context.hshow = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_SHOW,
687                         __stub_show_cb, NULL);
688         if (!__context.hshow)
689                 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_SHOW event");
690
691         __context.hhide = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_HIDE,
692                         __stub_hide_cb, NULL);
693         if (!__context.hhide)
694                 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_HIDE event");
695
696         __context.hvchange = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_VISIBILITY_CHANGE,
697                         __stub_visibility_cb, NULL);
698         if (!__context.hvchange)
699                 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE event");
700
701         __context.hlower = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_LOWER,
702                         __stub_lower_cb, NULL);
703         if (!__context.hlower)
704                 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_LOWER event");
705
706         __context.hpvchange = ecore_event_handler_add(ECORE_WL2_EVENT_WINDOW_PRE_VISIBILITY_CHANGE,
707                         __stub_pre_visibility_cb, NULL);
708         if (!__context.hpvchange)
709                 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_PRE_VISIBILITY_CHANGE event");
710
711         __context.hauxmsg = ecore_event_handler_add(ECORE_WL2_EVENT_AUX_MESSAGE,
712                         __stub_aux_message_cb, NULL);
713         if (!__context.hauxmsg)
714                 _ERR("Failed to add ECORE_WL2_EVENT_AUX_MESSAGE event");
715 }
716
717 static void __del_ecore_events(void)
718 {
719         if (__context.hshow) {
720                 ecore_event_handler_del(__context.hshow);
721                 __context.hshow = NULL;
722         }
723
724         if (__context.hhide) {
725                 ecore_event_handler_del(__context.hhide);
726                 __context.hhide = NULL;
727         }
728
729         if (__context.hvchange) {
730                 ecore_event_handler_del(__context.hvchange);
731                 __context.hvchange = NULL;
732         }
733
734         if (__context.hlower) {
735                 ecore_event_handler_del(__context.hlower);
736                 __context.hlower = NULL;
737         }
738
739         if (__context.hpvchange) {
740                 ecore_event_handler_del(__context.hpvchange);
741                 __context.hpvchange = NULL;
742         }
743
744         if (__context.hauxmsg) {
745                 ecore_event_handler_del(__context.hauxmsg);
746                 __context.hauxmsg = NULL;
747         }
748 }
749
750 EXPORT_API int appcore_ui_base_on_create(void)
751 {
752         __add_ecore_events();
753         appcore_base_on_create();
754         __context.state = AS_CREATED;
755         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]", __context.appid);
756
757         return 0;
758 }
759
760 EXPORT_API int appcore_ui_base_on_terminate(void)
761 {
762         if (__context.state == AS_RUNNING) {
763                 if (__context.ops.pause) {
764                         _DBG("Call pause callback");
765                         __context.ops.pause(__context.data);
766                 }
767         }
768
769         __context.state = AS_DYING;
770
771         appcore_base_on_terminate();
772
773         return 0;
774 }
775
776 EXPORT_API int appcore_ui_base_on_pause(void)
777 {
778         return 0;
779 }
780
781 EXPORT_API int appcore_ui_base_on_resume(void)
782 {
783         return 0;
784 }
785
786 EXPORT_API int appcore_ui_base_on_control(bundle *b)
787 {
788         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]", __context.appid);
789         appcore_base_on_control(b);
790         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]", __context.appid);
791
792         return 0;
793 }
794
795 EXPORT_API int appcore_ui_base_on_trim_memory(void)
796 {
797         return appcore_base_on_trim_memory();
798 }
799
800 static void __group_attach()
801 {
802         if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL))
803                 return;
804
805         appcore_ui_base_group_add();
806 }
807
808 static void __group_lower()
809 {
810         if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL))
811                 return;
812         appcore_ui_base_group_remove();
813 }
814
815 EXPORT_API int appcore_ui_base_group_add()
816 {
817         static bool attached = false;
818         int ret;
819
820         _DBG("__group_attach");
821         if (attached)
822                 return 0;
823
824         int wid = __get_main_surface();
825         if (wid == 0) {
826                 _ERR("window wasn't ready");
827                 return -1;
828         }
829
830         ret = aul_app_group_set_window(wid);
831         if (ret < 0) {
832                 _ERR("Failed to set app group window. error(%d)", ret);
833                 return ret;
834         }
835
836         attached = true;
837         return 0;
838 }
839
840 EXPORT_API void appcore_ui_base_group_remove()
841 {
842         int exit = 0;
843
844         _DBG("__group_lower");
845         aul_app_group_lower(&exit);
846         if (exit) {
847                 _DBG("__group_lower : sub-app!");
848                 if (__context.ops.base.exit)
849                         __context.ops.base.exit(__context.data);
850         }
851 }
852
853 EXPORT_API void appcore_ui_base_window_on_show(int type, void *event)
854 {
855         Ecore_Wl2_Event_Window_Show *ev;
856
857         ev = event;
858         if (ev->parent_win != 0) {
859                 /* This is child window. Skip!!! */
860                 return;
861         }
862
863         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x, %d\n",
864                         ev->win, ev->data[0]);
865
866         if (!__find_win((unsigned int)ev->win)) {
867                 __add_win((unsigned int)ev->win, (unsigned int)ev->data[0]);
868         } else {
869                 __update_win((unsigned int)ev->win, (unsigned int)ev->data[0],
870                                 VT_NONE);
871         }
872
873         if (ev->data[0] != 0)
874                 __group_attach();
875 }
876
877 static bool __check_visible(void)
878 {
879         GSList *iter = NULL;
880         struct win_node *entry = NULL;
881
882         _DBG("[EVENT_TEST][EVENT] __check_visible\n");
883
884         for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
885                 entry = iter->data;
886                 _DBG("win : %x visibility : %d\n", entry->win, entry->vis);
887                 if (entry->vis == VT_UNOBSCURED)
888                         return true;
889         }
890
891         return false;
892 }
893
894 EXPORT_API void appcore_ui_base_window_on_hide(int type, void *event)
895 {
896         Ecore_Wl2_Event_Window_Hide *ev;
897         int bvisibility;
898
899         ev = event;
900         _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
901
902         if (__find_win((unsigned int)ev->win)) {
903                 __delete_win((unsigned int)ev->win);
904                 bvisibility = __check_visible();
905                 if (!bvisibility && w_status != WS_PAUSE) {
906                         _DBG(" Go to Pasue state \n");
907                         w_status = WS_PAUSE;
908                         __do_pause();
909                 }
910         }
911 }
912
913 EXPORT_API void appcore_ui_base_window_on_lower(int type, void *event)
914 {
915         Ecore_Wl2_Event_Window_Lower *ev;
916
917         ev = event;
918         if (!ev)
919                 return;
920         _DBG("ECORE_WL2_EVENT_WINDOW_LOWER window id:%u\n", ev->win);
921         __group_lower();
922 }
923
924 EXPORT_API void appcore_ui_base_window_on_visibility(int type, void *event)
925 {
926         Ecore_Wl2_Event_Window_Visibility_Change *ev;
927         int bvisibility;
928
929         ev = event;
930         __update_win((unsigned int)ev->win, 0,
931                         ev->fully_obscured ? VT_FULLY_OBSCURED : VT_UNOBSCURED);
932         bvisibility = __check_visible();
933
934         _DBG("bvisibility %d, w_status %d", bvisibility, w_status);
935
936         if (bvisibility && (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL) &&
937                         __context.below_app) {
938                 aul_app_group_activate_below(__context.below_app);
939                 free(__context.below_app);
940                 __context.below_app = NULL;
941         }
942
943         if (bvisibility && w_status != WS_RESUME) {
944                 _DBG(" Go to Resume state\n");
945                 w_status = WS_RESUME;
946                 __do_resume();
947         } else if (!bvisibility && w_status != WS_PAUSE) {
948                 _DBG(" Go to Pasue state \n");
949                 w_status = WS_PAUSE;
950                 __do_pause();
951         } else {
952                 _DBG(" No change state \n");
953         }
954
955 }
956
957 EXPORT_API void appcore_ui_base_window_on_pre_visibility(int type, void *event)
958 {
959         Ecore_Wl2_Event_Window_Pre_Visibility_Change *ev = event;
960         bool bvisibility;
961
962         if (ev && ev->type == ECORE_WL2_WINDOW_VISIBILITY_TYPE_PRE_UNOBSCURED) {
963                 __update_win((unsigned int)ev->win, 0, VT_UNOBSCURED);
964                 bvisibility = __check_visible();
965
966                 _DBG("bvisibility %d, w_status %d", bvisibility, w_status);
967                 if (bvisibility && w_status != WS_RESUME) {
968                         _DBG(" Go to Resume state\n");
969                         w_status = WS_RESUME;
970                         __do_resume();
971                 }
972         }
973 }
974
975 EXPORT_API void appcore_ui_base_window_on_aux_message(int type, void *event)
976 {
977         Ecore_Wl2_Event_Aux_Message *ev = event;
978
979         if (ev->key && !strcmp(ev->key, "dpms_wm")) {
980                 if (ev->val && !strcmp(ev->val, "on")) {
981                         _DBG("Display state: on");
982                         appcore_base_set_display_state(
983                                         APPCORE_BASE_DISPLAY_STATE_ON);
984                 } else if (ev->val && !strcmp(ev->val, "off")) {
985                         _DBG("Display state: off");
986                         appcore_base_set_display_state(
987                                         APPCORE_BASE_DISPLAY_STATE_OFF);
988                 } else {
989                         _ERR("Unknown state: %s", ev->val);
990                 }
991         }
992 }
993
994 EXPORT_API int appcore_ui_base_init(appcore_ui_base_ops ops, int argc, char **argv,
995                 void *data, unsigned int hint)
996 {
997         const char *bg_launch;
998         bundle *b;
999         char appid[PATH_MAX] = {0, };
1000         int ret;
1001
1002         if (!ecore_wl2_init()) {
1003                 _ERR("could not wl2 init");
1004                 return -1;
1005         }
1006
1007         ecore_wl2_display_connect(NULL);
1008         appcore_ui_plugin_init(&ops, argc, argv, &hint);
1009         ret = aul_app_get_appid_bypid(getpid(), appid, sizeof(appid));
1010         if (ret != 0) {
1011                 _ERR("Fail to get appid (%d)", getpid());
1012         }
1013         __context.ops = ops;
1014         __context.data = data;
1015         __context.argc = argc;
1016         __context.argv = argv;
1017         __context.hint = hint;
1018         __context.state = AS_NONE;
1019         __context.appid = strdup(appid);
1020         __context.resource_reclaiming = true;
1021
1022         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", appid);
1023         if (__context.hint & APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL) {
1024                 b = bundle_import_from_argv(argc, argv);
1025                 if (b) {
1026                         bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
1027                         if (bg_launch && strcmp(bg_launch, "enable") == 0)
1028                                 __set_bg_state();
1029
1030                         bundle_free(b);
1031                 }
1032         }
1033
1034         if (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_ID_CONTROL)
1035                 __set_app_id();
1036
1037         return appcore_base_init(ops.base, argc, argv, data);
1038 }
1039
1040 EXPORT_API void appcore_ui_base_fini(void)
1041 {
1042         __del_ecore_events();
1043         __finish_wl();
1044
1045         free(__context.appid);
1046         __context.appid = NULL;
1047
1048         appcore_base_fini();
1049         appcore_ui_plugin_fini();
1050         _ERR("disconnect wl2_display");
1051         ecore_wl2_display_disconnect(ecore_wl2_connected_display_get(NULL));
1052         ecore_wl2_shutdown();
1053 }
1054
1055 EXPORT_API void appcore_ui_base_pause(void)
1056 {
1057         __do_pause();
1058 }
1059
1060 EXPORT_API void appcore_ui_base_resume(void)
1061 {
1062         __do_resume();
1063 }
1064
1065 EXPORT_API bool appcore_ui_base_is_resumed(void)
1066 {
1067         return __context.state == AS_RUNNING;
1068 }
1069
1070 EXPORT_API void appcore_ui_base_exit(void)
1071 {
1072         if (__context.ops.base.exit)
1073                 __context.ops.base.exit(__context.data);
1074 }
1075
1076 EXPORT_API unsigned int appcore_ui_base_get_main_window(void)
1077 {
1078         return __get_main_window();
1079 }
1080
1081 EXPORT_API unsigned int appcore_ui_base_get_main_surface(void)
1082 {
1083         return __get_main_surface();
1084 }
1085
1086 EXPORT_API int appcore_ui_base_get_hint(void)
1087 {
1088         return __context.hint;
1089 }
1090
1091 EXPORT_API bool appcore_ui_base_get_bg_state(void)
1092 {
1093         return __context.bg_state;
1094 }
1095
1096 EXPORT_API void appcore_ui_base_set_bg_state(bool bg_state)
1097 {
1098         __context.bg_state = bg_state;
1099 }
1100
1101 EXPORT_API void appcore_ui_base_set_system_resource_reclaiming(bool enable)
1102 {
1103         __context.resource_reclaiming = enable;
1104 }
1105
1106 static int __on_receive(aul_type type, bundle *b, void *data)
1107 {
1108         return appcore_ui_base_on_receive(type, b);
1109 }
1110
1111 static int __on_create(void *data)
1112 {
1113         return appcore_ui_base_on_create();
1114 }
1115
1116 static int __on_terminate(void *data)
1117 {
1118         return appcore_ui_base_on_terminate();
1119 }
1120
1121 static int __on_pause(void *data)
1122 {
1123         return appcore_ui_base_on_pause();
1124 }
1125
1126 static int __on_resume(void *data)
1127 {
1128         return appcore_ui_base_on_resume();
1129 }
1130
1131 static void __window_on_show(int type, void *event, void *data)
1132 {
1133         appcore_ui_base_window_on_show(type, event);
1134 }
1135
1136 static void __window_on_hide(int type, void *event, void *data)
1137 {
1138         appcore_ui_base_window_on_hide(type, event);
1139 }
1140
1141 static void __window_on_lower(int type, void *event, void *data)
1142 {
1143         appcore_ui_base_window_on_lower(type, event);
1144 }
1145
1146 static void __window_on_visibility(int type, void *event, void *data)
1147 {
1148         appcore_ui_base_window_on_visibility(type, event);
1149 }
1150
1151 static void __window_on_pre_visibility(int type, void *event, void *data)
1152 {
1153         appcore_ui_base_window_on_pre_visibility(type, event);
1154 }
1155
1156 static void __window_on_aux_message(int type, void *event, void *data)
1157 {
1158         appcore_ui_base_window_on_aux_message(type, event);
1159 }
1160
1161 EXPORT_API appcore_ui_base_ops appcore_ui_base_get_default_ops(void)
1162 {
1163         appcore_ui_base_ops ops;
1164
1165         ops.base = appcore_base_get_default_ops();
1166
1167         /* override methods */
1168         ops.base.create = __on_create;
1169         ops.base.terminate = __on_terminate;
1170         ops.base.receive = __on_receive;
1171         ops.base.init = NULL;
1172         ops.base.finish = NULL;
1173         ops.base.run = NULL;
1174         ops.base.exit = NULL;
1175
1176         ops.pause = __on_pause;
1177         ops.resume = __on_resume;
1178         ops.window.show = __window_on_show;
1179         ops.window.hide = __window_on_hide;
1180         ops.window.lower = __window_on_lower;
1181         ops.window.visibility = __window_on_visibility;
1182         ops.window.pre_visibility = __window_on_pre_visibility;
1183         ops.window.aux_message = __window_on_aux_message;
1184
1185         return ops;
1186 }
1187
1188