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