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