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_cb_conformant(void *data,
93 struct tizen_policy *tizen_policy,
94 struct wl_surface *surface_resource,
95 uint32_t is_conformant)
100 static void _wl_cb_conformant_area(void *data,
101 struct tizen_policy *tizen_policy,
102 struct wl_surface *surface_resource,
103 uint32_t conformant_part,
105 int32_t x, int32_t y, int32_t w, int32_t h)
110 static void _wl_cb_notification_done(void *data,
111 struct tizen_policy *tizen_policy,
112 struct wl_surface *surface,
119 static void _wl_cb_transient_for_done(void *data,
120 struct tizen_policy *tizen_policy,
126 static void _wl_cb_scr_mode_done(void *data,
127 struct tizen_policy *tizen_policy,
128 struct wl_surface *surface,
135 static void _wl_cb_iconify_state_changed(void *data,
136 struct tizen_policy *tizen_policy,
137 struct wl_surface *surface_resource,
144 static void _wl_cb_supported_aux_hints(void *data,
145 struct tizen_policy *tizen_policy,
146 struct wl_surface *surface_resource,
147 struct wl_array *hints,
153 static void _wl_cb_allowed_aux_hint(void *data,
154 struct tizen_policy *tizen_policy,
155 struct wl_surface *surface_resource,
161 static void _wl_cb_aux_message(void *data,
162 struct tizen_policy *tizen_policy,
163 struct wl_surface *surface_resource,
166 struct wl_array *options)
171 static void _wl_cb_conformant_region(void *data,
172 struct tizen_policy *tizen_policy,
173 struct wl_surface *surface,
174 uint32_t conformant_part,
176 int32_t x, int32_t y, int32_t w, int32_t h,
182 static const struct tizen_policy_listener _tizen_policy_listener = {
184 _wl_cb_conformant_area,
185 _wl_cb_notification_done,
186 _wl_cb_transient_for_done,
187 _wl_cb_scr_mode_done,
188 _wl_cb_iconify_state_changed,
189 _wl_cb_supported_aux_hints,
190 _wl_cb_allowed_aux_hint,
192 _wl_cb_conformant_region,
195 static void __wl_listener_cb(void *data, struct wl_registry *reg,
196 uint32_t id, const char *interface, uint32_t ver)
198 if (interface && !strcmp(interface, "tizen_policy")) {
200 tz_policy = wl_registry_bind(reg, id,
201 &tizen_policy_interface, 7);
203 tizen_policy_add_listener(tz_policy, &_tizen_policy_listener, dsp);
208 static void __wl_listener_remove_cb(void *data, struct wl_registry *reg,
214 static const struct wl_registry_listener reg_listener = {
216 __wl_listener_remove_cb
219 static Eina_Bool __stub_show_cb(void *data, int type, void *event)
221 if (__context.ops.window.show)
222 __context.ops.window.show(type, event, __context.data);
224 return ECORE_CALLBACK_RENEW;
227 static Eina_Bool __stub_hide_cb(void *data, int type, void *event)
229 if (__context.ops.window.hide)
230 __context.ops.window.hide(type, event, __context.data);
232 return ECORE_CALLBACK_RENEW;
235 static Eina_Bool __stub_visibility_cb(void *data, int type, void *event)
237 if (__context.ops.window.visibility)
238 __context.ops.window.visibility(type, event, __context.data);
240 return ECORE_CALLBACK_RENEW;
243 static Eina_Bool __stub_lower_cb(void *data, int type, void *event)
245 if (__context.ops.window.lower)
246 __context.ops.window.lower(type, event, __context.data);
248 return ECORE_CALLBACK_RENEW;
251 static Eina_Bool __stub_pre_visibility_cb(void *data, int type, void *event)
253 if (__context.ops.window.pre_visibility)
254 __context.ops.window.pre_visibility(type, event, __context.data);
256 return ECORE_CALLBACK_RENEW;
259 static void __prepare_to_suspend(void)
261 int suspend = APPCORE_BASE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
263 if (appcore_base_is_bg_allowed() && !appcore_base_is_suspended()) {
264 appcore_base_raise_event((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
265 appcore_base_toggle_suspended_state();
269 static void __exit_from_suspend(void)
271 int suspend = APPCORE_BASE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
273 if (appcore_base_is_suspended()) {
274 appcore_base_raise_event((void *)&suspend, APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE);
275 appcore_base_toggle_suspended_state();
279 static void __do_pause(void)
281 if (__context.state == AS_RUNNING) {
282 if (__context.ops.pause) {
283 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:PAUSE");
284 __context.ops.pause(__context.data);
285 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
288 __context.state = AS_PAUSED;
289 __prepare_to_suspend();
291 aul_status_update(STATUS_BG);
294 static void __do_resume(void)
296 if (__context.state == AS_PAUSED || __context.state == AS_CREATED) {
297 __exit_from_suspend();
298 if (__context.ops.resume) {
299 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:start]", __context.appid);
300 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:RESUME");
301 __context.ops.resume(__context.data);
302 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
303 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:done]", __context.appid);
305 if ((__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL) &&
306 __context.below_app) {
307 aul_app_group_activate_below(__context.below_app);
308 free(__context.below_app);
309 __context.below_app = NULL;
311 __context.state = AS_RUNNING;
314 aul_status_update(STATUS_VISIBLE);
317 static GSList *__find_win(unsigned int win)
322 for (iter = g_winnode_list; iter; iter = g_slist_next(iter)) {
324 if (t && t->win == win)
331 static int __get_main_window(void)
333 struct win_node *entry = NULL;
335 if (g_winnode_list != NULL) {
336 entry = g_winnode_list->data;
337 return (unsigned int) entry->win;
343 static int __get_main_surface(void)
345 struct win_node *entry = NULL;
347 if (g_winnode_list != NULL) {
348 entry = g_winnode_list->data;
349 return (unsigned int) entry->surf;
355 static bool __add_win(unsigned int win, unsigned int surf)
360 _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
365 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
369 t = calloc(1, sizeof(struct win_node));
375 t->bfobscured = FALSE;
377 g_winnode_list = g_slist_append(g_winnode_list, t);
382 static bool __delete_win(unsigned int win)
389 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
395 g_winnode_list = g_slist_delete_link(g_winnode_list, f);
400 static bool __update_win(unsigned int win, unsigned int surf, bool bfobscured)
405 _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
411 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
415 t = (struct win_node *)f->data;
419 t->bfobscured = bfobscured;
424 static void __raise_win(void)
426 Ecore_Wl_Window *win;
429 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL))
432 win_id = __get_main_window();
434 _DBG("Raise window: %d", win_id);
435 win = ecore_wl_window_find(win_id);
436 ecore_wl_window_activate(win);
439 static void __pause_win(void)
441 Ecore_Wl_Window *win;
442 GSList *wlist = g_winnode_list;
443 struct win_node *entry = NULL;
445 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL))
448 _DBG("Pause window");
453 _DBG("Pause window: %d", entry->win);
454 win = ecore_wl_window_find(entry->win);
455 ecore_wl_window_iconified_set(win, EINA_TRUE);
461 static int __init_wl(void)
463 _DBG("initialize wayland");
464 dsp = wl_display_connect(NULL);
466 _ERR("Failed to connect wl display");
470 reg = wl_display_get_registry(dsp);
472 _ERR("Failed to get registry");
473 wl_display_disconnect(dsp);
477 wl_registry_add_listener(reg, ®_listener, NULL);
478 wl_display_roundtrip(dsp);
481 _ERR("Failed to get tizen policy interface");
482 wl_registry_destroy(reg);
483 wl_display_disconnect(dsp);
490 static void __finish_wl(void)
493 tizen_policy_destroy(tz_policy);
498 wl_registry_destroy(reg);
503 wl_display_disconnect(dsp);
508 static void __set_bg_state(void)
510 if (!tz_policy && __init_wl() < 0)
513 tizen_policy_set_background_state(tz_policy, getpid());
514 wl_display_roundtrip(dsp);
515 __context.bg_state = true;
516 _DBG("bg state: %d", __context.bg_state);
519 static void __unset_bg_state(void)
524 tizen_policy_unset_background_state(tz_policy, getpid());
525 wl_display_roundtrip(dsp);
526 __context.bg_state = false;
527 _DBG("bg state: %d", __context.bg_state);
530 static void __do_start(bundle *b)
532 const char *bg_launch;
533 const char *below_app;
535 if (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL) {
536 if (__context.below_app) {
537 free(__context.below_app);
538 __context.below_app = NULL;
541 below_app = bundle_get_val(b, AUL_SVC_K_RELOCATE_BELOW);
543 __context.below_app = strdup(below_app);
547 first_launch = FALSE;
551 if (__context.hint & APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL) {
552 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
553 if (bg_launch && strcmp(bg_launch, "enable") == 0) {
554 if (!__context.bg_state &&
555 __context.state != AS_RUNNING)
558 if (__context.bg_state)
563 if (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_AUTO_CONTROL) {
564 if (!__context.bg_state)
569 static int __is_legacy_lifecycle(void)
571 static int is_legacy = -1;
572 const char *api_version;
577 api_version = getenv("TIZEN_API_VERSION");
579 if (strverscmp("2.4", api_version) > 0 &&
580 strverscmp("2.2.1", api_version) < 0)
591 EXPORT_API int appcore_ui_base_on_receive(aul_type type, bundle *b)
593 if (__context.state == AS_DYING) {
594 _ERR("Skip the event in dying state");
598 if (type == AUL_TERMINATE_BGAPP && __context.state != AS_PAUSED)
601 if (type == AUL_START)
602 __exit_from_suspend();
604 appcore_base_on_receive(type, b);
609 if (__context.hint & APPCORE_UI_BASE_HINT_LEGACY_CONTROL) {
610 if (!__context.bg_state && __is_legacy_lifecycle()) {
611 _DBG("Legacy lifecycle");
617 if (__context.bg_state)
623 case AUL_TERMINATE_BGAPP:
624 _DBG("[APP %d] is paused. TERMINATE", getpid());
625 __context.state = AS_DYING;
626 aul_status_update(STATUS_DYING);
627 if (__context.ops.base.exit)
628 __context.ops.base.exit(__context.data);
640 static void __add_ecore_events(void)
642 __context.hshow = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_SHOW,
643 __stub_show_cb, NULL);
644 if (!__context.hshow)
645 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_SHOW event");
647 __context.hhide = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_HIDE,
648 __stub_hide_cb, NULL);
649 if (!__context.hhide)
650 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_HIDE event");
652 __context.hvchange = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE,
653 __stub_visibility_cb, NULL);
654 if (!__context.hvchange)
655 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE event");
657 __context.hlower = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_LOWER,
658 __stub_lower_cb, NULL);
659 if (!__context.hlower)
660 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_LOWER event");
662 __context.hpvchange = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_PRE_VISIBILITY_CHANGE,
663 __stub_pre_visibility_cb, NULL);
664 if (!__context.hpvchange)
665 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_PRE_VISIBILITY_CHANGE event");
668 static void __del_ecore_events(void)
670 if (__context.hshow) {
671 ecore_event_handler_del(__context.hshow);
672 __context.hshow = NULL;
675 if (__context.hhide) {
676 ecore_event_handler_del(__context.hhide);
677 __context.hhide = NULL;
680 if (__context.hvchange) {
681 ecore_event_handler_del(__context.hvchange);
682 __context.hvchange = NULL;
685 if (__context.hlower) {
686 ecore_event_handler_del(__context.hlower);
687 __context.hlower = NULL;
690 if (__context.hpvchange) {
691 ecore_event_handler_del(__context.hpvchange);
692 __context.hpvchange = NULL;
696 EXPORT_API int appcore_ui_base_on_create(void)
698 __add_ecore_events();
699 appcore_base_on_create();
700 __context.state = AS_CREATED;
701 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]", __context.appid);
706 EXPORT_API int appcore_ui_base_on_terminate(void)
708 if (__context.state == AS_RUNNING) {
709 if (__context.ops.pause)
710 __context.ops.pause(__context.data);
713 __context.state = AS_DYING;
715 appcore_base_on_terminate();
720 EXPORT_API int appcore_ui_base_on_pause(void)
725 EXPORT_API int appcore_ui_base_on_resume(void)
730 EXPORT_API int appcore_ui_base_on_control(bundle *b)
732 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]", __context.appid);
733 appcore_base_on_control(b);
734 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]", __context.appid);
739 static void __group_attach()
741 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL))
744 appcore_ui_base_group_add();
747 static void __group_lower()
749 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL))
751 appcore_ui_base_group_remove();
754 EXPORT_API void appcore_ui_base_group_add()
756 static bool attached = false;
758 _DBG("__group_attach");
762 int wid = __get_main_surface();
764 _ERR("window wasn't ready");
768 aul_app_group_set_window(wid);
772 EXPORT_API void appcore_ui_base_group_remove()
776 _DBG("__group_lower");
777 aul_app_group_lower(&exit);
779 _DBG("__group_lower : sub-app!");
780 if (__context.ops.base.exit)
781 __context.ops.base.exit(__context.data);
785 EXPORT_API void appcore_ui_base_window_on_show(int type, void *event)
787 Ecore_Wl_Event_Window_Show *ev;
790 if (ev->parent_win != 0) {
791 /* This is child window. Skip!!! */
795 _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x, %d\n", ev->win, ev->data[0]);
797 if (!__find_win((unsigned int)ev->win))
798 __add_win((unsigned int)ev->win, (unsigned int)ev->data[0]);
800 __update_win((unsigned int)ev->win, (unsigned int)ev->data[0], FALSE);
802 if (ev->data[0] != 0)
806 static bool __check_visible(void)
809 struct win_node *entry = NULL;
811 _DBG("[EVENT_TEST][EVENT] __check_visible\n");
813 for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
815 _DBG("win : %x obscured : %d\n", entry->win, entry->bfobscured);
816 if (entry->bfobscured == FALSE)
823 EXPORT_API void appcore_ui_base_window_on_hide(int type, void *event)
825 Ecore_Wl_Event_Window_Hide *ev;
829 _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
831 if (__find_win((unsigned int)ev->win)) {
832 __delete_win((unsigned int)ev->win);
833 bvisibility = __check_visible();
834 if (!bvisibility && b_active == TRUE) {
835 _DBG(" Go to Pasue state \n");
842 EXPORT_API void appcore_ui_base_window_on_lower(int type, void *event)
844 Ecore_Wl_Event_Window_Lower *ev;
849 _DBG("ECORE_WL_EVENT_WINDOW_LOWER window id:%u\n", ev->win);
853 EXPORT_API void appcore_ui_base_window_on_visibility(int type, void *event)
855 Ecore_Wl_Event_Window_Visibility_Change *ev;
859 __update_win((unsigned int)ev->win, 0, ev->fully_obscured);
860 bvisibility = __check_visible();
862 _DBG("bvisibility %d, b_active %d", bvisibility, b_active);
864 if (bvisibility && b_active == FALSE) {
865 _DBG(" Go to Resume state\n");
868 } else if (!bvisibility && b_active == TRUE) {
869 _DBG(" Go to Pasue state \n");
873 _DBG(" No change state \n");
878 EXPORT_API void appcore_ui_base_window_on_pre_visibility(int type, void *event)
880 Ecore_Wl_Event_Window_Pre_Visibility_Change *ev = event;
883 if (ev && ev->type == ECORE_WL_WINDOW_VISIBILITY_TYPE_PRE_UNOBSCURED) {
884 __update_win((unsigned int)ev->win, 0, false);
885 bvisibility = __check_visible();
887 _DBG("bvisibility %d, b_active %d", bvisibility, b_active);
888 if (bvisibility && b_active == FALSE) {
889 _DBG(" Go to Resume state\n");
896 EXPORT_API int appcore_ui_base_init(appcore_ui_base_ops ops, int argc, char **argv,
897 void *data, unsigned int hint)
899 const char *bg_launch;
901 char appid[PATH_MAX] = {0, };
905 appcore_ui_plugin_init(&ops, argc, argv, &hint);
906 aul_app_get_appid_bypid(getpid(), appid, sizeof(appid));
908 __context.data = data;
909 __context.argc = argc;
910 __context.argv = argv;
911 __context.hint = hint;
912 __context.state = AS_NONE;
913 __context.appid = strdup(appid);
915 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", appid);
916 if (__context.hint & APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL) {
917 b = bundle_import_from_argv(argc, argv);
919 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
920 if (bg_launch && strcmp(bg_launch, "enable") == 0)
927 return appcore_base_init(ops.base, argc, argv, data);
930 EXPORT_API void appcore_ui_base_fini(void)
932 __del_ecore_events();
935 free(__context.appid);
936 __context.appid = NULL;
939 appcore_ui_plugin_fini();
943 EXPORT_API void appcore_ui_base_pause(void)
948 EXPORT_API void appcore_ui_base_resume(void)
953 EXPORT_API bool appcore_ui_base_is_resumed(void)
955 return __context.state == AS_RUNNING;
958 EXPORT_API void appcore_ui_base_exit(void)
960 if (__context.ops.base.exit)
961 __context.ops.base.exit(__context.data);
964 EXPORT_API unsigned int appcore_ui_base_get_main_window(void)
966 return __get_main_window();
969 EXPORT_API unsigned int appcore_ui_base_get_main_surface(void)
971 return __get_main_surface();
974 EXPORT_API int appcore_ui_base_get_hint(void)
976 return __context.hint;
979 EXPORT_API bool appcore_ui_base_get_bg_state(void)
981 return __context.bg_state;
984 EXPORT_API void appcore_ui_base_set_bg_state(bool bg_state)
986 __context.bg_state = bg_state;
989 static int __on_receive(aul_type type, bundle *b, void *data)
991 return appcore_ui_base_on_receive(type, b);
994 static int __on_create(void *data)
996 return appcore_ui_base_on_create();
999 static int __on_terminate(void *data)
1001 return appcore_ui_base_on_terminate();
1004 static int __on_pause(void *data)
1006 return appcore_ui_base_on_pause();
1009 static int __on_resume(void *data)
1011 return appcore_ui_base_on_resume();
1014 static void __window_on_show(int type, void *event, void *data)
1016 appcore_ui_base_window_on_show(type, event);
1019 static void __window_on_hide(int type, void *event, void *data)
1021 appcore_ui_base_window_on_hide(type, event);
1024 static void __window_on_lower(int type, void *event, void *data)
1026 appcore_ui_base_window_on_lower(type, event);
1029 static void __window_on_visibility(int type, void *event, void *data)
1031 appcore_ui_base_window_on_visibility(type, event);
1034 static void __window_on_pre_visibility(int type, void *event, void *data)
1036 appcore_ui_base_window_on_pre_visibility(type, event);
1039 EXPORT_API appcore_ui_base_ops appcore_ui_base_get_default_ops(void)
1041 appcore_ui_base_ops ops;
1043 ops.base = appcore_base_get_default_ops();
1045 /* override methods */
1046 ops.base.create = __on_create;
1047 ops.base.terminate = __on_terminate;
1048 ops.base.receive = __on_receive;
1049 ops.base.init = NULL;
1050 ops.base.finish = NULL;
1051 ops.base.run = NULL;
1052 ops.base.exit = NULL;
1054 ops.pause = __on_pause;
1055 ops.resume = __on_resume;
1056 ops.window.show = __window_on_show;
1057 ops.window.hide = __window_on_hide;
1058 ops.window.lower = __window_on_lower;
1059 ops.window.visibility = __window_on_visibility;
1060 ops.window.pre_visibility = __window_on_pre_visibility;