12bc7880bd2ac32e4dfda4c0e4051b92976af742
[framework/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
23 #include <errno.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <X11/Xatom.h>
27 #include <X11/Xlib.h>
28 #include <Ecore_X.h>
29 #include <Elementary.h>
30 #include <glib-object.h>
31 #include <malloc.h>
32 #include <sysman.h>
33 #include <glib.h>
34 #include <stdbool.h>
35 #include "appcore-internal.h"
36 #include "appcore-efl.h"
37
38 static pid_t _pid;
39
40 struct ui_priv {
41         const char *name;
42         enum app_state state;
43
44         Ecore_Event_Handler *hshow;
45         Ecore_Event_Handler *hhide;
46         Ecore_Event_Handler *hvchange;
47
48         Ecore_Timer *mftimer;   /* Ecore Timer for memory flushing */
49
50         struct appcore_ops *ops;
51         void (*mfcb) (void);    /* Memory Flushing Callback */
52 };
53
54 static struct ui_priv priv;
55
56 static const char *_ae_name[AE_MAX] = {
57         [AE_UNKNOWN] = "UNKNOWN",
58         [AE_CREATE] = "CREATE",
59         [AE_TERMINATE] = "TERMINATE",
60         [AE_PAUSE] = "PAUSE",
61         [AE_RESUME] = "RESUME",
62         [AE_RESET] = "RESET",
63         [AE_LOWMEM_POST] = "LOWMEM_POST",
64         [AE_MEM_FLUSH] = "MEM_FLUSH",
65 };
66
67 static const char *_as_name[] = {
68         [AS_NONE] = "NONE",
69         [AS_CREATED] = "CREATED",
70         [AS_RUNNING] = "RUNNING",
71         [AS_PAUSED] = "PAUSED",
72         [AS_DYING] = "DYING",
73 };
74
75 static bool b_active = 1;
76 struct win_node {
77         unsigned int win;
78         bool bfobscured;
79 };
80
81 static int WIN_COMP(gconstpointer data1, gconstpointer data2)
82 {
83         struct win_node *a = (struct win_node *)data1;
84         struct win_node *b = (struct win_node *)data2;
85         return (int)((a->win)-(b->win));
86 }
87
88 GSList *g_winnode_list;
89
90 #if defined(MEMORY_FLUSH_ACTIVATE)
91 static Eina_Bool __appcore_memory_flush_cb(void *data)
92 {
93         struct ui_priv *ui = (struct ui_priv *)data;
94
95         appcore_flush_memory();
96         ui->mftimer = NULL;
97
98         return ECORE_CALLBACK_CANCEL;
99 }
100
101 static int __appcore_low_memory_post_cb(struct ui_priv *ui)
102 {
103         if (ui->state == AS_PAUSED) {
104                 appcore_flush_memory();
105         } else {
106                 malloc_trim(0);
107         }
108
109         return 0;
110 }
111
112 static void __appcore_timer_add(struct ui_priv *ui)
113 {
114         ui->mftimer = ecore_timer_add(5, __appcore_memory_flush_cb, ui);
115 }
116
117 static void __appcore_timer_del(struct ui_priv *ui)
118 {
119         if (ui->mftimer) {
120                 ecore_timer_del(ui->mftimer);
121                 ui->mftimer = NULL;
122         }
123 }
124
125 #else
126
127 static int __appcore_low_memory_post_cb(ui_priv *ui)
128 {
129         return -1;
130 }
131
132 #define __appcore_timer_add(ui) 0
133 #define __appcore_timer_del(ui) 0
134
135 #endif
136
137 static void __appcore_efl_memory_flush_cb(void)
138 {
139         _DBG("[APP %d]   __appcore_efl_memory_flush_cb()", _pid);
140         elm_cache_all_flush();
141 }
142
143 static void __do_app(enum app_event event, void *data, bundle * b)
144 {
145         int r = -1;
146         struct ui_priv *ui = data;
147
148         _DBG("[APP %d] Event: %d", _pid, event);
149         _ret_if(ui == NULL || event >= AE_MAX);
150         _DBG("[APP %d] Event: %s State: %s", _pid, _ae_name[event],
151              _as_name[ui->state]);
152
153         if (event == AE_MEM_FLUSH) {
154                 ui->mfcb();
155                 return;
156         }
157
158         if (event == AE_LOWMEM_POST) {
159                 if (__appcore_low_memory_post_cb(ui) == 0)
160                         return;
161         }
162
163         if (!(ui->state == AS_PAUSED && event == AE_PAUSE))
164                 __appcore_timer_del(ui);
165
166         if (event == AE_TERMINATE) {
167                 _DBG("[APP %d] TERMINATE", _pid);
168                 ui->state = AS_DYING;
169                 elm_exit();
170                 return;
171         }
172
173         _ret_if(ui->ops == NULL);
174
175         switch (event) {
176         case AE_RESET:
177                 _DBG("[APP %d] RESET", _pid);
178                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]",
179                     ui->name);
180                 if (ui->ops->reset)
181                         r = ui->ops->reset(b, ui->ops->data);
182                 ui->state = AS_RUNNING;
183                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]",
184                     ui->name);
185                 break;
186         case AE_PAUSE:
187                 if (ui->state == AS_RUNNING) {
188                         _DBG("[APP %d] PAUSE", _pid);
189                         if (ui->ops->pause)
190                                 r = ui->ops->pause(ui->ops->data);
191                         ui->state = AS_PAUSED;
192                         if(r >= 0)
193                                 __appcore_timer_add(ui);
194                 }
195                 /* TODO : rotation stop */
196                 r = appcore_pause_rotation_cb();
197
198                 sysman_inform_backgrd();
199                 break;
200         case AE_RESUME:
201                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:start]",
202                     ui->name);
203                 if (ui->state == AS_PAUSED) {
204                         _DBG("[APP %d] RESUME", _pid);
205                         if (ui->ops->resume)
206                                 r = ui->ops->resume(ui->ops->data);
207                         ui->state = AS_RUNNING;
208                 }
209                 /*TODO : rotation start*/
210                 r = appcore_resume_rotation_cb();
211                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:done]",
212                     ui->name);
213                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:Launching:done]",
214                     ui->name);
215                 sysman_inform_foregrd();
216
217                 break;
218         default:
219                 /* do nothing */
220                 break;
221         }
222 }
223
224 static struct ui_ops efl_ops = {
225         .data = &priv,
226         .cb_app = __do_app,
227 };
228
229
230 static bool __check_visible(void)
231 {
232         GSList *iter = NULL;
233         struct win_node *entry = NULL;
234
235         _DBG("[EVENT_TEST][EVENT] __check_visible\n");
236         
237         for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
238                 entry = iter->data;     
239                 _DBG("win : %x obscured : %d\n", entry->win, entry->bfobscured);
240                 if(entry->bfobscured == FALSE)
241                         return TRUE;            
242         }
243         return FALSE;
244 }
245
246 static bool __exist_win(unsigned int win)
247 {
248         struct win_node temp;
249         GSList *f;
250
251         temp.win = win;
252
253         f = g_slist_find_custom(g_winnode_list, &temp, WIN_COMP);
254         if (f == NULL) {
255                 return FALSE;
256         } else {
257                 return TRUE;
258         }
259
260 }
261
262 static bool __add_win(unsigned int win)
263 {
264         struct win_node *t;
265         GSList *f;
266
267         t = calloc(1, sizeof(struct win_node));
268         if (t == NULL)
269                 return FALSE;
270
271         t->win = win;
272         t->bfobscured = FALSE;
273
274         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
275
276         f = g_slist_find_custom(g_winnode_list, t, WIN_COMP);
277
278         if (f) {
279                 errno = ENOENT;
280                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
281                 free(t);
282                 return 0;
283         }
284
285         g_winnode_list = g_slist_append(g_winnode_list, t);
286
287         return TRUE;
288
289 }
290
291 static bool __delete_win(unsigned int win)
292 {
293         struct win_node temp;
294         GSList *f;
295
296         temp.win = win;
297
298         f = g_slist_find_custom(g_winnode_list, &temp, WIN_COMP);
299         if (f == NULL) {
300                 errno = ENOENT;
301                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
302                      win);
303                 return 0;
304         }
305
306         g_winnode_list = g_slist_remove_link(g_winnode_list, f);
307
308         free(f->data);
309
310         return TRUE;
311 }
312
313 static bool __update_win(unsigned int win, bool bfobscured)
314 {
315         struct win_node temp;
316         GSList *f;
317
318         struct win_node *t;
319
320         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
321              bfobscured);
322
323         temp.win = win;
324
325         f = g_slist_find_custom(g_winnode_list, &temp, WIN_COMP);
326
327         if (f == NULL) {
328                 errno = ENOENT;
329                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
330                 return FALSE;
331         }
332
333         g_winnode_list = g_slist_remove_link(g_winnode_list, f);
334
335         free(f->data);
336
337         t = calloc(1, sizeof(struct win_node));
338         if (t == NULL)
339                 return FALSE;
340
341         t->win = win;
342         t->bfobscured = bfobscured;
343
344         g_winnode_list = g_slist_append(g_winnode_list, t);
345         
346         return TRUE;
347
348 }
349
350 static Eina_Bool __show_cb(void *data, int type, void *event)
351 {
352         Ecore_X_Event_Window_Show *ev;
353
354         ev = event;
355
356         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x\n", ev->win);
357
358         if (!__exist_win((unsigned int)ev->win))
359                 __add_win((unsigned int)ev->win);
360         else
361                 __update_win((unsigned int)ev->win, FALSE);
362
363         return ECORE_CALLBACK_RENEW;
364 }
365
366 static Eina_Bool __hide_cb(void *data, int type, void *event)
367 {
368         Ecore_X_Event_Window_Hide *ev;
369         int bvisibility = 0;
370
371         ev = event;
372
373         _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
374
375         if (__exist_win((unsigned int)ev->win)) {
376                 __delete_win((unsigned int)ev->win);
377                 
378                 bvisibility = __check_visible();
379                 if (!bvisibility && b_active == 1) {
380                         _DBG(" Go to Pasue state \n");
381                         b_active = 0;
382                         __do_app(AE_PAUSE, data, NULL);
383                 }
384         }
385
386         return ECORE_CALLBACK_RENEW;
387 }
388
389 static Eina_Bool __visibility_cb(void *data, int type, void *event)
390 {
391         Ecore_X_Event_Window_Visibility_Change *ev;
392         int bvisibility = 0;
393
394         ev = event;
395
396         __update_win((unsigned int)ev->win, ev->fully_obscured);
397         bvisibility = __check_visible();
398
399         if (bvisibility && b_active == 0) {
400                 _DBG(" Go to Resume state\n");
401                 b_active = 1;
402                 __do_app(AE_RESUME, data, NULL);
403
404         } else if (!bvisibility && b_active == 1) {
405                 _DBG(" Go to Pasue state \n");
406                 b_active = 0;
407                 __do_app(AE_PAUSE, data, NULL);
408         } else
409                 _DBG(" No change state \n");
410
411         return ECORE_CALLBACK_RENEW;
412
413 }
414
415 static void __add_climsg_cb(struct ui_priv *ui)
416 {
417         _ret_if(ui == NULL);
418
419         ui->hshow =
420             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHOW, __show_cb, ui);
421         ui->hhide =
422             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_HIDE, __hide_cb, ui);
423         ui->hvchange =
424             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE,
425                                     __visibility_cb, ui);
426
427 }
428
429 static int __before_loop(struct ui_priv *ui, int *argc, char ***argv)
430 {
431         int r;
432
433         if (argc == NULL || argv == NULL) {
434                 _ERR("argc/argv is NULL");
435                 errno = EINVAL;
436                 return -1;
437         }
438
439         g_type_init();
440         elm_init(*argc, *argv);
441
442         r = appcore_init(ui->name, &efl_ops, *argc, *argv);
443         _retv_if(r == -1, -1);
444
445         LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:appcore_init:done]", ui->name);
446         if (ui->ops && ui->ops->create) {
447                 r = ui->ops->create(ui->ops->data);
448                 if (r == -1) {
449                         _ERR("create() return error");
450                         appcore_exit();
451                         errno = ECANCELED;
452                         return -1;
453                 }
454                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]",
455                     ui->name);
456         }
457         ui->state = AS_CREATED;
458
459         __add_climsg_cb(ui);
460
461         return 0;
462 }
463
464 static void __after_loop(struct ui_priv *ui)
465 {
466         appcore_unset_rotation_cb();
467         appcore_exit();
468
469         if (ui->ops && ui->ops->terminate)
470                 ui->ops->terminate(ui->ops->data);
471
472         if (ui->hshow)
473                 ecore_event_handler_del(ui->hshow);
474         if (ui->hhide)
475                 ecore_event_handler_del(ui->hhide);
476         if (ui->hvchange)
477                 ecore_event_handler_del(ui->hvchange);
478
479         __appcore_timer_del(ui);
480
481         elm_shutdown();
482 }
483
484 static int __set_data(struct ui_priv *ui, const char *name,
485                     struct appcore_ops *ops)
486 {
487         if (ui->name) {
488                 _ERR("Mainloop already started");
489                 errno = EINPROGRESS;
490                 return -1;
491         }
492
493         if (name == NULL || name[0] == '\0') {
494                 _ERR("Invalid name");
495                 errno = EINVAL;
496                 return -1;
497         }
498
499         if (ops == NULL) {
500                 _ERR("ops is NULL");
501                 errno = EINVAL;
502                 return -1;
503         }
504
505         ui->name = strdup(name);
506         _retv_if(ui->name == NULL, -1);
507
508         ui->ops = ops;
509
510         ui->mfcb = __appcore_efl_memory_flush_cb;
511
512         _pid = getpid();
513
514         return 0;
515 }
516
517 static void __unset_data(struct ui_priv *ui)
518 {
519         if (ui->name)
520                 free((void *)ui->name);
521
522         memset(ui, 0, sizeof(struct ui_priv));
523 }
524
525 EXPORT_API int appcore_efl_main(const char *name, int *argc, char ***argv,
526                                 struct appcore_ops *ops)
527 {
528         int r;
529
530         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", name);
531
532         r = __set_data(&priv, name, ops);
533         _retv_if(r == -1, -1);
534
535         r = __before_loop(&priv, argc, argv);
536         if (r == -1) {
537                 __unset_data(&priv);
538                 return -1;
539         }
540
541         elm_run();
542
543         __after_loop(&priv);
544
545         __unset_data(&priv);
546
547         return 0;
548 }