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