Add new api for customizing main loop
[platform/core/appfw/app-core.git] / src / appcore-efl.c
1 /*
2  *  app-core
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdarg.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <stdlib.h>
31
32 #ifdef WAYLAND
33 #include <Ecore_Wayland.h>
34 #endif
35
36 #ifdef X11
37 #include <X11/Xatom.h>
38 #include <X11/Xlib.h>
39 #include <Ecore_X.h>
40 #endif
41
42 #include <Ecore.h>
43 #include <Ecore_Evas.h>
44 #include <Ecore_Input_Evas.h>
45 #include <Elementary.h>
46 #include <glib-object.h>
47 #include <malloc.h>
48 #include <glib.h>
49 #include <dbus/dbus.h>
50 #include <stdbool.h>
51 #include <aul.h>
52 #include "appcore-internal.h"
53 #include "appcore-efl.h"
54
55 static pid_t _pid;
56
57 static bool resource_reclaiming = TRUE;
58 static int tmp_val = 0;
59
60 enum proc_status_type { /** cgroup command type **/
61         PROC_STATUS_LAUNCH,
62         PROC_STATUS_RESUME,
63         PROC_STATUS_TERMINATE,
64         PROC_STATUS_FOREGRD,
65         PROC_STATUS_BACKGRD,
66 };
67
68 struct ui_priv {
69         const char *name;
70         enum app_state state;
71
72         Ecore_Event_Handler *hshow;
73         Ecore_Event_Handler *hhide;
74         Ecore_Event_Handler *hvchange;
75         Ecore_Event_Handler *hcmsg; /* WM_ROTATE */
76
77         Ecore_Timer *mftimer;   /* Ecore Timer for memory flushing */
78
79         struct appcore_ops *ops;
80         void (*mfcb) (void);    /* Memory Flushing Callback */
81
82         /* WM_ROTATE */
83         int wm_rot_supported;
84         int rot_started;
85         int (*rot_cb) (void *event_info, enum appcore_rm, void *);
86         void *rot_cb_data;
87         enum appcore_rm rot_mode;
88         bundle *pending_data;
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 #ifdef WAYLAND
118         unsigned int surf;
119 #endif
120         bool bfobscured;
121 };
122
123 static struct ui_wm_rotate wm_rotate;
124 static Eina_Bool __visibility_cb(void *data, int type, void *event);
125
126
127 static void _send_to_resourced(enum proc_status_type type)
128 {
129         DBusConnection *conn;
130         DBusMessage* msg;
131         DBusError dbus_error;
132
133         dbus_error_init(&dbus_error);
134
135         conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);
136         if (!conn) {
137                 _ERR("dbus_bus_get failed : [%s]", dbus_error.message);
138                 dbus_error_free(&dbus_error);
139                 return;
140         }
141
142         msg = dbus_message_new_signal("/Org/Tizen/ResourceD/Process",
143                         "org.tizen.resourced.process",
144                         "ProcStatus");
145         if (!msg) {
146                 _ERR("dbus_message_new_signal is failed");
147                 return;
148         }
149
150         if (!dbus_message_append_args(msg,
151                                 DBUS_TYPE_INT32, &type,
152                                 DBUS_TYPE_INT32, &_pid,
153                                 DBUS_TYPE_INVALID)) {
154                 _ERR("dbus_message_append_args is failed. type = %d, pid = %d",
155                                 type, _pid);
156                 dbus_message_unref(msg);
157                 return;
158         }
159
160         if (!dbus_connection_send (conn, msg, NULL)) {
161                 _ERR("dbus_connection_send is failed");
162         }
163
164         dbus_message_unref(msg);
165 }
166
167 static GSList *g_winnode_list;
168
169 #if defined(MEMORY_FLUSH_ACTIVATE)
170 static Eina_Bool __appcore_memory_flush_cb(void *data)
171 {
172         struct ui_priv *ui = (struct ui_priv *)data;
173
174         appcore_flush_memory();
175         ui->mftimer = NULL;
176
177         return ECORE_CALLBACK_CANCEL;
178 }
179
180 static int __appcore_low_memory_post_cb(struct ui_priv *ui)
181 {
182         if (ui->state == AS_PAUSED) {
183                 appcore_flush_memory();
184         } else {
185                 malloc_trim(0);
186         }
187
188         return 0;
189 }
190
191 static void __appcore_timer_add(struct ui_priv *ui)
192 {
193         ui->mftimer = ecore_timer_add(5, __appcore_memory_flush_cb, ui);
194 }
195
196 static void __appcore_timer_del(struct ui_priv *ui)
197 {
198         if (ui->mftimer) {
199                 ecore_timer_del(ui->mftimer);
200                 ui->mftimer = NULL;
201         }
202 }
203
204 #else
205
206 static int __appcore_low_memory_post_cb(ui_priv *ui)
207 {
208         return -1;
209 }
210
211 #define __appcore_timer_add(ui) 0
212 #define __appcore_timer_del(ui) 0
213
214 #endif
215
216 static void __appcore_efl_memory_flush_cb(void)
217 {
218         _DBG("[APP %d]   __appcore_efl_memory_flush_cb()", _pid);
219         elm_cache_all_flush();
220 }
221 #ifdef WAYLAND
222 static void wl_raise_win()
223 {
224         Ecore_Wl_Window *win;
225         unsigned int win_id = appcore_get_main_window();
226         _DBG("Raise window : %d", win_id);
227         win = ecore_wl_window_find(win_id);
228         ecore_wl_window_activate(win);
229 }
230 #endif
231
232 static void __do_app(enum app_event event, void *data, bundle * b)
233 {
234         int r = -1;
235         struct ui_priv *ui = data;
236
237         _DBG("[APP %d] Event: %d", _pid, event);
238         _ret_if(ui == NULL || event >= AE_MAX);
239         _DBG("[APP %d] Event: %s State: %s", _pid, _ae_name[event],
240              _as_name[ui->state]);
241
242         if (event == AE_MEM_FLUSH) {
243                 ui->mfcb();
244                 return;
245         }
246
247         if (event == AE_LOWMEM_POST) {
248                 if (__appcore_low_memory_post_cb(ui) == 0)
249                         return;
250         }
251
252         if (!(ui->state == AS_PAUSED && event == AE_PAUSE))
253                 __appcore_timer_del(ui);
254
255         if (ui->state == AS_DYING) {
256                 _ERR("Skip the event in dying state");
257                 return;
258         }
259
260         if (event == AE_TERMINATE) {
261                 _DBG("[APP %d] TERMINATE", _pid);
262                 elm_exit();
263                 aul_status_update(STATUS_DYING);
264                 return;
265         }
266
267         if (event == AE_RAISE) {
268 #ifdef X11
269                 x_raise_win(getpid());
270 #else
271                 wl_raise_win();
272 #endif
273                 return;
274         }
275
276         if (event == AE_LOWER) {
277 #ifdef X11
278                 x_pause_win(getpid());
279                 return;
280 #endif
281                 /* TODO: wayland support */
282         }
283
284         _ret_if(ui->ops == NULL);
285
286         switch (event) {
287         case AE_RESET:
288                 _DBG("[APP %d] RESET", _pid);
289                 ui->pending_data = bundle_dup(b);
290                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]", ui->name);
291                 if (ui->ops->reset)
292                         r = ui->ops->reset(b, ui->ops->data);
293                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]", ui->name);
294
295                 if (first_launch) {
296                         first_launch = FALSE;
297                 } else {
298                         _INFO("[APP %d] App already running, raise the window", _pid);
299 #ifdef X11
300                         x_raise_win(getpid());
301 #else
302                         wl_raise_win();
303 #endif
304                 }
305                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]",
306                     ui->name);
307                 break;
308         case AE_PAUSE:
309                 if (ui->state == AS_RUNNING) {
310                         _DBG("[APP %d] PAUSE", _pid);
311                         if (ui->ops->pause)
312                                 r = ui->ops->pause(ui->ops->data);
313                         ui->state = AS_PAUSED;
314                         if(r >= 0 && resource_reclaiming == TRUE)
315                                 __appcore_timer_add(ui);
316                 }
317                 /* TODO : rotation stop */
318                 //r = appcore_pause_rotation_cb();
319                 aul_status_update(STATUS_BG);
320                 _send_to_resourced(PROC_STATUS_BACKGRD);
321                 break;
322         case AE_RESUME:
323                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:start]",
324                                 ui->name);
325                 if (ui->state == AS_PAUSED || ui->state == AS_CREATED) {
326                         _DBG("[APP %d] RESUME", _pid);
327
328                         if (ui->state == AS_CREATED) {
329                                 appcore_group_reset(ui->pending_data);
330                                 bundle_free(ui->pending_data);
331                                 ui->pending_data = NULL;
332                         } else {
333                                 appcore_group_resume();
334                         }
335
336                         if (ui->ops->resume) {
337                                 ui->ops->resume(ui->ops->data);
338                         }
339                         ui->state = AS_RUNNING;
340                 }
341                 /*TODO : rotation start*/
342                 //r = appcore_resume_rotation_cb();
343                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:done]",
344                     ui->name);
345                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:Launching:done]",
346                     ui->name);
347                 aul_status_update(STATUS_VISIBLE);
348                 _send_to_resourced(PROC_STATUS_FOREGRD);
349                 break;
350         case AE_TERMINATE_BGAPP:
351                 if (ui->state == AS_PAUSED) {
352                         _DBG("[APP %d] is paused. TERMINATE", _pid);
353                         ui->state = AS_DYING;
354                         aul_status_update(STATUS_DYING);
355                         elm_exit();
356                 } else if (ui->state == AS_RUNNING) {
357                         _DBG("[APP %d] is running.", _pid);
358                 } else {
359                         _DBG("[APP %d] is another state", _pid);
360                 }
361                 break;
362         default:
363                 /* do nothing */
364                 break;
365         }
366 }
367
368 static struct ui_ops efl_ops = {
369         .data = &priv,
370         .cb_app = __do_app,
371 };
372
373
374 static bool __check_visible(void)
375 {
376         GSList *iter = NULL;
377         struct win_node *entry = NULL;
378
379         _DBG("[EVENT_TEST][EVENT] __check_visible\n");
380         
381         for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
382                 entry = iter->data;     
383                 _DBG("win : %x obscured : %d\n", entry->win, entry->bfobscured);
384                 if(entry->bfobscured == FALSE)
385                         return TRUE;            
386         }
387         return FALSE;
388 }
389
390 static GSList *__find_win(unsigned int win)
391 {
392         GSList *iter;
393         struct win_node *t;
394
395         for (iter = g_winnode_list; iter; iter = g_slist_next(iter)) {
396                 t = iter->data;
397                 if (t && t->win == win)
398                         return iter;
399         }
400
401         return NULL;
402 }
403
404 #ifdef X11
405 static bool __add_win(unsigned int win)
406 {
407         struct win_node *t;
408         GSList *f;
409
410         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
411
412         f = __find_win(win);
413         if (f) {
414                 errno = ENOENT;
415                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
416                 return FALSE;
417         }
418
419         t = calloc(1, sizeof(struct win_node));
420         if (t == NULL)
421                 return FALSE;
422
423         t->win = win;
424         t->bfobscured = FALSE;
425
426         g_winnode_list = g_slist_append(g_winnode_list, t);
427
428         return TRUE;
429 }
430 #else
431 static bool __add_win(unsigned int win, unsigned int surf)
432 {
433         struct win_node *t;
434         GSList *f;
435
436         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
437
438         f = __find_win(win);
439         if (f) {
440                 errno = ENOENT;
441                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
442                 return FALSE;
443         }
444
445         t = calloc(1, sizeof(struct win_node));
446         if (t == NULL)
447                 return FALSE;
448
449         t->win = win;
450         t->surf = surf;
451         t->bfobscured = FALSE;
452
453         g_winnode_list = g_slist_append(g_winnode_list, t);
454
455         return TRUE;
456 }
457 #endif
458
459 static bool __delete_win(unsigned int win)
460 {
461         GSList *f;
462
463         f = __find_win(win);
464         if (!f) {
465                 errno = ENOENT;
466                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
467                                 win);
468                 return FALSE;
469         }
470
471         free(f->data);
472         g_winnode_list = g_slist_delete_link(g_winnode_list, f);
473
474         return TRUE;
475 }
476
477 #ifdef X11
478 static bool __update_win(unsigned int win, bool bfobscured)
479 {
480         GSList *f;
481         struct win_node *t;
482
483         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
484              bfobscured);
485
486         f = __find_win(win);
487         if (!f) {
488                 errno = ENOENT;
489                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
490                 return FALSE;
491         }
492
493         g_winnode_list = g_slist_remove_link(g_winnode_list, f);
494
495         t = (struct win_node *)f->data;
496         t->win = win;
497         t->bfobscured = bfobscured;
498
499         g_winnode_list = g_slist_concat(g_winnode_list, f);
500
501         return TRUE;
502 }
503 #else
504 static bool __update_win(unsigned int win, unsigned int surf, bool bfobscured)
505 {
506         GSList *f;
507         struct win_node *t;
508
509         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
510              bfobscured);
511
512         f = __find_win(win);
513         if (!f) {
514                 errno = ENOENT;
515                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
516                 return FALSE;
517         }
518
519         g_winnode_list = g_slist_remove_link(g_winnode_list, f);
520
521         t = (struct win_node *)f->data;
522         t->win = win;
523         if (surf != 0)
524                 t->surf = surf;
525         t->bfobscured = bfobscured;
526
527         g_winnode_list = g_slist_concat(g_winnode_list, f);
528
529         return TRUE;
530 }
531 #endif
532
533 /* WM_ROTATE */
534 #ifdef X11
535 static Ecore_X_Atom _WM_WINDOW_ROTATION_SUPPORTED = 0;
536 static Ecore_X_Atom _WM_WINDOW_ROTATION_CHANGE_REQUEST = 0;
537
538 static int __check_wm_rotation_support(void)
539 {
540         _DBG("Disable window manager rotation");
541         return -1;
542
543         Ecore_X_Window root, win, win2;
544         int ret;
545
546         if (!_WM_WINDOW_ROTATION_SUPPORTED) {
547                 _WM_WINDOW_ROTATION_SUPPORTED =
548                                         ecore_x_atom_get("_E_WINDOW_ROTATION_SUPPORTED");
549         }
550
551         if (!_WM_WINDOW_ROTATION_CHANGE_REQUEST) {
552                 _WM_WINDOW_ROTATION_CHANGE_REQUEST =
553                                         ecore_x_atom_get("_E_WINDOW_ROTATION_CHANGE_REQUEST");
554         }
555
556         root = ecore_x_window_root_first_get();
557         ret = ecore_x_window_prop_xid_get(root,
558                         _WM_WINDOW_ROTATION_SUPPORTED,
559                         ECORE_X_ATOM_WINDOW,
560                         &win, 1);
561         if ((ret == 1) && (win))
562         {
563                 ret = ecore_x_window_prop_xid_get(win,
564                                 _WM_WINDOW_ROTATION_SUPPORTED,
565                                 ECORE_X_ATOM_WINDOW,
566                                 &win2, 1);
567                 if ((ret == 1) && (win2 == win))
568                         return 0;
569         }
570
571         return -1;
572 }
573
574 static void __set_wm_rotation_support(unsigned int win, unsigned int set)
575 {
576         GSList *iter = NULL;
577         struct win_node *entry = NULL;
578
579         if (0 == win) {
580                 for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
581                         entry = iter->data;
582                         if (entry->win) {
583                                 ecore_x_window_prop_card32_set(entry->win,
584                                                 _WM_WINDOW_ROTATION_SUPPORTED,
585                                                 &set, 1);
586                         }
587                 }
588         } else {
589                 ecore_x_window_prop_card32_set(win,
590                                 _WM_WINDOW_ROTATION_SUPPORTED,
591                                 &set, 1);
592         }
593 }
594
595 #endif
596
597 static Eina_Bool __show_cb(void *data, int type, void *event)
598 {
599 #ifdef WAYLAND
600         Ecore_Wl_Event_Window_Show *ev;
601
602         ev = event;
603         if (ev->parent_win != 0)
604         {
605                 // This is child window. Skip!!!
606                 return ECORE_CALLBACK_PASS_ON;
607         }
608
609         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x, %d\n", ev->win, ev->data[0]);
610
611         if (!__find_win((unsigned int)ev->win))
612                 __add_win((unsigned int)ev->win, (unsigned int)ev->data[0]);
613         else
614                 __update_win((unsigned int)ev->win, (unsigned int)ev->data[0], FALSE);
615
616 #else
617         Ecore_X_Event_Window_Show *ev;
618         int ret;
619         Ecore_X_Window parent;
620
621         ev = event;
622
623         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x\n", ev->win);
624
625         if (!__find_win((unsigned int)ev->win)) {
626                 /* WM_ROTATE */
627                 if ((priv.wm_rot_supported) && (1 == priv.rot_started)) {
628                         __set_wm_rotation_support(ev->win, 1);
629                 }
630                 __add_win((unsigned int)ev->win);
631         }
632         else
633                 __update_win((unsigned int)ev->win, FALSE);
634 #endif
635
636         return ECORE_CALLBACK_RENEW;
637 }
638
639 static Eina_Bool __hide_cb(void *data, int type, void *event)
640 {
641 #ifdef WAYLAND
642         Ecore_Wl_Event_Window_Hide *ev;
643 #else
644         Ecore_X_Event_Window_Hide *ev;
645 #endif
646         int bvisibility = 0;
647
648         ev = event;
649
650         _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
651
652         if (__find_win((unsigned int)ev->win)) {
653                 __delete_win((unsigned int)ev->win);
654                 bvisibility = __check_visible();
655                 if (!bvisibility && b_active == TRUE) {
656                         _DBG(" Go to Pasue state \n");
657                         b_active = FALSE;
658                         __do_app(AE_PAUSE, data, NULL);
659                 }
660         }
661
662         return ECORE_CALLBACK_RENEW;
663 }
664
665 static Eina_Bool __visibility_cb(void *data, int type, void *event)
666 {
667 #ifdef WAYLAND
668         Ecore_Wl_Event_Window_Visibility_Change *ev;
669         int bvisibility = 0;
670         ev = event;
671         __update_win((unsigned int)ev->win, 0, ev->fully_obscured);
672 #else
673         Ecore_X_Event_Window_Visibility_Change *ev;
674         int bvisibility = 0;
675
676         ev = event;
677
678         __update_win((unsigned int)ev->win, ev->fully_obscured);
679 #endif
680         bvisibility = __check_visible();
681
682         _DBG("bvisibility %d, b_active %d", bvisibility, b_active);
683
684         if (bvisibility && b_active == FALSE) {
685                 _DBG(" Go to Resume state\n");
686                 b_active = TRUE;
687                 __do_app(AE_RESUME, data, NULL);
688
689         } else if (!bvisibility && b_active == TRUE) {
690                 _DBG(" Go to Pasue state \n");
691                 b_active = FALSE;
692                 __do_app(AE_PAUSE, data, NULL);
693         } else
694                 _DBG(" No change state \n");
695
696         return ECORE_CALLBACK_RENEW;
697
698 }
699
700 #ifdef X11
701 /* WM_ROTATE */
702 static Eina_Bool __cmsg_cb(void *data, int type, void *event)
703 {
704         struct ui_priv *ui = (struct ui_priv *)data;
705         Ecore_X_Event_Client_Message *e = event;
706
707         if (!ui) return ECORE_CALLBACK_PASS_ON;
708         if (e->format != 32) return ECORE_CALLBACK_PASS_ON;
709         if (e->message_type == _WM_WINDOW_ROTATION_CHANGE_REQUEST) {
710                 if ((0 == ui->wm_rot_supported) ||
711                         (0 == ui->rot_started) ||
712                         (NULL == ui->rot_cb)) {
713                         return ECORE_CALLBACK_PASS_ON;
714                 }
715
716                 enum appcore_rm rm;
717                 switch (e->data.l[1])
718                 {
719                         case   0: rm = APPCORE_RM_PORTRAIT_NORMAL;   break;
720                         case  90: rm = APPCORE_RM_LANDSCAPE_REVERSE; break;
721                         case 180: rm = APPCORE_RM_PORTRAIT_REVERSE;  break;
722                         case 270: rm = APPCORE_RM_LANDSCAPE_NORMAL;  break;
723                         default:  rm = APPCORE_RM_UNKNOWN;           break;
724                 }
725
726                 ui->rot_mode = rm;
727
728                 if (APPCORE_RM_UNKNOWN != rm) {
729                         ui->rot_cb((void *)&rm, rm, ui->rot_cb_data);
730                 }
731         }
732
733         return ECORE_CALLBACK_PASS_ON;
734 }
735 #endif
736
737 static void __add_climsg_cb(struct ui_priv *ui)
738 {
739         _ret_if(ui == NULL);
740 #ifdef WAYLAND
741         ui->hshow =
742             ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_SHOW, __show_cb, ui);
743         ui->hhide =
744             ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_HIDE, __hide_cb, ui);
745         ui->hvchange =
746             ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE,
747                                     __visibility_cb, ui);
748 #else
749         ui->hshow =
750             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHOW, __show_cb, ui);
751         ui->hhide =
752             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_HIDE, __hide_cb, ui);
753         ui->hvchange =
754             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE,
755                                     __visibility_cb, ui);
756
757         /* Add client message callback for WM_ROTATE */
758         if(!__check_wm_rotation_support())
759         {
760                 ui->hcmsg =
761                         ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, __cmsg_cb, ui);
762                 ui->wm_rot_supported = 1;
763                 appcore_set_wm_rotation(&wm_rotate);
764         }
765 #endif
766 }
767
768 static int __before_loop(struct ui_priv *ui, int *argc, char ***argv)
769 {
770         int r;
771         char *hwacc = NULL;
772
773         if (argc == NULL || argv == NULL) {
774                 _ERR("argc/argv is NULL");
775                 errno = EINVAL;
776                 return -1;
777         }
778
779         g_type_init();
780         elm_init(*argc, *argv);
781
782         hwacc = getenv("HWACC");
783
784         if(hwacc == NULL) {
785                 _DBG("elm_config_preferred_engine_set is not called");
786         } else if(strcmp(hwacc, "USE") == 0) {
787 #ifdef WAYLAND
788                 elm_config_preferred_engine_set("wayland_egl");
789                 _DBG("elm_config_preferred_engine_set : wayland_egl");
790 #else
791                 elm_config_preferred_engine_set("opengl_x11");
792                 _DBG("elm_config_preferred_engine_set : opengl_x11");
793 #endif
794         } else if(strcmp(hwacc, "NOT_USE") == 0) {
795 #ifdef WAYLAND
796                 elm_config_preferred_engine_set("wayland_shm");
797                 _DBG("elm_config_preferred_engine_set : wayland_shm");
798 #else
799                 elm_config_preferred_engine_set("software_x11");
800                 _DBG("elm_config_preferred_engine_set : software_x11");
801 #endif
802         } else {
803                 _DBG("elm_config_preferred_engine_set is not called");
804         }
805
806         r = appcore_init(ui->name, &efl_ops, *argc, *argv);
807         _retv_if(r == -1, -1);
808
809         LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:appcore_init:done]", ui->name);
810         if (ui->ops && ui->ops->create) {
811                 r = ui->ops->create(ui->ops->data);
812                 if (r < 0) {
813                         _ERR("create() return error");
814                         appcore_exit();
815                         if (ui->ops && ui->ops->terminate)
816                                 ui->ops->terminate(ui->ops->data);
817                         errno = ECANCELED;
818                         return -1;
819                 }
820                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]",
821                     ui->name);
822         }
823         ui->state = AS_CREATED;
824
825         __add_climsg_cb(ui);
826
827         return 0;
828 }
829
830 static void __after_loop(struct ui_priv *ui)
831 {
832         appcore_unset_rotation_cb();
833         appcore_exit();
834
835         if (ui->state == AS_RUNNING) {
836                 _DBG("[APP %d] PAUSE before termination", _pid);
837                 if (ui->ops && ui->ops->pause)
838                         ui->ops->pause(ui->ops->data);
839         }
840
841         if (ui->ops && ui->ops->terminate)
842                 ui->ops->terminate(ui->ops->data);
843
844         ui->state = AS_DYING;
845
846         if (ui->hshow)
847                 ecore_event_handler_del(ui->hshow);
848         if (ui->hhide)
849                 ecore_event_handler_del(ui->hhide);
850         if (ui->hvchange)
851                 ecore_event_handler_del(ui->hvchange);
852
853         __appcore_timer_del(ui);
854
855         elm_shutdown();
856 }
857
858 static int __set_data(struct ui_priv *ui, const char *name,
859                     struct appcore_ops *ops)
860 {
861         if (ui->name) {
862                 _ERR("Mainloop already started");
863                 errno = EINPROGRESS;
864                 return -1;
865         }
866
867         if (name == NULL || name[0] == '\0') {
868                 _ERR("Invalid name");
869                 errno = EINVAL;
870                 return -1;
871         }
872
873         if (ops == NULL) {
874                 _ERR("ops is NULL");
875                 errno = EINVAL;
876                 return -1;
877         }
878
879         ui->name = strdup(name);
880         _retv_if(ui->name == NULL, -1);
881
882         ui->ops = ops;
883
884         ui->mfcb = __appcore_efl_memory_flush_cb;
885
886         _pid = getpid();
887
888         /* WM_ROTATE */
889         ui->wm_rot_supported = 0;
890         ui->rot_started = 0;
891         ui->rot_cb = NULL;
892         ui->rot_cb_data = NULL;
893         ui->rot_mode = APPCORE_RM_UNKNOWN;
894
895         return 0;
896 }
897
898 static void __unset_data(struct ui_priv *ui)
899 {
900         if (ui->name)
901                 free((void *)ui->name);
902
903         memset(ui, 0, sizeof(struct ui_priv));
904 }
905
906 /* WM_ROTATE */
907 static int __wm_set_rotation_cb(int (*cb) (void *event_info, enum appcore_rm, void *), void *data)
908 {
909         if (cb == NULL) {
910                 errno = EINVAL;
911                 return -1;
912         }
913
914         if ((priv.wm_rot_supported) && (0 == priv.rot_started)) {
915                 __set_wm_rotation_support(0, 1);
916         }
917
918         priv.rot_cb = cb;
919         priv.rot_cb_data = data;
920         priv.rot_started = 1;
921
922         return 0;
923 }
924
925 static int __wm_unset_rotation_cb(void)
926 {
927         if ((priv.wm_rot_supported) && (1 == priv.rot_started)) {
928                 __set_wm_rotation_support(0, 0);
929         }
930
931         priv.rot_cb = NULL;
932         priv.rot_cb_data = NULL;
933         priv.rot_started = 0;
934
935         return 0;
936 }
937
938 static int __wm_get_rotation_state(enum appcore_rm *curr)
939 {
940         if (curr == NULL) {
941                 errno = EINVAL;
942                 return -1;
943         }
944
945         *curr = priv.rot_mode;
946
947         return 0;
948 }
949
950 static int __wm_pause_rotation_cb(void)
951 {
952         if ((1 == priv.rot_started) && (priv.wm_rot_supported)) {
953                 __set_wm_rotation_support(0, 0);
954         }
955
956         priv.rot_started = 0;
957
958         return 0;
959 }
960
961 static int __wm_resume_rotation_cb(void)
962 {
963         if ((0 == priv.rot_started) && (priv.wm_rot_supported)) {
964                 __set_wm_rotation_support(0, 1);
965         }
966
967         priv.rot_started = 1;
968
969         return 0;
970 }
971
972 static struct ui_wm_rotate wm_rotate = {
973         __wm_set_rotation_cb,
974         __wm_unset_rotation_cb,
975         __wm_get_rotation_state,
976         __wm_pause_rotation_cb,
977         __wm_resume_rotation_cb
978 };
979
980 EXPORT_API int appcore_efl_init(const char *name, int *argc, char ***argv,
981                      struct appcore_ops *ops)
982 {
983         int r;
984
985         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", name);
986
987         r = __set_data(&priv, name, ops);
988         _retv_if(r == -1, -1);
989
990         r = __before_loop(&priv, argc, argv);
991         if (r == -1) {
992                 __unset_data(&priv);
993                 return -1;
994         }
995
996         return 0;
997 }
998
999 EXPORT_API void appcore_efl_fini(void)
1000 {
1001         aul_status_update(STATUS_DYING);
1002
1003         __after_loop(&priv);
1004
1005         __unset_data(&priv);
1006 }
1007
1008 EXPORT_API int appcore_efl_main(const char *name, int *argc, char ***argv,
1009                                 struct appcore_ops *ops)
1010 {
1011         int r;
1012
1013         r = appcore_efl_init(name, argc, argv, ops);
1014         _retv_if(r == -1, -1);
1015
1016         elm_run();
1017
1018         appcore_efl_fini();
1019
1020         return 0;
1021 }
1022
1023 EXPORT_API int appcore_set_system_resource_reclaiming(bool enable)
1024 {
1025         resource_reclaiming = enable;
1026
1027         return 0;
1028 }
1029
1030 EXPORT_API int appcore_set_app_state(int state)
1031 {
1032         priv.state = state;
1033
1034         tmp_val = 1;
1035
1036         return 0;
1037 }
1038
1039 EXPORT_API unsigned int appcore_get_main_window()
1040 {
1041         struct win_node *entry = NULL;
1042
1043         if (g_winnode_list != NULL) {
1044                 entry = g_winnode_list->data;
1045                 return (unsigned int) entry->win;
1046         }
1047         return 0;
1048 }
1049 #ifdef WAYLAND
1050 EXPORT_API unsigned int appcore_get_main_surface()
1051 {
1052         struct win_node *entry = NULL;
1053
1054         if (g_winnode_list != NULL) {
1055                 entry = g_winnode_list->data;
1056                 return (unsigned int) entry->surf;
1057         }
1058         return 0;
1059 }
1060 #endif