2 * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <sys/types.h>
19 #include <sys/socket.h>
27 #include <linux/limits.h>
29 #include <Ecore_Wayland.h>
30 #include <wayland-client.h>
31 #include <wayland-tbm-client.h>
32 #include <tizen-extension-client-protocol.h>
35 #include <glib-object.h>
42 #include <bundle_internal.h>
45 #include "appcore_base.h"
46 #include "appcore_ui_base.h"
47 #include "appcore_ui_base_private.h"
48 #include "appcore_ui_plugin.h"
58 typedef struct _appcore_ui_base_context {
59 appcore_ui_base_ops ops;
69 Ecore_Event_Handler *hshow;
70 Ecore_Event_Handler *hhide;
71 Ecore_Event_Handler *hvchange;
72 Ecore_Event_Handler *hlower;
73 Ecore_Event_Handler *hpvchange;
74 } appcore_ui_base_context;
77 static bool b_active = false;
78 static bool first_launch = true;
86 static GSList *g_winnode_list;
87 static appcore_ui_base_context __context;
88 static struct wl_display *dsp;
89 static struct wl_registry *reg;
90 static struct tizen_policy *tz_policy;
92 static void __wl_listener_cb(void *data, struct wl_registry *reg,
93 uint32_t id, const char *interface, uint32_t ver)
95 if (interface && !strcmp(interface, "tizen_policy")) {
97 tz_policy = wl_registry_bind(reg, id,
98 &tizen_policy_interface, 1);
102 static void __wl_listener_remove_cb(void *data, struct wl_registry *reg,
108 static const struct wl_registry_listener reg_listener = {
110 __wl_listener_remove_cb
113 static Eina_Bool __stub_show_cb(void *data, int type, void *event)
115 if (__context.ops.window.show)
116 __context.ops.window.show(type, event, __context.data);
118 return ECORE_CALLBACK_RENEW;
121 static Eina_Bool __stub_hide_cb(void *data, int type, void *event)
123 if (__context.ops.window.hide)
124 __context.ops.window.hide(type, event, __context.data);
126 return ECORE_CALLBACK_RENEW;
129 static Eina_Bool __stub_visibility_cb(void *data, int type, void *event)
131 if (__context.ops.window.visibility)
132 __context.ops.window.visibility(type, event, __context.data);
134 return ECORE_CALLBACK_RENEW;
137 static Eina_Bool __stub_lower_cb(void *data, int type, void *event)
139 if (__context.ops.window.lower)
140 __context.ops.window.lower(type, event, __context.data);
142 return ECORE_CALLBACK_RENEW;
145 static Eina_Bool __stub_pre_visibility_cb(void *data, int type, void *event)
147 if (__context.ops.window.pre_visibility)
148 __context.ops.window.pre_visibility(type, event, __context.data);
150 return ECORE_CALLBACK_RENEW;
153 static void __prepare_to_suspend(void)
155 int suspend = APPCORE_BASE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
157 if (appcore_base_is_bg_allowed() && !appcore_base_is_suspended()) {
158 appcore_base_raise_event((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
159 appcore_base_toggle_suspended_state();
163 static void __exit_from_suspend(void)
165 int suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
167 if (appcore_base_is_suspended()) {
168 appcore_base_raise_event((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
169 appcore_base_toggle_suspended_state();
173 static void __do_pause(void)
175 if (__context.state == AS_RUNNING) {
176 if (__context.ops.pause) {
177 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:PAUSE");
178 __context.ops.pause(__context.data);
179 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
182 __context.state = AS_PAUSED;
183 __prepare_to_suspend();
185 aul_status_update(STATUS_BG);
188 static void __do_resume(void)
190 if (__context.state == AS_PAUSED || __context.state == AS_CREATED) {
191 __exit_from_suspend();
192 if (__context.ops.resume) {
193 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:start]", __context.appid);
194 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESUME");
195 __context.ops.resume(__context.data);
196 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
197 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:done]", __context.appid);
198 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:Launching:done]", __context.appid);
200 if ((__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL) &&
201 __context.below_app) {
202 aul_app_group_activate_below(__context.below_app);
203 free(__context.below_app);
204 __context.below_app = NULL;
206 __context.state = AS_RUNNING;
209 aul_status_update(STATUS_VISIBLE);
212 static GSList *__find_win(unsigned int win)
217 for (iter = g_winnode_list; iter; iter = g_slist_next(iter)) {
219 if (t && t->win == win)
226 static int __get_main_window(void)
228 struct win_node *entry = NULL;
230 if (g_winnode_list != NULL) {
231 entry = g_winnode_list->data;
232 return (unsigned int) entry->win;
238 static int __get_main_surface(void)
240 struct win_node *entry = NULL;
242 if (g_winnode_list != NULL) {
243 entry = g_winnode_list->data;
244 return (unsigned int) entry->surf;
250 static bool __add_win(unsigned int win, unsigned int surf)
255 _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
260 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
264 t = calloc(1, sizeof(struct win_node));
270 t->bfobscured = FALSE;
272 g_winnode_list = g_slist_append(g_winnode_list, t);
277 static bool __delete_win(unsigned int win)
284 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
290 g_winnode_list = g_slist_delete_link(g_winnode_list, f);
295 static bool __update_win(unsigned int win, unsigned int surf, bool bfobscured)
300 _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
306 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
310 t = (struct win_node *)f->data;
314 t->bfobscured = bfobscured;
319 static void __raise_win(void)
321 Ecore_Wl_Window *win;
324 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL))
327 win_id = __get_main_window();
329 _DBG("Raise window: %d", win_id);
330 win = ecore_wl_window_find(win_id);
331 ecore_wl_window_activate(win);
334 static void __pause_win(void)
336 Ecore_Wl_Window *win;
337 GSList *wlist = g_winnode_list;
338 struct win_node *entry = NULL;
340 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL))
343 _DBG("Pause window");
348 _DBG("Pause window: %d", entry->win);
349 win = ecore_wl_window_find(entry->win);
350 ecore_wl_window_iconified_set(win, EINA_TRUE);
356 static int __init_wl(void)
358 _DBG("initialize wayland");
359 dsp = wl_display_connect(NULL);
361 _ERR("Failed to connect wl display");
365 reg = wl_display_get_registry(dsp);
367 _ERR("Failed to get registry");
368 wl_display_disconnect(dsp);
372 wl_registry_add_listener(reg, ®_listener, NULL);
373 wl_display_roundtrip(dsp);
376 _ERR("Failed to get tizen policy interface");
377 wl_registry_destroy(reg);
378 wl_display_disconnect(dsp);
385 static void __finish_wl(void)
388 tizen_policy_destroy(tz_policy);
393 wl_registry_destroy(reg);
398 wl_display_disconnect(dsp);
403 static void __set_bg_state(void)
405 if (!tz_policy && __init_wl() < 0)
408 tizen_policy_set_background_state(tz_policy, getpid());
409 wl_display_roundtrip(dsp);
410 __context.bg_state = true;
411 _DBG("bg state: %d", __context.bg_state);
414 static void __unset_bg_state(void)
419 tizen_policy_unset_background_state(tz_policy, getpid());
420 wl_display_roundtrip(dsp);
421 __context.bg_state = false;
422 _DBG("bg state: %d", __context.bg_state);
425 static void __do_start(bundle *b)
427 const char *bg_launch;
428 const char *below_app;
430 if (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL) {
431 if (__context.below_app) {
432 free(__context.below_app);
433 __context.below_app = NULL;
436 below_app = bundle_get_val(b, AUL_SVC_K_RELOCATE_BELOW);
438 __context.below_app = strdup(below_app);
442 first_launch = FALSE;
446 if (__context.hint & APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL) {
447 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
448 if (bg_launch && strcmp(bg_launch, "enable") == 0) {
449 if (!__context.bg_state &&
450 __context.state != AS_RUNNING)
453 if (__context.bg_state)
458 if (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_AUTO_CONTROL) {
459 if (!__context.bg_state)
464 static int __is_legacy_lifecycle(void)
466 static int is_legacy = -1;
467 const char *api_version;
472 api_version = getenv("TIZEN_API_VERSION");
474 if (strverscmp("2.4", api_version) > 0 &&
475 strverscmp("2.2.1", api_version) < 0)
486 EXPORT_API int appcore_ui_base_on_receive(aul_type type, bundle *b)
488 if (__context.state == AS_DYING) {
489 _ERR("Skip the event in dying state");
493 if (type == AUL_TERMINATE_BGAPP && __context.state != AS_PAUSED)
496 if (type == AUL_START)
497 __exit_from_suspend();
499 appcore_base_on_receive(type, b);
504 if (__context.hint & APPCORE_UI_BASE_HINT_LEGACY_CONTROL) {
505 if (!__context.bg_state && __is_legacy_lifecycle()) {
506 _DBG("Legacy lifecycle");
512 if (__context.bg_state)
518 case AUL_TERMINATE_BGAPP:
519 _DBG("[APP %d] is paused. TERMINATE", getpid());
520 __context.state = AS_DYING;
521 aul_status_update(STATUS_DYING);
522 if (__context.ops.base.exit)
523 __context.ops.base.exit(__context.data);
535 static void __add_ecore_events(void)
537 __context.hshow = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_SHOW,
538 __stub_show_cb, NULL);
539 if (!__context.hshow)
540 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_SHOW event");
542 __context.hhide = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_HIDE,
543 __stub_hide_cb, NULL);
544 if (!__context.hhide)
545 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_HIDE event");
547 __context.hvchange = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE,
548 __stub_visibility_cb, NULL);
549 if (!__context.hvchange)
550 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE event");
552 __context.hlower = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_LOWER,
553 __stub_lower_cb, NULL);
554 if (!__context.hlower)
555 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_LOWER event");
557 __context.hpvchange = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_PRE_VISIBILITY_CHANGE,
558 __stub_pre_visibility_cb, NULL);
559 if (!__context.hpvchange)
560 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_PRE_VISIBILITY_CHANGE event");
563 static void __del_ecore_events(void)
565 if (__context.hshow) {
566 ecore_event_handler_del(__context.hshow);
567 __context.hshow = NULL;
570 if (__context.hhide) {
571 ecore_event_handler_del(__context.hhide);
572 __context.hhide = NULL;
575 if (__context.hvchange) {
576 ecore_event_handler_del(__context.hvchange);
577 __context.hvchange = NULL;
580 if (__context.hlower) {
581 ecore_event_handler_del(__context.hlower);
582 __context.hlower = NULL;
585 if (__context.hpvchange) {
586 ecore_event_handler_del(__context.hpvchange);
587 __context.hpvchange = NULL;
591 EXPORT_API int appcore_ui_base_on_create(void)
593 __add_ecore_events();
594 appcore_base_on_create();
595 __context.state = AS_CREATED;
596 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]", __context.appid);
601 EXPORT_API int appcore_ui_base_on_terminate(void)
603 if (__context.state == AS_RUNNING) {
604 if (__context.ops.pause)
605 __context.ops.pause(__context.data);
608 __context.state = AS_DYING;
610 appcore_base_on_terminate();
615 EXPORT_API int appcore_ui_base_on_pause(void)
620 EXPORT_API int appcore_ui_base_on_resume(void)
625 EXPORT_API int appcore_ui_base_on_control(bundle *b)
627 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]", __context.appid);
628 appcore_base_on_control(b);
629 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]", __context.appid);
634 static void __group_attach()
636 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL))
639 appcore_ui_base_group_add();
642 static void __group_lower()
644 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL))
646 appcore_ui_base_group_remove();
649 EXPORT_API void appcore_ui_base_group_add()
651 static bool attached = false;
653 _DBG("__group_attach");
657 int wid = __get_main_surface();
659 _ERR("window wasn't ready");
663 aul_app_group_set_window(wid);
667 EXPORT_API void appcore_ui_base_group_remove()
671 _DBG("__group_lower");
672 aul_app_group_lower(&exit);
674 _DBG("__group_lower : sub-app!");
675 if (__context.ops.base.exit)
676 __context.ops.base.exit(__context.data);
680 EXPORT_API void appcore_ui_base_window_on_show(int type, void *event)
682 Ecore_Wl_Event_Window_Show *ev;
685 if (ev->parent_win != 0) {
686 /* This is child window. Skip!!! */
690 _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x, %d\n", ev->win, ev->data[0]);
692 if (!__find_win((unsigned int)ev->win))
693 __add_win((unsigned int)ev->win, (unsigned int)ev->data[0]);
695 __update_win((unsigned int)ev->win, (unsigned int)ev->data[0], FALSE);
697 if (ev->data[0] != 0)
701 static bool __check_visible(void)
704 struct win_node *entry = NULL;
706 _DBG("[EVENT_TEST][EVENT] __check_visible\n");
708 for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
710 _DBG("win : %x obscured : %d\n", entry->win, entry->bfobscured);
711 if (entry->bfobscured == FALSE)
718 EXPORT_API void appcore_ui_base_window_on_hide(int type, void *event)
720 Ecore_Wl_Event_Window_Hide *ev;
724 _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
726 if (__find_win((unsigned int)ev->win)) {
727 __delete_win((unsigned int)ev->win);
728 bvisibility = __check_visible();
729 if (!bvisibility && b_active == TRUE) {
730 _DBG(" Go to Pasue state \n");
737 EXPORT_API void appcore_ui_base_window_on_lower(int type, void *event)
739 Ecore_Wl_Event_Window_Lower *ev;
744 _DBG("ECORE_WL_EVENT_WINDOW_LOWER window id:%u\n", ev->win);
748 EXPORT_API void appcore_ui_base_window_on_visibility(int type, void *event)
750 Ecore_Wl_Event_Window_Visibility_Change *ev;
754 __update_win((unsigned int)ev->win, 0, ev->fully_obscured);
755 bvisibility = __check_visible();
757 _DBG("bvisibility %d, b_active %d", bvisibility, b_active);
759 if (bvisibility && b_active == FALSE) {
760 _DBG(" Go to Resume state\n");
763 } else if (!bvisibility && b_active == TRUE) {
764 _DBG(" Go to Pasue state \n");
768 _DBG(" No change state \n");
773 EXPORT_API void appcore_ui_base_window_on_pre_visibility(int type, void *event)
775 Ecore_Wl_Event_Window_Pre_Visibility_Change *ev = event;
778 if (ev && ev->type == ECORE_WL_WINDOW_VISIBILITY_TYPE_PRE_UNOBSCURED) {
779 __update_win((unsigned int)ev->win, 0, false);
780 bvisibility = __check_visible();
782 _DBG("bvisibility %d, b_active %d", bvisibility, b_active);
783 if (bvisibility && b_active == FALSE) {
784 _DBG(" Go to Resume state\n");
791 EXPORT_API int appcore_ui_base_init(appcore_ui_base_ops ops, int argc, char **argv,
792 void *data, unsigned int hint)
794 const char *bg_launch;
796 char appid[PATH_MAX] = {0, };
798 appcore_ui_plugin_init(&ops, argc, argv, &hint);
799 aul_app_get_appid_bypid(getpid(), appid, sizeof(appid));
801 __context.data = data;
802 __context.argc = argc;
803 __context.argv = argv;
804 __context.hint = hint;
805 __context.state = AS_NONE;
806 __context.appid = strdup(appid);
808 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", appid);
809 if (__context.hint & APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL) {
810 b = bundle_import_from_argv(argc, argv);
812 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
813 if (bg_launch && strcmp(bg_launch, "enable") == 0)
820 return appcore_base_init(ops.base, argc, argv, data);
823 EXPORT_API void appcore_ui_base_fini(void)
825 __del_ecore_events();
828 free(__context.appid);
829 __context.appid = NULL;
831 appcore_ui_plugin_fini();
835 EXPORT_API void appcore_ui_base_pause(void)
840 EXPORT_API void appcore_ui_base_resume(void)
845 EXPORT_API bool appcore_ui_base_is_resumed(void)
847 return __context.state == AS_RUNNING;
850 EXPORT_API void appcore_ui_base_exit(void)
852 if (__context.ops.base.exit)
853 __context.ops.base.exit(__context.data);
856 EXPORT_API unsigned int appcore_ui_base_get_main_window(void)
858 return __get_main_window();
861 EXPORT_API unsigned int appcore_ui_base_get_main_surface(void)
863 return __get_main_surface();
866 EXPORT_API int appcore_ui_base_get_hint(void)
868 return __context.hint;
871 EXPORT_API bool appcore_ui_base_get_bg_state(void)
873 return __context.bg_state;
876 EXPORT_API void appcore_ui_base_set_bg_state(bool bg_state)
878 __context.bg_state = bg_state;
881 static int __on_receive(aul_type type, bundle *b, void *data)
883 return appcore_ui_base_on_receive(type, b);
886 static int __on_create(void *data)
888 return appcore_ui_base_on_create();
891 static int __on_terminate(void *data)
893 return appcore_ui_base_on_terminate();
896 static int __on_pause(void *data)
898 return appcore_ui_base_on_pause();
901 static int __on_resume(void *data)
903 return appcore_ui_base_on_resume();
906 static void __window_on_show(int type, void *event, void *data)
908 appcore_ui_base_window_on_show(type, event);
911 static void __window_on_hide(int type, void *event, void *data)
913 appcore_ui_base_window_on_hide(type, event);
916 static void __window_on_lower(int type, void *event, void *data)
918 appcore_ui_base_window_on_lower(type, event);
921 static void __window_on_visibility(int type, void *event, void *data)
923 appcore_ui_base_window_on_visibility(type, event);
926 static void __window_on_pre_visibility(int type, void *event, void *data)
928 appcore_ui_base_window_on_pre_visibility(type, event);
931 EXPORT_API appcore_ui_base_ops appcore_ui_base_get_default_ops(void)
933 appcore_ui_base_ops ops;
935 ops.base = appcore_base_get_default_ops();
937 /* override methods */
938 ops.base.create = __on_create;
939 ops.base.terminate = __on_terminate;
940 ops.base.receive = __on_receive;
941 ops.base.init = NULL;
942 ops.base.finish = NULL;
944 ops.base.exit = NULL;
946 ops.pause = __on_pause;
947 ops.resume = __on_resume;
948 ops.window.show = __window_on_show;
949 ops.window.hide = __window_on_hide;
950 ops.window.lower = __window_on_lower;
951 ops.window.visibility = __window_on_visibility;
952 ops.window.pre_visibility = __window_on_pre_visibility;