Release version 1.3.0
[platform/core/appfw/app-core.git] / src / appcore-efl.c
1 /*
2  * Copyright (c) 2000 - 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 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <sys/un.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <stdarg.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <stdlib.h>
26
27 #if defined(WAYLAND)
28 #include <Ecore_Wayland.h>
29 #include <wayland-client.h>
30 #include <wayland-tbm-client.h>
31 #include <tizen-extension-client-protocol.h>
32 #elif defined(X11)
33 #include <X11/Xatom.h>
34 #include <X11/Xlib.h>
35 #include <Ecore_X.h>
36 #endif
37
38 #include <Ecore.h>
39 #include <Ecore_Evas.h>
40 #include <Ecore_Input_Evas.h>
41 #include <Elementary.h>
42 #include <glib-object.h>
43 #include <malloc.h>
44 #include <glib.h>
45 #include <gio/gio.h>
46 #include <stdbool.h>
47 #include <aul.h>
48 #include <aul_svc.h>
49 #include <bundle_internal.h>
50 #include <ttrace.h>
51
52 #include "appcore-internal.h"
53 #include "appcore-efl.h"
54 #include <system_info.h>
55
56 static pid_t _pid;
57 static bool resource_reclaiming = TRUE;
58 static int tmp_val = 0;
59
60 struct ui_priv {
61         const char *name;
62         enum app_state state;
63
64         Ecore_Event_Handler *hshow;
65         Ecore_Event_Handler *hhide;
66         Ecore_Event_Handler *hvchange;
67 #if defined(WAYLAND)
68         Ecore_Event_Handler *hlower;
69 #endif
70         Ecore_Event_Handler *hcmsg; /* WM_ROTATE */
71
72         Ecore_Timer *mftimer; /* Ecore Timer for memory flushing */
73
74         struct appcore *app_core;
75         void (*prepare_to_suspend) (void *data);
76         void (*exit_from_suspend) (void *data);
77         struct appcore_ops *ops;
78         void (*mfcb) (void); /* Memory Flushing Callback */
79
80         /* WM_ROTATE */
81         int wm_rot_supported;
82         int rot_started;
83         int (*rot_cb) (void *event_info, enum appcore_rm, void *);
84         void *rot_cb_data;
85         enum appcore_rm rot_mode;
86         bundle *pending_data;
87         char *below_app;
88 };
89
90 static struct ui_priv priv;
91
92 static const char *_ae_name[AE_MAX] = {
93         [AE_UNKNOWN] = "UNKNOWN",
94         [AE_CREATE] = "CREATE",
95         [AE_TERMINATE] = "TERMINATE",
96         [AE_PAUSE] = "PAUSE",
97         [AE_RESUME] = "RESUME",
98         [AE_RESET] = "RESET",
99         [AE_LOWMEM_POST] = "LOWMEM_POST",
100         [AE_MEM_FLUSH] = "MEM_FLUSH",
101         [AE_UPDATE_REQUESTED] = "UPDATE_REQUESTED",
102 };
103
104 static const char *_as_name[] = {
105         [AS_NONE] = "NONE",
106         [AS_CREATED] = "CREATED",
107         [AS_RUNNING] = "RUNNING",
108         [AS_PAUSED] = "PAUSED",
109         [AS_DYING] = "DYING",
110 };
111
112 static bool b_active = FALSE;
113 static bool first_launch = TRUE;
114
115 struct win_node {
116         unsigned int win;
117 #if defined(WAYLAND)
118         unsigned int surf;
119 #endif
120         bool bfobscured;
121 };
122
123 #if defined(X11)
124 static struct ui_wm_rotate wm_rotate;
125 #endif
126 static Eina_Bool __visibility_cb(void *data, int type, void *event);
127 static GSList *g_winnode_list;
128
129 static struct wl_display *dsp;
130 static struct wl_registry *reg;
131 static struct tizen_policy *tz_policy;
132 static bool bg_state = false;
133
134 static void __wl_listener_cb(void *data, struct wl_registry *reg,
135                 uint32_t id, const char *interface, uint32_t ver)
136 {
137         if (interface && !strcmp(interface, "tizen_policy")) {
138                 if (!tz_policy)
139                         tz_policy = wl_registry_bind(reg, id,
140                                         &tizen_policy_interface, 1);
141         }
142 }
143
144 static void __wl_listener_remove_cb(void *data, struct wl_registry *reg,
145                 unsigned int id)
146 {
147         /* do nothing */
148 }
149
150 static const struct wl_registry_listener reg_listener = {
151         __wl_listener_cb,
152         __wl_listener_remove_cb
153 };
154
155 static int __init_wl(void)
156 {
157         _DBG("initialize wayland");
158         dsp = wl_display_connect(NULL);
159         if (dsp == NULL) {
160                 _ERR("Failed to connect wl display");
161                 return -1;
162         }
163
164         reg = wl_display_get_registry(dsp);
165         if (reg == NULL) {
166                 _ERR("Failed to get registry");
167                 wl_display_disconnect(dsp);
168                 return -1;
169         }
170
171         wl_registry_add_listener(reg, &reg_listener, NULL);
172         wl_display_roundtrip(dsp);
173
174         if (!tz_policy) {
175                 _ERR("Failed to get tizen policy interface");
176                 wl_registry_destroy(reg);
177                 wl_display_disconnect(dsp);
178                 return -1;
179         }
180
181         return 0;
182 }
183
184 static void __finish_wl(void)
185 {
186         if (tz_policy) {
187                 tizen_policy_destroy(tz_policy);
188                 tz_policy = NULL;
189         }
190
191         if (reg) {
192                 wl_registry_destroy(reg);
193                 reg = NULL;
194         }
195
196         if (dsp) {
197                 wl_display_disconnect(dsp);
198                 dsp = NULL;
199         }
200 }
201
202 static void __set_bg_state(void)
203 {
204         if (__init_wl() < 0)
205                 return;
206
207         tizen_policy_set_background_state(tz_policy, getpid());
208         wl_display_roundtrip(dsp);
209         bg_state = true;
210         _DBG("bg state: %d", bg_state);
211 }
212
213 static void __unset_bg_state(void)
214 {
215         if (!tz_policy)
216                 return;
217
218         tizen_policy_unset_background_state(tz_policy, getpid());
219         wl_display_roundtrip(dsp);
220         bg_state = false;
221         _DBG("bg state: %d", bg_state);
222         __finish_wl();
223 }
224
225 static void __appcore_efl_prepare_to_suspend(void *data)
226 {
227         struct ui_priv *ui = (struct ui_priv *)data;
228         struct sys_op *op = NULL;
229         int suspend = APPCORE_SUSPENDED_STATE_WILL_ENTER_SUSPEND;
230
231         if (ui->app_core && !ui->app_core->allowed_bg && !ui->app_core->suspended_state) {
232                 op = &ui->app_core->sops[SE_SUSPENDED_STATE];
233                 if (op && op->func)
234                         op->func((void *)&suspend, op->data); /* calls c-api handler */
235
236                 ui->app_core->suspended_state = true;
237         }
238         _DBG("[__SUSPEND__]");
239 }
240
241 static void __appcore_efl_exit_from_suspend(void *data)
242 {
243         struct ui_priv *ui = (struct ui_priv *)data;
244         struct sys_op *op = NULL;
245         int suspend = APPCORE_SUSPENDED_STATE_DID_EXIT_FROM_SUSPEND;
246
247         if (ui->app_core && !ui->app_core->allowed_bg && ui->app_core->suspended_state) {
248                 op = &ui->app_core->sops[SE_SUSPENDED_STATE];
249                 if (op && op->func)
250                         op->func((void *)&suspend, op->data); /* calls c-api handler */
251
252                 ui->app_core->suspended_state = false;
253         }
254         _DBG("[__SUSPEND__]");
255 }
256
257 static void __appcore_efl_update_requested(void *data)
258 {
259         struct ui_priv *ui = (struct ui_priv *)data;
260         struct sys_op *op;
261         int dummy = 0;
262
263         if (ui->app_core) {
264                 op = &ui->app_core->sops[SE_UPDATE_REQUESTED];
265                 if (op && op->func)
266                         op->func((void *)&dummy, op->data);
267         }
268         _DBG("[__UPDATE_REQUESTED__]");
269 }
270
271 #if defined(MEMORY_FLUSH_ACTIVATE)
272 static Eina_Bool __appcore_memory_flush_cb(void *data)
273 {
274         struct ui_priv *ui = (struct ui_priv *)data;
275
276         appcore_flush_memory();
277         if (ui)
278                 ui->mftimer = NULL;
279
280         if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT && ui && ui->prepare_to_suspend) {
281                 _DBG("[__SUSPEND__] flush case");
282                 ui->prepare_to_suspend(ui);
283         }
284
285         return ECORE_CALLBACK_CANCEL;
286 }
287
288 static int __appcore_low_memory_post_cb(struct ui_priv *ui)
289 {
290         if (ui->state == AS_PAUSED)
291                 appcore_flush_memory();
292         else
293                 malloc_trim(0);
294
295         return 0;
296 }
297
298 static void __appcore_timer_add(struct ui_priv *ui)
299 {
300         ui->mftimer = ecore_timer_add(5, __appcore_memory_flush_cb, ui);
301 }
302
303 static void __appcore_timer_del(struct ui_priv *ui)
304 {
305         if (ui->mftimer) {
306                 ecore_timer_del(ui->mftimer);
307                 ui->mftimer = NULL;
308         }
309 }
310
311 #else
312
313 static int __appcore_low_memory_post_cb(ui_priv *ui)
314 {
315         return -1;
316 }
317
318 #define __appcore_timer_add(ui) 0
319 #define __appcore_timer_del(ui) 0
320
321 #endif
322
323 static void __appcore_efl_memory_flush_cb(void)
324 {
325         _DBG("[APP %d]   __appcore_efl_memory_flush_cb()", _pid);
326         elm_cache_all_flush();
327 }
328 #if defined(WAYLAND)
329 static void wl_raise_win(void)
330 {
331         Ecore_Wl_Window *win;
332         unsigned int win_id = appcore_get_main_window();
333
334         _DBG("Raise window: %d", win_id);
335         win = ecore_wl_window_find(win_id);
336         ecore_wl_window_activate(win);
337 }
338
339 static void wl_pause_win(void)
340 {
341         Ecore_Wl_Window *win;
342         GSList *wlist = g_winnode_list;
343         struct win_node *entry = NULL;
344
345         _DBG("Pause window");
346
347         while (wlist) {
348                 entry = wlist->data;
349
350                 _DBG("Pause window: %d", entry->win);
351                 win = ecore_wl_window_find(entry->win);
352                 ecore_wl_window_iconified_set(win, EINA_TRUE);
353
354                 wlist = wlist->next;
355         }
356 }
357
358 #endif
359
360 static void __do_app(enum app_event event, void *data, bundle * b)
361 {
362         int r = -1;
363         struct ui_priv *ui = data;
364         const char *below_app;
365         const char *bg_launch;
366
367         _DBG("[APP %d] Event: %d", _pid, event);
368         _ret_if(ui == NULL || event >= AE_MAX);
369         _DBG("[APP %d] Event: %s State: %s", _pid, _ae_name[event],
370              _as_name[ui->state]);
371
372         if (event == AE_MEM_FLUSH) {
373                 ui->mfcb();
374                 return;
375         }
376
377         if (event == AE_LOWMEM_POST) {
378                 if (__appcore_low_memory_post_cb(ui) == 0)
379                         return;
380         }
381
382         if (!(ui->state == AS_PAUSED && event == AE_PAUSE))
383                 __appcore_timer_del(ui);
384
385         if (ui->state == AS_DYING) {
386                 _ERR("Skip the event in dying state");
387                 return;
388         }
389
390         if (event == AE_TERMINATE) {
391                 _DBG("[APP %d] TERMINATE", _pid);
392                 elm_exit();
393                 aul_status_update(STATUS_DYING);
394                 return;
395         }
396
397         if (event == AE_RAISE) {
398 #if defined(X11)
399                 x_raise_win(getpid());
400 #elif defined(WAYLAND)
401                 wl_raise_win();
402 #endif
403                 return;
404         }
405
406         if (event == AE_LOWER) {
407 #if defined(X11)
408                 x_pause_win(getpid());
409 #elif defined(WAYLAND)
410                 wl_pause_win();
411 #endif
412                 return;
413         }
414
415         _ret_if(ui->ops == NULL);
416
417         switch (event) {
418         case AE_RESET:
419                 _DBG("[APP %d] RESET", _pid);
420                 if (ui->pending_data)
421                         bundle_free(ui->pending_data);
422                 ui->pending_data = bundle_dup(b);
423                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]", ui->name);
424
425                 if (ui->below_app) {
426                         free(ui->below_app);
427                         ui->below_app = NULL;
428                 }
429
430                 below_app = bundle_get_val(b, AUL_SVC_K_RELOCATE_BELOW);
431                 if (below_app)
432                         ui->below_app = strdup(below_app);
433                 if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT && ui->exit_from_suspend) {
434                         _DBG("[__SUSPEND__] reset case");
435                         ui->exit_from_suspend(ui);
436                 }
437
438                 if (ui->ops->reset) {
439                         traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
440                                         "APPCORE:RESET");
441                         r = ui->ops->reset(b, ui->ops->data);
442                         traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
443                 }
444                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]", ui->name);
445
446                 if (first_launch) {
447                         if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT && ui->app_core->allowed_bg)
448                                 __appcore_timer_add(ui);
449                         first_launch = FALSE;
450                 } else {
451                         _INFO("[APP %d] App already running, raise the window", _pid);
452                         if (bg_state) {
453                                 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
454                                 if (!bg_launch || strcmp(bg_launch, "enable"))
455                                         __unset_bg_state();
456                         }
457 #ifdef X11
458                         x_raise_win(getpid());
459 #else
460                         wl_raise_win();
461 #endif
462                 }
463                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]",
464                     ui->name);
465                 break;
466         case AE_PAUSE:
467                 if (ui->state == AS_RUNNING) {
468                         _DBG("[APP %d] PAUSE", _pid);
469                         if (ui->ops->pause) {
470                                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
471                                                 "APPCORE:PAUSE");
472                                 r = ui->ops->pause(ui->ops->data);
473                                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
474                         }
475                         ui->state = AS_PAUSED;
476                         if (r >= 0 && resource_reclaiming == TRUE)
477                                 __appcore_timer_add(ui);
478                         else if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT && r >= 0 && resource_reclaiming == FALSE
479                                         && ui->prepare_to_suspend) {
480                                 _DBG("[__SUSPEND__] pause case");
481                                 ui->prepare_to_suspend(ui);
482                         }
483                 }
484                 /* TODO : rotation stop */
485                 /* r = appcore_pause_rotation_cb(); */
486                 aul_status_update(STATUS_BG);
487                 break;
488         case AE_RESUME:
489                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:start]",
490                                 ui->name);
491                 if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT) {
492                         if (ui->exit_from_suspend) {
493                                 _DBG("[__SUSPEND__] resume case");
494                                 ui->exit_from_suspend(ui);
495                         }
496                         if (ui->app_core->allowed_bg)
497                                 __appcore_timer_del(ui);
498                 }
499
500                 if (ui->state == AS_PAUSED || ui->state == AS_CREATED) {
501                         _DBG("[APP %d] RESUME", _pid);
502
503                         if (ui->state == AS_CREATED) {
504                                 bundle_free(ui->pending_data);
505                                 ui->pending_data = NULL;
506                         }
507
508                         if (ui->ops->resume) {
509                                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
510                                         "APPCORE:RESUME");
511                                 ui->ops->resume(ui->ops->data);
512                                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
513                         }
514                         ui->state = AS_RUNNING;
515
516                         if (ui->below_app) {
517                                 aul_app_group_activate_below(ui->below_app);
518                                 free(ui->below_app);
519                                 ui->below_app = NULL;
520                         }
521                 }
522                 /*TODO : rotation start*/
523                 /* r = appcore_resume_rotation_cb(); */
524                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:done]",
525                     ui->name);
526                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:Launching:done]",
527                     ui->name);
528                 aul_status_update(STATUS_VISIBLE);
529                 break;
530         case AE_TERMINATE_BGAPP:
531                 if (ui->state == AS_PAUSED) {
532                         _DBG("[APP %d] is paused. TERMINATE", _pid);
533                         ui->state = AS_DYING;
534                         aul_status_update(STATUS_DYING);
535                         elm_exit();
536                 } else if (ui->state == AS_RUNNING) {
537                         _DBG("[APP %d] is running.", _pid);
538                 } else {
539                         _DBG("[APP %d] is another state", _pid);
540                 }
541                 break;
542         case AE_UPDATE_REQUESTED:
543                 __appcore_efl_update_requested(ui);
544                 break;
545         default:
546                 /* do nothing */
547                 break;
548         }
549 }
550
551 static struct ui_ops efl_ops = {
552         .data = &priv,
553         .cb_app = __do_app,
554 };
555
556 static bool __check_visible(void)
557 {
558         GSList *iter = NULL;
559         struct win_node *entry = NULL;
560
561         _DBG("[EVENT_TEST][EVENT] __check_visible\n");
562
563         for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
564                 entry = iter->data;
565                 _DBG("win : %x obscured : %d\n", entry->win, entry->bfobscured);
566                 if (entry->bfobscured == FALSE)
567                         return TRUE;
568         }
569
570         return FALSE;
571 }
572
573 static GSList *__find_win(unsigned int win)
574 {
575         GSList *iter;
576         struct win_node *t;
577
578         for (iter = g_winnode_list; iter; iter = g_slist_next(iter)) {
579                 t = iter->data;
580                 if (t && t->win == win)
581                         return iter;
582         }
583
584         return NULL;
585 }
586
587 #if defined(X11)
588 static bool __add_win(unsigned int win)
589 {
590         struct win_node *t;
591         GSList *f;
592
593         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
594
595         f = __find_win(win);
596         if (f) {
597                 errno = ENOENT;
598                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
599                 return FALSE;
600         }
601
602         t = calloc(1, sizeof(struct win_node));
603         if (t == NULL)
604                 return FALSE;
605
606         t->win = win;
607         t->bfobscured = FALSE;
608
609         g_winnode_list = g_slist_append(g_winnode_list, t);
610
611         return TRUE;
612 }
613 #elif defined(WAYLAND)
614 static bool __add_win(unsigned int win, unsigned int surf)
615 {
616         struct win_node *t;
617         GSList *f;
618
619         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
620
621         f = __find_win(win);
622         if (f) {
623                 errno = ENOENT;
624                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
625                 return FALSE;
626         }
627
628         t = calloc(1, sizeof(struct win_node));
629         if (t == NULL)
630                 return FALSE;
631
632         t->win = win;
633         t->surf = surf;
634         t->bfobscured = FALSE;
635
636         g_winnode_list = g_slist_append(g_winnode_list, t);
637
638         return TRUE;
639 }
640 #endif
641
642 static bool __delete_win(unsigned int win)
643 {
644         GSList *f;
645
646         f = __find_win(win);
647         if (!f) {
648                 errno = ENOENT;
649                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
650                                 win);
651                 return FALSE;
652         }
653
654         free(f->data);
655         g_winnode_list = g_slist_delete_link(g_winnode_list, f);
656
657         return TRUE;
658 }
659
660 #if defined(X11)
661 static bool __update_win(unsigned int win, bool bfobscured)
662 {
663         GSList *f;
664         struct win_node *t;
665
666         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
667              bfobscured);
668
669         f = __find_win(win);
670         if (!f) {
671                 errno = ENOENT;
672                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
673                 return FALSE;
674         }
675
676         t = (struct win_node *)f->data;
677         t->win = win;
678         t->bfobscured = bfobscured;
679
680         return TRUE;
681 }
682 #elif defined(WAYLAND)
683 static bool __update_win(unsigned int win, unsigned int surf, bool bfobscured)
684 {
685         GSList *f;
686         struct win_node *t;
687
688         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
689              bfobscured);
690
691         f = __find_win(win);
692         if (!f) {
693                 errno = ENOENT;
694                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
695                 return FALSE;
696         }
697
698         t = (struct win_node *)f->data;
699         t->win = win;
700         if (surf != 0)
701                 t->surf = surf;
702         t->bfobscured = bfobscured;
703
704         return TRUE;
705 }
706 #endif
707
708 /* WM_ROTATE */
709 #ifdef X11
710 static Ecore_X_Atom _WM_WINDOW_ROTATION_SUPPORTED = 0;
711 static Ecore_X_Atom _WM_WINDOW_ROTATION_CHANGE_REQUEST = 0;
712
713 static int __check_wm_rotation_support(void)
714 {
715         _DBG("Disable window manager rotation");
716         return -1;
717
718         Ecore_X_Window root, win, win2;
719         int ret;
720
721         if (!_WM_WINDOW_ROTATION_SUPPORTED) {
722                 _WM_WINDOW_ROTATION_SUPPORTED =
723                                         ecore_x_atom_get("_E_WINDOW_ROTATION_SUPPORTED");
724         }
725
726         if (!_WM_WINDOW_ROTATION_CHANGE_REQUEST) {
727                 _WM_WINDOW_ROTATION_CHANGE_REQUEST =
728                                         ecore_x_atom_get("_E_WINDOW_ROTATION_CHANGE_REQUEST");
729         }
730
731         root = ecore_x_window_root_first_get();
732         ret = ecore_x_window_prop_xid_get(root,
733                         _WM_WINDOW_ROTATION_SUPPORTED,
734                         ECORE_X_ATOM_WINDOW,
735                         &win, 1);
736         if ((ret == 1) && (win)) {
737                 ret = ecore_x_window_prop_xid_get(win,
738                                 _WM_WINDOW_ROTATION_SUPPORTED,
739                                 ECORE_X_ATOM_WINDOW,
740                                 &win2, 1);
741                 if ((ret == 1) && (win2 == win))
742                         return 0;
743         }
744
745         return -1;
746 }
747
748 static void __set_wm_rotation_support(unsigned int win, unsigned int set)
749 {
750         GSList *iter = NULL;
751         struct win_node *entry = NULL;
752
753         if (win == 0) {
754                 for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
755                         entry = iter->data;
756                         if (entry->win) {
757                                 ecore_x_window_prop_card32_set(entry->win,
758                                                 _WM_WINDOW_ROTATION_SUPPORTED,
759                                                 &set, 1);
760                         }
761                 }
762         } else {
763                 ecore_x_window_prop_card32_set(win,
764                                 _WM_WINDOW_ROTATION_SUPPORTED,
765                                 &set, 1);
766         }
767 }
768 #endif
769
770 static Eina_Bool __show_cb(void *data, int type, void *event)
771 {
772 #if defined(WAYLAND)
773         Ecore_Wl_Event_Window_Show *ev;
774
775         ev = event;
776         if (ev->parent_win != 0) {
777                 /* This is child window. Skip!!! */
778                 return ECORE_CALLBACK_PASS_ON;
779         }
780
781         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x, %d\n", ev->win, ev->data[0]);
782
783         if (!__find_win((unsigned int)ev->win))
784                 __add_win((unsigned int)ev->win, (unsigned int)ev->data[0]);
785         else
786                 __update_win((unsigned int)ev->win, (unsigned int)ev->data[0], FALSE);
787
788 #elif defined(X11)
789         Ecore_X_Event_Window_Show *ev;
790
791         ev = event;
792
793         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x\n", ev->win);
794
795         if (!__find_win((unsigned int)ev->win)) {
796                 /* WM_ROTATE */
797                 if ((priv.wm_rot_supported) && (1 == priv.rot_started))
798                         __set_wm_rotation_support(ev->win, 1);
799                 __add_win((unsigned int)ev->win);
800         } else {
801                 __update_win((unsigned int)ev->win, FALSE);
802         }
803 #endif
804
805         appcore_group_attach();
806         return ECORE_CALLBACK_RENEW;
807 }
808
809 static Eina_Bool __hide_cb(void *data, int type, void *event)
810 {
811 #if defined(WAYLAND)
812         Ecore_Wl_Event_Window_Hide *ev;
813 #elif defined(X11)
814         Ecore_X_Event_Window_Hide *ev;
815 #endif
816         int bvisibility = 0;
817
818         ev = event;
819
820         _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
821
822         if (__find_win((unsigned int)ev->win)) {
823                 __delete_win((unsigned int)ev->win);
824                 bvisibility = __check_visible();
825                 if (!bvisibility && b_active == TRUE) {
826                         _DBG(" Go to Pasue state \n");
827                         b_active = FALSE;
828                         __do_app(AE_PAUSE, data, NULL);
829                 }
830         }
831
832         return ECORE_CALLBACK_RENEW;
833 }
834
835 #if defined(WAYLAND)
836 static Eina_Bool __lower_cb(void *data, int type, void *event)
837 {
838         Ecore_Wl_Event_Window_Lower *ev;
839         ev = event;
840         if (!ev) return ECORE_CALLBACK_RENEW;
841         _DBG("ECORE_WL_EVENT_WINDOW_LOWER window id:%u\n", ev->win);
842         appcore_group_lower();
843         return ECORE_CALLBACK_RENEW;
844 }
845 #endif
846
847 static Eina_Bool __visibility_cb(void *data, int type, void *event)
848 {
849 #if defined(WAYLAND)
850         Ecore_Wl_Event_Window_Visibility_Change *ev;
851         int bvisibility = 0;
852         ev = event;
853         __update_win((unsigned int)ev->win, 0, ev->fully_obscured);
854 #elif defined(X11)
855         Ecore_X_Event_Window_Visibility_Change *ev;
856         int bvisibility = 0;
857
858         ev = event;
859
860         __update_win((unsigned int)ev->win, ev->fully_obscured);
861 #endif
862         bvisibility = __check_visible();
863
864         _DBG("bvisibility %d, b_active %d", bvisibility, b_active);
865
866         if (bvisibility && b_active == FALSE) {
867                 _DBG(" Go to Resume state\n");
868                 b_active = TRUE;
869                 __do_app(AE_RESUME, data, NULL);
870
871         } else if (!bvisibility && b_active == TRUE) {
872                 _DBG(" Go to Pasue state \n");
873                 b_active = FALSE;
874                 __do_app(AE_PAUSE, data, NULL);
875         } else
876                 _DBG(" No change state \n");
877
878         return ECORE_CALLBACK_RENEW;
879
880 }
881
882 #if defined(X11)
883 /* WM_ROTATE */
884 static Eina_Bool __cmsg_cb(void *data, int type, void *event)
885 {
886         struct ui_priv *ui = (struct ui_priv *)data;
887         Ecore_X_Event_Client_Message *e = event;
888
889         if (!ui)
890                 return ECORE_CALLBACK_PASS_ON;
891
892         if (e->format != 32)
893                 return ECORE_CALLBACK_PASS_ON;
894
895         if (e->message_type == _WM_WINDOW_ROTATION_CHANGE_REQUEST) {
896                 if ((ui->wm_rot_supported == 0)
897                         || (ui->rot_started == 0)
898                         || (ui->rot_cb == NULL)) {
899                         return ECORE_CALLBACK_PASS_ON;
900                 }
901
902                 enum appcore_rm rm;
903                 switch (e->data.l[1]) {
904                 case 0:
905                         rm = APPCORE_RM_PORTRAIT_NORMAL;
906                         break;
907                 case 90:
908                         rm = APPCORE_RM_LANDSCAPE_REVERSE;
909                         break;
910                 case 180:
911                         rm = APPCORE_RM_PORTRAIT_REVERSE;
912                         break;
913                 case 270:
914                         rm = APPCORE_RM_LANDSCAPE_NORMAL;
915                         break;
916                 default:
917                         rm = APPCORE_RM_UNKNOWN;
918                         break;
919                 }
920
921                 ui->rot_mode = rm;
922
923                 if (APPCORE_RM_UNKNOWN != rm)
924                         ui->rot_cb((void *)&rm, rm, ui->rot_cb_data);
925         }
926
927         return ECORE_CALLBACK_PASS_ON;
928 }
929 #endif
930
931 static void __add_climsg_cb(struct ui_priv *ui)
932 {
933         _ret_if(ui == NULL);
934 #if defined(WAYLAND)
935         ui->hshow =
936                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_SHOW, __show_cb, ui);
937         ui->hhide =
938                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_HIDE, __hide_cb, ui);
939         ui->hvchange =
940                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE,
941                                 __visibility_cb, ui);
942         ui->hlower =
943                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_LOWER,
944                                 __lower_cb, ui);
945 #elif defined(X11)
946         ui->hshow =
947                 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHOW, __show_cb, ui);
948         ui->hhide =
949                 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_HIDE, __hide_cb, ui);
950         ui->hvchange =
951                 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE,
952                                 __visibility_cb, ui);
953
954         /* Add client message callback for WM_ROTATE */
955         if (!__check_wm_rotation_support()) {
956                 ui->hcmsg = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,
957                                 __cmsg_cb, ui);
958                 ui->wm_rot_supported = 1;
959                 appcore_set_wm_rotation(&wm_rotate);
960         }
961 #endif
962 }
963
964 static int __before_loop(struct ui_priv *ui, int *argc, char ***argv)
965 {
966         int r;
967         char *hwacc = NULL;
968         struct appcore *ac = NULL;
969         bundle *b;
970         const char *bg_launch;
971
972         if (argc == NULL || argv == NULL) {
973                 _ERR("argc/argv is NULL");
974                 errno = EINVAL;
975                 return -1;
976         }
977
978 #if !(GLIB_CHECK_VERSION(2, 36, 0))
979         g_type_init();
980 #endif
981         elm_init(*argc, *argv);
982
983         hwacc = getenv("HWACC");
984         if (hwacc == NULL) {
985                 _DBG("elm_config_accel_preference_set is not called");
986         } else if (strcmp(hwacc, "USE") == 0) {
987                 elm_config_accel_preference_set("hw");
988                 _DBG("elm_config_accel_preference_set : hw");
989         } else if (strcmp(hwacc, "NOT_USE") == 0) {
990                 elm_config_accel_preference_set("none");
991                 _DBG("elm_config_accel_preference_set : none");
992         } else {
993                 _DBG("elm_config_accel_preference_set is not called");
994         }
995
996         r = appcore_init(ui->name, &efl_ops, *argc, *argv);
997         _retv_if(r == -1, -1);
998
999         if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT) {
1000                 appcore_get_app_core(&ac);
1001                 ui->app_core = ac;
1002                 SECURE_LOGD("[__SUSPEND__] appcore initialized, appcore addr: #%x", ac);
1003         }
1004
1005         b = bundle_import_from_argv(*argc, *argv);
1006         if (b) {
1007                 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
1008                 if (bg_launch && strcmp(bg_launch, "enable") == 0)
1009                         __set_bg_state();
1010
1011                 bundle_free(b);
1012         }
1013
1014         LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:appcore_init:done]", ui->name);
1015         if (ui->ops && ui->ops->create) {
1016                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1017                 r = ui->ops->create(ui->ops->data);
1018                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1019                 if (r < 0) {
1020                         _ERR("create() return error");
1021                         appcore_exit();
1022                         if (ui->ops && ui->ops->terminate) {
1023                                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
1024                                         "APPCORE:TERMINATE");
1025                                 ui->ops->terminate(ui->ops->data);
1026                                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1027                         }
1028                         errno = ECANCELED;
1029                         return -1;
1030                 }
1031                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]",
1032                     ui->name);
1033         }
1034         ui->state = AS_CREATED;
1035
1036         __add_climsg_cb(ui);
1037
1038         return 0;
1039 }
1040
1041 static void __after_loop(struct ui_priv *ui)
1042 {
1043         appcore_unset_rotation_cb();
1044         appcore_exit();
1045
1046         if (ui->state == AS_RUNNING) {
1047                 _DBG("[APP %d] PAUSE before termination", _pid);
1048                 if (ui->ops && ui->ops->pause) {
1049                         traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
1050                                         "APPCORE:PAUSE");
1051                         ui->ops->pause(ui->ops->data);
1052                         traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1053                 }
1054         }
1055
1056         if (ui->ops && ui->ops->terminate) {
1057                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1058                 ui->ops->terminate(ui->ops->data);
1059                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1060         }
1061
1062         ui->state = AS_DYING;
1063
1064         if (ui->hshow)
1065                 ecore_event_handler_del(ui->hshow);
1066         if (ui->hhide)
1067                 ecore_event_handler_del(ui->hhide);
1068         if (ui->hvchange)
1069                 ecore_event_handler_del(ui->hvchange);
1070 #if defined(WAYLAND)
1071         if (ui->hlower)
1072                 ecore_event_handler_del(ui->hlower);
1073 #endif
1074
1075         __appcore_timer_del(ui);
1076
1077         elm_shutdown();
1078
1079         /* Check loader case */
1080         if (getenv("AUL_LOADER_INIT")) {
1081                 unsetenv("AUL_LOADER_INIT");
1082                 elm_shutdown();
1083         }
1084 }
1085
1086 static int __set_data(struct ui_priv *ui, const char *name,
1087                     struct appcore_ops *ops)
1088 {
1089         if (ui->name) {
1090                 _ERR("Mainloop already started");
1091                 errno = EINPROGRESS;
1092                 return -1;
1093         }
1094
1095         if (name == NULL || name[0] == '\0') {
1096                 _ERR("Invalid name");
1097                 errno = EINVAL;
1098                 return -1;
1099         }
1100
1101         if (ops == NULL) {
1102                 _ERR("ops is NULL");
1103                 errno = EINVAL;
1104                 return -1;
1105         }
1106
1107         ui->name = strdup(name);
1108         _retv_if(ui->name == NULL, -1);
1109
1110         ui->ops = ops;
1111         ui->mfcb = __appcore_efl_memory_flush_cb;
1112         _pid = getpid();
1113
1114         /* WM_ROTATE */
1115         ui->wm_rot_supported = 0;
1116         ui->rot_started = 0;
1117         ui->rot_cb = NULL;
1118         ui->rot_cb_data = NULL;
1119         ui->rot_mode = APPCORE_RM_UNKNOWN;
1120
1121         if (_APPFW_FEATURE_BACKGROUND_MANAGEMENT) {
1122                 ui->app_core = NULL;
1123                 ui->prepare_to_suspend = __appcore_efl_prepare_to_suspend;
1124                 ui->exit_from_suspend = __appcore_efl_exit_from_suspend;
1125         }
1126
1127         return 0;
1128 }
1129
1130 static void __unset_data(struct ui_priv *ui)
1131 {
1132         if (ui->name)
1133                 free((void *)ui->name);
1134
1135         memset(ui, 0, sizeof(struct ui_priv));
1136 }
1137
1138 #if defined(X11)
1139 /* WM_ROTATE */
1140 static int __wm_set_rotation_cb(int (*cb) (void *event_info, enum appcore_rm, void *), void *data)
1141 {
1142         if (cb == NULL) {
1143                 errno = EINVAL;
1144                 return -1;
1145         }
1146
1147         if ((priv.wm_rot_supported) && (0 == priv.rot_started))
1148                 __set_wm_rotation_support(0, 1);
1149
1150         priv.rot_cb = cb;
1151         priv.rot_cb_data = data;
1152         priv.rot_started = 1;
1153
1154         return 0;
1155 }
1156
1157 static int __wm_unset_rotation_cb(void)
1158 {
1159         if ((priv.wm_rot_supported) && (1 == priv.rot_started))
1160                 __set_wm_rotation_support(0, 0);
1161
1162         priv.rot_cb = NULL;
1163         priv.rot_cb_data = NULL;
1164         priv.rot_started = 0;
1165
1166         return 0;
1167 }
1168
1169 static int __wm_get_rotation_state(enum appcore_rm *curr)
1170 {
1171         if (curr == NULL) {
1172                 errno = EINVAL;
1173                 return -1;
1174         }
1175
1176         *curr = priv.rot_mode;
1177
1178         return 0;
1179 }
1180
1181 static int __wm_pause_rotation_cb(void)
1182 {
1183         if ((priv.rot_started == 1) && (priv.wm_rot_supported))
1184                 __set_wm_rotation_support(0, 0);
1185
1186         priv.rot_started = 0;
1187
1188         return 0;
1189 }
1190
1191 static int __wm_resume_rotation_cb(void)
1192 {
1193         if ((priv.rot_started == 0) && (priv.wm_rot_supported))
1194                 __set_wm_rotation_support(0, 1);
1195
1196         priv.rot_started = 1;
1197
1198         return 0;
1199 }
1200
1201 static struct ui_wm_rotate wm_rotate = {
1202         __wm_set_rotation_cb,
1203         __wm_unset_rotation_cb,
1204         __wm_get_rotation_state,
1205         __wm_pause_rotation_cb,
1206         __wm_resume_rotation_cb
1207 };
1208 #endif
1209
1210 EXPORT_API int appcore_efl_init(const char *name, int *argc, char ***argv,
1211                      struct appcore_ops *ops)
1212 {
1213         int r;
1214
1215         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", name);
1216
1217         r = __set_data(&priv, name, ops);
1218         _retv_if(r == -1, -1);
1219
1220         r = __before_loop(&priv, argc, argv);
1221         if (r == -1) {
1222                 aul_status_update(STATUS_DYING);
1223                 __unset_data(&priv);
1224                 return -1;
1225         }
1226
1227         return 0;
1228 }
1229
1230 EXPORT_API void appcore_efl_fini(void)
1231 {
1232         aul_status_update(STATUS_DYING);
1233
1234         __after_loop(&priv);
1235
1236         __unset_data(&priv);
1237 }
1238
1239 EXPORT_API int appcore_efl_main(const char *name, int *argc, char ***argv,
1240                                 struct appcore_ops *ops)
1241 {
1242         int r;
1243
1244         r = appcore_efl_init(name, argc, argv, ops);
1245         _retv_if(r == -1, -1);
1246
1247         elm_run();
1248
1249         appcore_efl_fini();
1250
1251         return 0;
1252 }
1253
1254 EXPORT_API int appcore_set_system_resource_reclaiming(bool enable)
1255 {
1256         resource_reclaiming = enable;
1257
1258         return 0;
1259 }
1260
1261 EXPORT_API int appcore_set_app_state(int state)
1262 {
1263         priv.state = state;
1264
1265         tmp_val = 1;
1266
1267         return 0;
1268 }
1269
1270 EXPORT_API int appcore_set_preinit_window_name(const char *win_name)
1271 {
1272         int ret = -1;
1273         void *preinit_window = NULL;
1274         const Evas *e = NULL;
1275
1276         if (!win_name) {
1277                 _ERR("invalid parameter");
1278                 return ret;
1279         }
1280
1281         preinit_window = elm_win_precreated_object_get();
1282         if (!preinit_window) {
1283                 _ERR("Failed to get preinit window");
1284                 return ret;
1285         }
1286
1287         e = evas_object_evas_get((const Evas_Object *)preinit_window);
1288         if (e) {
1289                 Ecore_Evas *ee = ecore_evas_ecore_evas_get(e);
1290                 if (ee) {
1291                         ecore_evas_name_class_set(ee, win_name, win_name);
1292                         ret = 0;
1293                 }
1294         }
1295
1296         return ret;
1297 }
1298
1299 EXPORT_API unsigned int appcore_get_main_window(void)
1300 {
1301         struct win_node *entry = NULL;
1302
1303         if (g_winnode_list != NULL) {
1304                 entry = g_winnode_list->data;
1305                 return (unsigned int) entry->win;
1306         }
1307
1308         return 0;
1309 }
1310
1311 #if defined(WAYLAND)
1312 EXPORT_API unsigned int appcore_get_main_surface(void)
1313 {
1314         struct win_node *entry = NULL;
1315
1316         if (g_winnode_list != NULL) {
1317                 entry = g_winnode_list->data;
1318                 return (unsigned int) entry->surf;
1319         }
1320
1321         return 0;
1322 }
1323 #endif
1324
1325 tizen_profile_t _get_tizen_profile()
1326 {
1327         static tizen_profile_t profile = TIZEN_PROFILE_UNKNOWN;
1328         if (__builtin_expect(profile != TIZEN_PROFILE_UNKNOWN, 1))
1329                 return profile;
1330
1331         char *profileName;
1332         system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
1333         switch (*profileName) {
1334         case 'm':
1335         case 'M':
1336                 profile = TIZEN_PROFILE_MOBILE;
1337                 break;
1338         case 'w':
1339         case 'W':
1340                 profile = TIZEN_PROFILE_WEARABLE;
1341                 break;
1342         case 't':
1343         case 'T':
1344                 profile = TIZEN_PROFILE_TV;
1345                 break;
1346         case 'i':
1347         case 'I':
1348                 profile = TIZEN_PROFILE_IVI;
1349                 break;
1350         default: // common or unTIZEN_nown ==> ALL ARE COMMON.
1351                 profile = TIZEN_PROFILE_COMMON;
1352         }
1353         free(profileName);
1354
1355         return profile;
1356 }