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);
199 if ((__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL) &&
200 __context.below_app) {
201 aul_app_group_activate_below(__context.below_app);
202 free(__context.below_app);
203 __context.below_app = NULL;
205 __context.state = AS_RUNNING;
208 aul_status_update(STATUS_VISIBLE);
211 static GSList *__find_win(unsigned int win)
216 for (iter = g_winnode_list; iter; iter = g_slist_next(iter)) {
218 if (t && t->win == win)
225 static int __get_main_window(void)
227 struct win_node *entry = NULL;
229 if (g_winnode_list != NULL) {
230 entry = g_winnode_list->data;
231 return (unsigned int) entry->win;
237 static int __get_main_surface(void)
239 struct win_node *entry = NULL;
241 if (g_winnode_list != NULL) {
242 entry = g_winnode_list->data;
243 return (unsigned int) entry->surf;
249 static bool __add_win(unsigned int win, unsigned int surf)
254 _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
259 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
263 t = calloc(1, sizeof(struct win_node));
269 t->bfobscured = FALSE;
271 g_winnode_list = g_slist_append(g_winnode_list, t);
276 static bool __delete_win(unsigned int win)
283 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
289 g_winnode_list = g_slist_delete_link(g_winnode_list, f);
294 static bool __update_win(unsigned int win, unsigned int surf, bool bfobscured)
299 _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
305 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
309 t = (struct win_node *)f->data;
313 t->bfobscured = bfobscured;
318 static void __raise_win(void)
320 Ecore_Wl_Window *win;
323 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL))
326 win_id = __get_main_window();
328 _DBG("Raise window: %d", win_id);
329 win = ecore_wl_window_find(win_id);
330 ecore_wl_window_activate(win);
333 static void __pause_win(void)
335 Ecore_Wl_Window *win;
336 GSList *wlist = g_winnode_list;
337 struct win_node *entry = NULL;
339 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL))
342 _DBG("Pause window");
347 _DBG("Pause window: %d", entry->win);
348 win = ecore_wl_window_find(entry->win);
349 ecore_wl_window_iconified_set(win, EINA_TRUE);
355 static int __init_wl(void)
357 _DBG("initialize wayland");
358 dsp = wl_display_connect(NULL);
360 _ERR("Failed to connect wl display");
364 reg = wl_display_get_registry(dsp);
366 _ERR("Failed to get registry");
367 wl_display_disconnect(dsp);
371 wl_registry_add_listener(reg, ®_listener, NULL);
372 wl_display_roundtrip(dsp);
375 _ERR("Failed to get tizen policy interface");
376 wl_registry_destroy(reg);
377 wl_display_disconnect(dsp);
384 static void __finish_wl(void)
387 tizen_policy_destroy(tz_policy);
392 wl_registry_destroy(reg);
397 wl_display_disconnect(dsp);
402 static void __set_bg_state(void)
404 if (!tz_policy && __init_wl() < 0)
407 tizen_policy_set_background_state(tz_policy, getpid());
408 wl_display_roundtrip(dsp);
409 __context.bg_state = true;
410 _DBG("bg state: %d", __context.bg_state);
413 static void __unset_bg_state(void)
418 tizen_policy_unset_background_state(tz_policy, getpid());
419 wl_display_roundtrip(dsp);
420 __context.bg_state = false;
421 _DBG("bg state: %d", __context.bg_state);
424 static void __do_start(bundle *b)
426 const char *bg_launch;
427 const char *below_app;
429 if (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL) {
430 if (__context.below_app) {
431 free(__context.below_app);
432 __context.below_app = NULL;
435 below_app = bundle_get_val(b, AUL_SVC_K_RELOCATE_BELOW);
437 __context.below_app = strdup(below_app);
441 first_launch = FALSE;
445 if (__context.hint & APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL) {
446 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
447 if (bg_launch && strcmp(bg_launch, "enable") == 0) {
448 if (!__context.bg_state &&
449 __context.state != AS_RUNNING)
452 if (__context.bg_state)
457 if (__context.hint & APPCORE_UI_BASE_HINT_WINDOW_AUTO_CONTROL) {
458 if (!__context.bg_state)
463 static int __is_legacy_lifecycle(void)
465 static int is_legacy = -1;
466 const char *api_version;
471 api_version = getenv("TIZEN_API_VERSION");
473 if (strverscmp("2.4", api_version) > 0 &&
474 strverscmp("2.2.1", api_version) < 0)
485 EXPORT_API int appcore_ui_base_on_receive(aul_type type, bundle *b)
487 if (__context.state == AS_DYING) {
488 _ERR("Skip the event in dying state");
492 if (type == AUL_TERMINATE_BGAPP && __context.state != AS_PAUSED)
495 if (type == AUL_START)
496 __exit_from_suspend();
498 appcore_base_on_receive(type, b);
503 if (__context.hint & APPCORE_UI_BASE_HINT_LEGACY_CONTROL) {
504 if (!__context.bg_state && __is_legacy_lifecycle()) {
505 _DBG("Legacy lifecycle");
511 if (__context.bg_state)
517 case AUL_TERMINATE_BGAPP:
518 _DBG("[APP %d] is paused. TERMINATE", getpid());
519 __context.state = AS_DYING;
520 aul_status_update(STATUS_DYING);
521 if (__context.ops.base.exit)
522 __context.ops.base.exit(__context.data);
534 static void __add_ecore_events(void)
536 __context.hshow = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_SHOW,
537 __stub_show_cb, NULL);
538 if (!__context.hshow)
539 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_SHOW event");
541 __context.hhide = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_HIDE,
542 __stub_hide_cb, NULL);
543 if (!__context.hhide)
544 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_HIDE event");
546 __context.hvchange = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE,
547 __stub_visibility_cb, NULL);
548 if (!__context.hvchange)
549 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE event");
551 __context.hlower = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_LOWER,
552 __stub_lower_cb, NULL);
553 if (!__context.hlower)
554 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_LOWER event");
556 __context.hpvchange = ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_PRE_VISIBILITY_CHANGE,
557 __stub_pre_visibility_cb, NULL);
558 if (!__context.hpvchange)
559 _ERR("Failed to add ECORE_WL_EVENT_WINDOW_PRE_VISIBILITY_CHANGE event");
562 static void __del_ecore_events(void)
564 if (__context.hshow) {
565 ecore_event_handler_del(__context.hshow);
566 __context.hshow = NULL;
569 if (__context.hhide) {
570 ecore_event_handler_del(__context.hhide);
571 __context.hhide = NULL;
574 if (__context.hvchange) {
575 ecore_event_handler_del(__context.hvchange);
576 __context.hvchange = NULL;
579 if (__context.hlower) {
580 ecore_event_handler_del(__context.hlower);
581 __context.hlower = NULL;
584 if (__context.hpvchange) {
585 ecore_event_handler_del(__context.hpvchange);
586 __context.hpvchange = NULL;
590 EXPORT_API int appcore_ui_base_on_create(void)
592 __add_ecore_events();
593 appcore_base_on_create();
594 __context.state = AS_CREATED;
595 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]", __context.appid);
600 EXPORT_API int appcore_ui_base_on_terminate(void)
602 if (__context.state == AS_RUNNING) {
603 if (__context.ops.pause)
604 __context.ops.pause(__context.data);
607 __context.state = AS_DYING;
609 appcore_base_on_terminate();
614 EXPORT_API int appcore_ui_base_on_pause(void)
619 EXPORT_API int appcore_ui_base_on_resume(void)
624 EXPORT_API int appcore_ui_base_on_control(bundle *b)
626 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]", __context.appid);
627 appcore_base_on_control(b);
628 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]", __context.appid);
633 static void __group_attach()
635 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL))
638 appcore_ui_base_group_add();
641 static void __group_lower()
643 if (!(__context.hint & APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL))
645 appcore_ui_base_group_remove();
648 EXPORT_API void appcore_ui_base_group_add()
650 static bool attached = false;
652 _DBG("__group_attach");
656 int wid = __get_main_surface();
658 _ERR("window wasn't ready");
662 aul_app_group_set_window(wid);
666 EXPORT_API void appcore_ui_base_group_remove()
670 _DBG("__group_lower");
671 aul_app_group_lower(&exit);
673 _DBG("__group_lower : sub-app!");
674 if (__context.ops.base.exit)
675 __context.ops.base.exit(__context.data);
679 EXPORT_API void appcore_ui_base_window_on_show(int type, void *event)
681 Ecore_Wl_Event_Window_Show *ev;
684 if (ev->parent_win != 0) {
685 /* This is child window. Skip!!! */
689 _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x, %d\n", ev->win, ev->data[0]);
691 if (!__find_win((unsigned int)ev->win))
692 __add_win((unsigned int)ev->win, (unsigned int)ev->data[0]);
694 __update_win((unsigned int)ev->win, (unsigned int)ev->data[0], FALSE);
696 if (ev->data[0] != 0)
700 static bool __check_visible(void)
703 struct win_node *entry = NULL;
705 _DBG("[EVENT_TEST][EVENT] __check_visible\n");
707 for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
709 _DBG("win : %x obscured : %d\n", entry->win, entry->bfobscured);
710 if (entry->bfobscured == FALSE)
717 EXPORT_API void appcore_ui_base_window_on_hide(int type, void *event)
719 Ecore_Wl_Event_Window_Hide *ev;
723 _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
725 if (__find_win((unsigned int)ev->win)) {
726 __delete_win((unsigned int)ev->win);
727 bvisibility = __check_visible();
728 if (!bvisibility && b_active == TRUE) {
729 _DBG(" Go to Pasue state \n");
736 EXPORT_API void appcore_ui_base_window_on_lower(int type, void *event)
738 Ecore_Wl_Event_Window_Lower *ev;
743 _DBG("ECORE_WL_EVENT_WINDOW_LOWER window id:%u\n", ev->win);
747 EXPORT_API void appcore_ui_base_window_on_visibility(int type, void *event)
749 Ecore_Wl_Event_Window_Visibility_Change *ev;
753 __update_win((unsigned int)ev->win, 0, ev->fully_obscured);
754 bvisibility = __check_visible();
756 _DBG("bvisibility %d, b_active %d", bvisibility, b_active);
758 if (bvisibility && b_active == FALSE) {
759 _DBG(" Go to Resume state\n");
762 } else if (!bvisibility && b_active == TRUE) {
763 _DBG(" Go to Pasue state \n");
767 _DBG(" No change state \n");
772 EXPORT_API void appcore_ui_base_window_on_pre_visibility(int type, void *event)
774 Ecore_Wl_Event_Window_Pre_Visibility_Change *ev = event;
777 if (ev && ev->type == ECORE_WL_WINDOW_VISIBILITY_TYPE_PRE_UNOBSCURED) {
778 __update_win((unsigned int)ev->win, 0, false);
779 bvisibility = __check_visible();
781 _DBG("bvisibility %d, b_active %d", bvisibility, b_active);
782 if (bvisibility && b_active == FALSE) {
783 _DBG(" Go to Resume state\n");
790 EXPORT_API int appcore_ui_base_init(appcore_ui_base_ops ops, int argc, char **argv,
791 void *data, unsigned int hint)
793 const char *bg_launch;
795 char appid[PATH_MAX] = {0, };
799 appcore_ui_plugin_init(&ops, argc, argv, &hint);
800 aul_app_get_appid_bypid(getpid(), appid, sizeof(appid));
802 __context.data = data;
803 __context.argc = argc;
804 __context.argv = argv;
805 __context.hint = hint;
806 __context.state = AS_NONE;
807 __context.appid = strdup(appid);
809 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", appid);
810 if (__context.hint & APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL) {
811 b = bundle_import_from_argv(argc, argv);
813 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
814 if (bg_launch && strcmp(bg_launch, "enable") == 0)
821 return appcore_base_init(ops.base, argc, argv, data);
824 EXPORT_API void appcore_ui_base_fini(void)
826 __del_ecore_events();
829 free(__context.appid);
830 __context.appid = NULL;
832 appcore_ui_plugin_fini();
837 EXPORT_API void appcore_ui_base_pause(void)
842 EXPORT_API void appcore_ui_base_resume(void)
847 EXPORT_API bool appcore_ui_base_is_resumed(void)
849 return __context.state == AS_RUNNING;
852 EXPORT_API void appcore_ui_base_exit(void)
854 if (__context.ops.base.exit)
855 __context.ops.base.exit(__context.data);
858 EXPORT_API unsigned int appcore_ui_base_get_main_window(void)
860 return __get_main_window();
863 EXPORT_API unsigned int appcore_ui_base_get_main_surface(void)
865 return __get_main_surface();
868 EXPORT_API int appcore_ui_base_get_hint(void)
870 return __context.hint;
873 EXPORT_API bool appcore_ui_base_get_bg_state(void)
875 return __context.bg_state;
878 EXPORT_API void appcore_ui_base_set_bg_state(bool bg_state)
880 __context.bg_state = bg_state;
883 static int __on_receive(aul_type type, bundle *b, void *data)
885 return appcore_ui_base_on_receive(type, b);
888 static int __on_create(void *data)
890 return appcore_ui_base_on_create();
893 static int __on_terminate(void *data)
895 return appcore_ui_base_on_terminate();
898 static int __on_pause(void *data)
900 return appcore_ui_base_on_pause();
903 static int __on_resume(void *data)
905 return appcore_ui_base_on_resume();
908 static void __window_on_show(int type, void *event, void *data)
910 appcore_ui_base_window_on_show(type, event);
913 static void __window_on_hide(int type, void *event, void *data)
915 appcore_ui_base_window_on_hide(type, event);
918 static void __window_on_lower(int type, void *event, void *data)
920 appcore_ui_base_window_on_lower(type, event);
923 static void __window_on_visibility(int type, void *event, void *data)
925 appcore_ui_base_window_on_visibility(type, event);
928 static void __window_on_pre_visibility(int type, void *event, void *data)
930 appcore_ui_base_window_on_pre_visibility(type, event);
933 EXPORT_API appcore_ui_base_ops appcore_ui_base_get_default_ops(void)
935 appcore_ui_base_ops ops;
937 ops.base = appcore_base_get_default_ops();
939 /* override methods */
940 ops.base.create = __on_create;
941 ops.base.terminate = __on_terminate;
942 ops.base.receive = __on_receive;
943 ops.base.init = NULL;
944 ops.base.finish = NULL;
946 ops.base.exit = NULL;
948 ops.pause = __on_pause;
949 ops.resume = __on_resume;
950 ops.window.show = __window_on_show;
951 ops.window.hide = __window_on_hide;
952 ops.window.lower = __window_on_lower;
953 ops.window.visibility = __window_on_visibility;
954 ops.window.pre_visibility = __window_on_pre_visibility;