Add appcore event
[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                 ui->pending_data = bundle_dup(b);
426                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]", ui->name);
427
428                 if (ui->below_app) {
429                         free(ui->below_app);
430                         ui->below_app = NULL;
431                 }
432
433                 below_app = bundle_get_val(b, AUL_SVC_K_RELOCATE_BELOW);
434                 if (below_app)
435                         ui->below_app = strdup(below_app);
436 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
437                 if (ui->exit_from_suspend) {
438                         _DBG("[__SUSPEND__] reset case");
439                         ui->exit_from_suspend(ui);
440                 }
441 #endif
442
443                 if (ui->ops->reset) {
444                         traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
445                                         "APPCORE:RESET");
446                         r = ui->ops->reset(b, ui->ops->data);
447                         traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
448                 }
449                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]", ui->name);
450
451                 if (first_launch) {
452 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
453                         if (ui->app_core->allowed_bg)
454                                 __appcore_timer_add(ui);
455 #endif
456                         first_launch = FALSE;
457                 } else {
458                         _INFO("[APP %d] App already running, raise the window", _pid);
459                         if (bg_state) {
460                                 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
461                                 if (!bg_launch || strcmp(bg_launch, "enable"))
462                                         __unset_bg_state();
463                         }
464 #ifdef X11
465                         x_raise_win(getpid());
466 #else
467                         wl_raise_win();
468 #endif
469                 }
470                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]",
471                     ui->name);
472                 break;
473         case AE_PAUSE:
474                 if (ui->state == AS_RUNNING) {
475                         _DBG("[APP %d] PAUSE", _pid);
476                         if (ui->ops->pause) {
477                                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
478                                                 "APPCORE:PAUSE");
479                                 r = ui->ops->pause(ui->ops->data);
480                                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
481                         }
482                         ui->state = AS_PAUSED;
483                         if (r >= 0 && resource_reclaiming == TRUE)
484                                 __appcore_timer_add(ui);
485 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
486                         else if (r >= 0 && resource_reclaiming == FALSE
487                                         && ui->prepare_to_suspend) {
488                                 _DBG("[__SUSPEND__] pause case");
489                                 ui->prepare_to_suspend(ui);
490                         }
491 #endif
492                 }
493                 /* TODO : rotation stop */
494                 /* r = appcore_pause_rotation_cb(); */
495                 aul_status_update(STATUS_BG);
496                 break;
497         case AE_RESUME:
498                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:start]",
499                                 ui->name);
500 #ifdef _APPFW_FEATURE_BACKGROUND_MANAGEMENT
501                 if (ui->exit_from_suspend) {
502                         _DBG("[__SUSPEND__] resume case");
503                         ui->exit_from_suspend(ui);
504                 }
505                 if (ui->app_core->allowed_bg)
506                         __appcore_timer_del(ui);
507 #endif
508
509                 if (ui->state == AS_PAUSED || ui->state == AS_CREATED) {
510                         _DBG("[APP %d] RESUME", _pid);
511
512                         if (ui->state == AS_CREATED) {
513                                 bundle_free(ui->pending_data);
514                                 ui->pending_data = NULL;
515                         }
516
517                         if (ui->ops->resume) {
518                                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
519                                         "APPCORE:RESUME");
520                                 ui->ops->resume(ui->ops->data);
521                                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
522                         }
523                         ui->state = AS_RUNNING;
524
525                         if (ui->below_app) {
526                                 aul_app_group_activate_below(ui->below_app);
527                                 free(ui->below_app);
528                                 ui->below_app = NULL;
529                         }
530                 }
531                 /*TODO : rotation start*/
532                 /* r = appcore_resume_rotation_cb(); */
533                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:done]",
534                     ui->name);
535                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:Launching:done]",
536                     ui->name);
537                 aul_status_update(STATUS_VISIBLE);
538                 break;
539         case AE_TERMINATE_BGAPP:
540                 if (ui->state == AS_PAUSED) {
541                         _DBG("[APP %d] is paused. TERMINATE", _pid);
542                         ui->state = AS_DYING;
543                         aul_status_update(STATUS_DYING);
544                         elm_exit();
545                 } else if (ui->state == AS_RUNNING) {
546                         _DBG("[APP %d] is running.", _pid);
547                 } else {
548                         _DBG("[APP %d] is another state", _pid);
549                 }
550                 break;
551         case AE_UPDATE_REQUESTED:
552                 __appcore_efl_update_requested(ui);
553                 break;
554         default:
555                 /* do nothing */
556                 break;
557         }
558 }
559
560 static struct ui_ops efl_ops = {
561         .data = &priv,
562         .cb_app = __do_app,
563 };
564
565 static bool __check_visible(void)
566 {
567         GSList *iter = NULL;
568         struct win_node *entry = NULL;
569
570         _DBG("[EVENT_TEST][EVENT] __check_visible\n");
571
572         for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
573                 entry = iter->data;
574                 _DBG("win : %x obscured : %d\n", entry->win, entry->bfobscured);
575                 if (entry->bfobscured == FALSE)
576                         return TRUE;
577         }
578
579         return FALSE;
580 }
581
582 static GSList *__find_win(unsigned int win)
583 {
584         GSList *iter;
585         struct win_node *t;
586
587         for (iter = g_winnode_list; iter; iter = g_slist_next(iter)) {
588                 t = iter->data;
589                 if (t && t->win == win)
590                         return iter;
591         }
592
593         return NULL;
594 }
595
596 #if defined(X11)
597 static bool __add_win(unsigned int win)
598 {
599         struct win_node *t;
600         GSList *f;
601
602         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
603
604         f = __find_win(win);
605         if (f) {
606                 errno = ENOENT;
607                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
608                 return FALSE;
609         }
610
611         t = calloc(1, sizeof(struct win_node));
612         if (t == NULL)
613                 return FALSE;
614
615         t->win = win;
616         t->bfobscured = FALSE;
617
618         g_winnode_list = g_slist_append(g_winnode_list, t);
619
620         return TRUE;
621 }
622 #elif defined(WAYLAND)
623 static bool __add_win(unsigned int win, unsigned int surf)
624 {
625         struct win_node *t;
626         GSList *f;
627
628         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
629
630         f = __find_win(win);
631         if (f) {
632                 errno = ENOENT;
633                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
634                 return FALSE;
635         }
636
637         t = calloc(1, sizeof(struct win_node));
638         if (t == NULL)
639                 return FALSE;
640
641         t->win = win;
642         t->surf = surf;
643         t->bfobscured = FALSE;
644
645         g_winnode_list = g_slist_append(g_winnode_list, t);
646
647         return TRUE;
648 }
649 #endif
650
651 static bool __delete_win(unsigned int win)
652 {
653         GSList *f;
654
655         f = __find_win(win);
656         if (!f) {
657                 errno = ENOENT;
658                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
659                                 win);
660                 return FALSE;
661         }
662
663         free(f->data);
664         g_winnode_list = g_slist_delete_link(g_winnode_list, f);
665
666         return TRUE;
667 }
668
669 #if defined(X11)
670 static bool __update_win(unsigned int win, bool bfobscured)
671 {
672         GSList *f;
673         struct win_node *t;
674
675         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
676              bfobscured);
677
678         f = __find_win(win);
679         if (!f) {
680                 errno = ENOENT;
681                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
682                 return FALSE;
683         }
684
685         g_winnode_list = g_slist_remove_link(g_winnode_list, f);
686
687         t = (struct win_node *)f->data;
688         t->win = win;
689         t->bfobscured = bfobscured;
690
691         g_winnode_list = g_slist_concat(g_winnode_list, f);
692
693         return TRUE;
694 }
695 #elif defined(WAYLAND)
696 static bool __update_win(unsigned int win, unsigned int surf, bool bfobscured)
697 {
698         GSList *f;
699         struct win_node *t;
700
701         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
702              bfobscured);
703
704         f = __find_win(win);
705         if (!f) {
706                 errno = ENOENT;
707                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
708                 return FALSE;
709         }
710
711         g_winnode_list = g_slist_remove_link(g_winnode_list, f);
712
713         t = (struct win_node *)f->data;
714         t->win = win;
715         if (surf != 0)
716                 t->surf = surf;
717         t->bfobscured = bfobscured;
718
719         g_winnode_list = g_slist_concat(g_winnode_list, f);
720
721         return TRUE;
722 }
723 #endif
724
725 /* WM_ROTATE */
726 #ifdef X11
727 static Ecore_X_Atom _WM_WINDOW_ROTATION_SUPPORTED = 0;
728 static Ecore_X_Atom _WM_WINDOW_ROTATION_CHANGE_REQUEST = 0;
729
730 static int __check_wm_rotation_support(void)
731 {
732         _DBG("Disable window manager rotation");
733         return -1;
734
735         Ecore_X_Window root, win, win2;
736         int ret;
737
738         if (!_WM_WINDOW_ROTATION_SUPPORTED) {
739                 _WM_WINDOW_ROTATION_SUPPORTED =
740                                         ecore_x_atom_get("_E_WINDOW_ROTATION_SUPPORTED");
741         }
742
743         if (!_WM_WINDOW_ROTATION_CHANGE_REQUEST) {
744                 _WM_WINDOW_ROTATION_CHANGE_REQUEST =
745                                         ecore_x_atom_get("_E_WINDOW_ROTATION_CHANGE_REQUEST");
746         }
747
748         root = ecore_x_window_root_first_get();
749         ret = ecore_x_window_prop_xid_get(root,
750                         _WM_WINDOW_ROTATION_SUPPORTED,
751                         ECORE_X_ATOM_WINDOW,
752                         &win, 1);
753         if ((ret == 1) && (win)) {
754                 ret = ecore_x_window_prop_xid_get(win,
755                                 _WM_WINDOW_ROTATION_SUPPORTED,
756                                 ECORE_X_ATOM_WINDOW,
757                                 &win2, 1);
758                 if ((ret == 1) && (win2 == win))
759                         return 0;
760         }
761
762         return -1;
763 }
764
765 static void __set_wm_rotation_support(unsigned int win, unsigned int set)
766 {
767         GSList *iter = NULL;
768         struct win_node *entry = NULL;
769
770         if (win == 0) {
771                 for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
772                         entry = iter->data;
773                         if (entry->win) {
774                                 ecore_x_window_prop_card32_set(entry->win,
775                                                 _WM_WINDOW_ROTATION_SUPPORTED,
776                                                 &set, 1);
777                         }
778                 }
779         } else {
780                 ecore_x_window_prop_card32_set(win,
781                                 _WM_WINDOW_ROTATION_SUPPORTED,
782                                 &set, 1);
783         }
784 }
785 #endif
786
787 static Eina_Bool __show_cb(void *data, int type, void *event)
788 {
789 #if defined(WAYLAND)
790         Ecore_Wl_Event_Window_Show *ev;
791
792         ev = event;
793         if (ev->parent_win != 0) {
794                 /* This is child window. Skip!!! */
795                 return ECORE_CALLBACK_PASS_ON;
796         }
797
798         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x, %d\n", ev->win, ev->data[0]);
799
800         if (!__find_win((unsigned int)ev->win))
801                 __add_win((unsigned int)ev->win, (unsigned int)ev->data[0]);
802         else
803                 __update_win((unsigned int)ev->win, (unsigned int)ev->data[0], FALSE);
804
805 #elif defined(X11)
806         Ecore_X_Event_Window_Show *ev;
807
808         ev = event;
809
810         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x\n", ev->win);
811
812         if (!__find_win((unsigned int)ev->win)) {
813                 /* WM_ROTATE */
814                 if ((priv.wm_rot_supported) && (1 == priv.rot_started))
815                         __set_wm_rotation_support(ev->win, 1);
816                 __add_win((unsigned int)ev->win);
817         } else {
818                 __update_win((unsigned int)ev->win, FALSE);
819         }
820 #endif
821
822         appcore_group_attach();
823         return ECORE_CALLBACK_RENEW;
824 }
825
826 static Eina_Bool __hide_cb(void *data, int type, void *event)
827 {
828 #if defined(WAYLAND)
829         Ecore_Wl_Event_Window_Hide *ev;
830 #elif defined(X11)
831         Ecore_X_Event_Window_Hide *ev;
832 #endif
833         int bvisibility = 0;
834
835         ev = event;
836
837         _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
838
839         if (__find_win((unsigned int)ev->win)) {
840                 __delete_win((unsigned int)ev->win);
841                 bvisibility = __check_visible();
842                 if (!bvisibility && b_active == TRUE) {
843                         _DBG(" Go to Pasue state \n");
844                         b_active = FALSE;
845                         __do_app(AE_PAUSE, data, NULL);
846                 }
847         }
848
849         return ECORE_CALLBACK_RENEW;
850 }
851
852 #if defined(WAYLAND)
853 static Eina_Bool __lower_cb(void *data, int type, void *event)
854 {
855         Ecore_Wl_Event_Window_Lower *ev;
856         ev = event;
857         if (!ev) return ECORE_CALLBACK_RENEW;
858         _DBG("ECORE_WL_EVENT_WINDOW_LOWER window id:%u\n", ev->win);
859         appcore_group_lower();
860         return ECORE_CALLBACK_RENEW;
861 }
862 #endif
863
864 static Eina_Bool __visibility_cb(void *data, int type, void *event)
865 {
866 #if defined(WAYLAND)
867         Ecore_Wl_Event_Window_Visibility_Change *ev;
868         int bvisibility = 0;
869         ev = event;
870         __update_win((unsigned int)ev->win, 0, ev->fully_obscured);
871 #elif defined(X11)
872         Ecore_X_Event_Window_Visibility_Change *ev;
873         int bvisibility = 0;
874
875         ev = event;
876
877         __update_win((unsigned int)ev->win, ev->fully_obscured);
878 #endif
879         bvisibility = __check_visible();
880
881         _DBG("bvisibility %d, b_active %d", bvisibility, b_active);
882
883         if (bvisibility && b_active == FALSE) {
884                 _DBG(" Go to Resume state\n");
885                 b_active = TRUE;
886                 __do_app(AE_RESUME, data, NULL);
887
888         } else if (!bvisibility && b_active == TRUE) {
889                 _DBG(" Go to Pasue state \n");
890                 b_active = FALSE;
891                 __do_app(AE_PAUSE, data, NULL);
892         } else
893                 _DBG(" No change state \n");
894
895         return ECORE_CALLBACK_RENEW;
896
897 }
898
899 #if defined(X11)
900 /* WM_ROTATE */
901 static Eina_Bool __cmsg_cb(void *data, int type, void *event)
902 {
903         struct ui_priv *ui = (struct ui_priv *)data;
904         Ecore_X_Event_Client_Message *e = event;
905
906         if (!ui)
907                 return ECORE_CALLBACK_PASS_ON;
908
909         if (e->format != 32)
910                 return ECORE_CALLBACK_PASS_ON;
911
912         if (e->message_type == _WM_WINDOW_ROTATION_CHANGE_REQUEST) {
913                 if ((ui->wm_rot_supported == 0)
914                         || (ui->rot_started == 0)
915                         || (ui->rot_cb == NULL)) {
916                         return ECORE_CALLBACK_PASS_ON;
917                 }
918
919                 enum appcore_rm rm;
920                 switch (e->data.l[1]) {
921                 case 0:
922                         rm = APPCORE_RM_PORTRAIT_NORMAL;
923                         break;
924                 case 90:
925                         rm = APPCORE_RM_LANDSCAPE_REVERSE;
926                         break;
927                 case 180:
928                         rm = APPCORE_RM_PORTRAIT_REVERSE;
929                         break;
930                 case 270:
931                         rm = APPCORE_RM_LANDSCAPE_NORMAL;
932                         break;
933                 default:
934                         rm = APPCORE_RM_UNKNOWN;
935                         break;
936                 }
937
938                 ui->rot_mode = rm;
939
940                 if (APPCORE_RM_UNKNOWN != rm)
941                         ui->rot_cb((void *)&rm, rm, ui->rot_cb_data);
942         }
943
944         return ECORE_CALLBACK_PASS_ON;
945 }
946 #endif
947
948 static void __add_climsg_cb(struct ui_priv *ui)
949 {
950         _ret_if(ui == NULL);
951 #if defined(WAYLAND)
952         ui->hshow =
953                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_SHOW, __show_cb, ui);
954         ui->hhide =
955                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_HIDE, __hide_cb, ui);
956         ui->hvchange =
957                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE,
958                                 __visibility_cb, ui);
959         ui->hlower =
960                 ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_LOWER,
961                                 __lower_cb, ui);
962 #elif defined(X11)
963         ui->hshow =
964                 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHOW, __show_cb, ui);
965         ui->hhide =
966                 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_HIDE, __hide_cb, ui);
967         ui->hvchange =
968                 ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE,
969                                 __visibility_cb, ui);
970
971         /* Add client message callback for WM_ROTATE */
972         if (!__check_wm_rotation_support()) {
973                 ui->hcmsg = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,
974                                 __cmsg_cb, ui);
975                 ui->wm_rot_supported = 1;
976                 appcore_set_wm_rotation(&wm_rotate);
977         }
978 #endif
979 }
980
981 static int __before_loop(struct ui_priv *ui, int *argc, char ***argv)
982 {
983         int r;
984         char *hwacc = NULL;
985 #if _APPFW_FEATURE_BACKGROUND_MANAGEMENT
986         struct appcore *ac = NULL;
987 #endif
988         bundle *b;
989         const char *bg_launch;
990
991         if (argc == NULL || argv == NULL) {
992                 _ERR("argc/argv is NULL");
993                 errno = EINVAL;
994                 return -1;
995         }
996
997 #if !(GLIB_CHECK_VERSION(2, 36, 0))
998         g_type_init();
999 #endif
1000         elm_init(*argc, *argv);
1001
1002         hwacc = getenv("HWACC");
1003         if (hwacc == NULL) {
1004                 _DBG("elm_config_accel_preference_set is not called");
1005         } else if (strcmp(hwacc, "USE") == 0) {
1006                 elm_config_accel_preference_set("hw");
1007                 _DBG("elm_config_accel_preference_set : hw");
1008         } else if (strcmp(hwacc, "NOT_USE") == 0) {
1009                 elm_config_accel_preference_set("none");
1010                 _DBG("elm_config_accel_preference_set : none");
1011         } else {
1012                 _DBG("elm_config_accel_preference_set is not called");
1013         }
1014
1015         r = appcore_init(ui->name, &efl_ops, *argc, *argv);
1016         _retv_if(r == -1, -1);
1017
1018 #if _APPFW_FEATURE_BACKGROUND_MANAGEMENT
1019         appcore_get_app_core(&ac);
1020         ui->app_core = ac;
1021         SECURE_LOGD("[__SUSPEND__] appcore initialized, appcore addr: #%x", ac);
1022 #endif
1023
1024         b = bundle_import_from_argv(*argc, *argv);
1025         if (b) {
1026                 bg_launch = bundle_get_val(b, AUL_SVC_K_BG_LAUNCH);
1027                 if (bg_launch && strcmp(bg_launch, "enable") == 0)
1028                         __set_bg_state();
1029
1030                 bundle_free(b);
1031         }
1032
1033         LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:appcore_init:done]", ui->name);
1034         if (ui->ops && ui->ops->create) {
1035                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:CREATE");
1036                 r = ui->ops->create(ui->ops->data);
1037                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1038                 if (r < 0) {
1039                         _ERR("create() return error");
1040                         appcore_exit();
1041                         if (ui->ops && ui->ops->terminate) {
1042                                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
1043                                         "APPCORE:TERMINATE");
1044                                 ui->ops->terminate(ui->ops->data);
1045                                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1046                         }
1047                         errno = ECANCELED;
1048                         return -1;
1049                 }
1050                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]",
1051                     ui->name);
1052         }
1053         ui->state = AS_CREATED;
1054
1055         __add_climsg_cb(ui);
1056
1057         return 0;
1058 }
1059
1060 static void __after_loop(struct ui_priv *ui)
1061 {
1062         appcore_unset_rotation_cb();
1063         appcore_exit();
1064
1065         if (ui->state == AS_RUNNING) {
1066                 _DBG("[APP %d] PAUSE before termination", _pid);
1067                 if (ui->ops && ui->ops->pause) {
1068                         traceBegin(TTRACE_TAG_APPLICATION_MANAGER,
1069                                         "APPCORE:PAUSE");
1070                         ui->ops->pause(ui->ops->data);
1071                         traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1072                 }
1073         }
1074
1075         if (ui->ops && ui->ops->terminate) {
1076                 traceBegin(TTRACE_TAG_APPLICATION_MANAGER, "APPCORE:TERMINATE");
1077                 ui->ops->terminate(ui->ops->data);
1078                 traceEnd(TTRACE_TAG_APPLICATION_MANAGER);
1079         }
1080
1081         ui->state = AS_DYING;
1082
1083         if (ui->hshow)
1084                 ecore_event_handler_del(ui->hshow);
1085         if (ui->hhide)
1086                 ecore_event_handler_del(ui->hhide);
1087         if (ui->hvchange)
1088                 ecore_event_handler_del(ui->hvchange);
1089 #if defined(WAYLAND)
1090         if (ui->hlower)
1091                 ecore_event_handler_del(ui->hlower);
1092 #endif
1093
1094         __appcore_timer_del(ui);
1095
1096         elm_shutdown();
1097 }
1098
1099 static int __set_data(struct ui_priv *ui, const char *name,
1100                     struct appcore_ops *ops)
1101 {
1102         if (ui->name) {
1103                 _ERR("Mainloop already started");
1104                 errno = EINPROGRESS;
1105                 return -1;
1106         }
1107
1108         if (name == NULL || name[0] == '\0') {
1109                 _ERR("Invalid name");
1110                 errno = EINVAL;
1111                 return -1;
1112         }
1113
1114         if (ops == NULL) {
1115                 _ERR("ops is NULL");
1116                 errno = EINVAL;
1117                 return -1;
1118         }
1119
1120         ui->name = strdup(name);
1121         _retv_if(ui->name == NULL, -1);
1122
1123         ui->ops = ops;
1124         ui->mfcb = __appcore_efl_memory_flush_cb;
1125         _pid = getpid();
1126
1127         /* WM_ROTATE */
1128         ui->wm_rot_supported = 0;
1129         ui->rot_started = 0;
1130         ui->rot_cb = NULL;
1131         ui->rot_cb_data = NULL;
1132         ui->rot_mode = APPCORE_RM_UNKNOWN;
1133
1134 #ifdef  _APPFW_FEATURE_BACKGROUND_MANAGEMENT
1135         ui->app_core = NULL;
1136         ui->prepare_to_suspend = __appcore_efl_prepare_to_suspend;
1137         ui->exit_from_suspend = __appcore_efl_exit_from_suspend;
1138 #endif
1139
1140         return 0;
1141 }
1142
1143 static void __unset_data(struct ui_priv *ui)
1144 {
1145         if (ui->name)
1146                 free((void *)ui->name);
1147
1148         memset(ui, 0, sizeof(struct ui_priv));
1149 }
1150
1151 #if defined(X11)
1152 /* WM_ROTATE */
1153 static int __wm_set_rotation_cb(int (*cb) (void *event_info, enum appcore_rm, void *), void *data)
1154 {
1155         if (cb == NULL) {
1156                 errno = EINVAL;
1157                 return -1;
1158         }
1159
1160         if ((priv.wm_rot_supported) && (0 == priv.rot_started))
1161                 __set_wm_rotation_support(0, 1);
1162
1163         priv.rot_cb = cb;
1164         priv.rot_cb_data = data;
1165         priv.rot_started = 1;
1166
1167         return 0;
1168 }
1169
1170 static int __wm_unset_rotation_cb(void)
1171 {
1172         if ((priv.wm_rot_supported) && (1 == priv.rot_started))
1173                 __set_wm_rotation_support(0, 0);
1174
1175         priv.rot_cb = NULL;
1176         priv.rot_cb_data = NULL;
1177         priv.rot_started = 0;
1178
1179         return 0;
1180 }
1181
1182 static int __wm_get_rotation_state(enum appcore_rm *curr)
1183 {
1184         if (curr == NULL) {
1185                 errno = EINVAL;
1186                 return -1;
1187         }
1188
1189         *curr = priv.rot_mode;
1190
1191         return 0;
1192 }
1193
1194 static int __wm_pause_rotation_cb(void)
1195 {
1196         if ((priv.rot_started == 1) && (priv.wm_rot_supported))
1197                 __set_wm_rotation_support(0, 0);
1198
1199         priv.rot_started = 0;
1200
1201         return 0;
1202 }
1203
1204 static int __wm_resume_rotation_cb(void)
1205 {
1206         if ((priv.rot_started == 0) && (priv.wm_rot_supported))
1207                 __set_wm_rotation_support(0, 1);
1208
1209         priv.rot_started = 1;
1210
1211         return 0;
1212 }
1213
1214 static struct ui_wm_rotate wm_rotate = {
1215         __wm_set_rotation_cb,
1216         __wm_unset_rotation_cb,
1217         __wm_get_rotation_state,
1218         __wm_pause_rotation_cb,
1219         __wm_resume_rotation_cb
1220 };
1221 #endif
1222
1223 EXPORT_API int appcore_efl_init(const char *name, int *argc, char ***argv,
1224                      struct appcore_ops *ops)
1225 {
1226         int r;
1227
1228         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", name);
1229
1230         r = __set_data(&priv, name, ops);
1231         _retv_if(r == -1, -1);
1232
1233         r = __before_loop(&priv, argc, argv);
1234         if (r == -1) {
1235                 aul_status_update(STATUS_DYING);
1236                 __unset_data(&priv);
1237                 return -1;
1238         }
1239
1240         return 0;
1241 }
1242
1243 EXPORT_API void appcore_efl_fini(void)
1244 {
1245         aul_status_update(STATUS_DYING);
1246
1247         __after_loop(&priv);
1248
1249         __unset_data(&priv);
1250 }
1251
1252 EXPORT_API int appcore_efl_main(const char *name, int *argc, char ***argv,
1253                                 struct appcore_ops *ops)
1254 {
1255         int r;
1256
1257         r = appcore_efl_init(name, argc, argv, ops);
1258         _retv_if(r == -1, -1);
1259
1260         elm_run();
1261
1262         appcore_efl_fini();
1263
1264         return 0;
1265 }
1266
1267 EXPORT_API int appcore_set_system_resource_reclaiming(bool enable)
1268 {
1269         resource_reclaiming = enable;
1270
1271         return 0;
1272 }
1273
1274 EXPORT_API int appcore_set_app_state(int state)
1275 {
1276         priv.state = state;
1277
1278         tmp_val = 1;
1279
1280         return 0;
1281 }
1282
1283 EXPORT_API int appcore_set_preinit_window_name(const char *win_name)
1284 {
1285         int ret = -1;
1286         void *preinit_window = NULL;
1287         const Evas *e = NULL;
1288
1289         if (!win_name) {
1290                 _ERR("invalid parameter");
1291                 return ret;
1292         }
1293
1294         preinit_window = elm_win_precreated_object_get();
1295         if (!preinit_window) {
1296                 _ERR("Failed to get preinit window");
1297                 return ret;
1298         }
1299
1300         e = evas_object_evas_get((const Evas_Object *)preinit_window);
1301         if (e) {
1302                 Ecore_Evas *ee = ecore_evas_ecore_evas_get(e);
1303                 if (ee) {
1304                         ecore_evas_name_class_set(ee, win_name, win_name);
1305                         ret = 0;
1306                 }
1307         }
1308
1309         return ret;
1310 }
1311
1312 EXPORT_API unsigned int appcore_get_main_window(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->win;
1319         }
1320
1321         return 0;
1322 }
1323
1324 #if defined(WAYLAND)
1325 EXPORT_API unsigned int appcore_get_main_surface(void)
1326 {
1327         struct win_node *entry = NULL;
1328
1329         if (g_winnode_list != NULL) {
1330                 entry = g_winnode_list->data;
1331                 return (unsigned int) entry->surf;
1332         }
1333
1334         return 0;
1335 }
1336 #endif