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