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