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