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