merged with private
[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                         if(r >= 0)
191                                 __appcore_timer_add(ui);
192                 }
193                 /* TODO : rotation stop */
194                 r = appcore_pause_rotation_cb();
195
196                 sysman_inform_backgrd();
197                 break;
198         case AE_RESUME:
199                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:start]",
200                     ui->name);
201                 if (ui->state == AS_PAUSED) {
202                         _DBG("[APP %d] RESUME", _pid);
203                         if (ui->ops->resume)
204                                 r = ui->ops->resume(ui->ops->data);
205                         ui->state = AS_RUNNING;
206                 }
207                 /*TODO : rotation start*/
208                 r = appcore_resume_rotation_cb();
209                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:done]",
210                     ui->name);
211                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:Launching:done]",
212                     ui->name);
213                 sysman_inform_foregrd();
214
215                 break;
216         default:
217                 /* do nothing */
218                 break;
219         }
220 }
221
222 static struct ui_ops efl_ops = {
223         .data = &priv,
224         .cb_app = __do_app,
225 };
226
227
228 static bool __check_visible(void)
229 {
230         GSList *iter = NULL;
231         struct win_node *entry = NULL;
232
233         _DBG("[EVENT_TEST][EVENT] __check_visible\n");
234         
235         for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
236                 entry = iter->data;     
237                 _DBG("win : %x obscured : %d\n", entry->win, entry->bfobscured);
238                 if(entry->bfobscured == FALSE)
239                         return TRUE;            
240         }
241         return FALSE;
242 }
243
244 static bool __exist_win(unsigned int win)
245 {
246         struct win_node temp;
247         GSList *f;
248
249         temp.win = win;
250
251         f = g_slist_find_custom(g_winnode_list, &temp, WIN_COMP);
252         if (f == NULL) {
253                 return FALSE;
254         } else {
255                 return TRUE;
256         }
257
258 }
259
260 static bool __add_win(unsigned int win)
261 {
262         struct win_node *t;
263         GSList *f;
264
265         t = calloc(1, sizeof(struct win_node));
266         if (t == NULL)
267                 return FALSE;
268
269         t->win = win;
270         t->bfobscured = FALSE;
271
272         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
273
274         f = g_slist_find_custom(g_winnode_list, t, WIN_COMP);
275
276         if (f) {
277                 errno = ENOENT;
278                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
279                 free(t);
280                 return 0;
281         }
282
283         g_winnode_list = g_slist_append(g_winnode_list, t);
284
285         return TRUE;
286
287 }
288
289 static bool __delete_win(unsigned int win)
290 {
291         struct win_node temp;
292         GSList *f;
293
294         temp.win = win;
295
296         f = g_slist_find_custom(g_winnode_list, &temp, WIN_COMP);
297         if (f == NULL) {
298                 errno = ENOENT;
299                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
300                      win);
301                 return 0;
302         }
303
304         g_winnode_list = g_slist_remove_link(g_winnode_list, f);
305
306         free(f->data);
307 }
308
309 static bool __update_win(unsigned int win, bool bfobscured)
310 {
311         struct win_node temp;
312         GSList *f;
313
314         struct win_node *t;
315
316         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
317              bfobscured);
318
319         temp.win = win;
320
321         f = g_slist_find_custom(g_winnode_list, &temp, WIN_COMP);
322
323         if (f == NULL) {
324                 errno = ENOENT;
325                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
326                 return FALSE;
327         }
328
329         g_winnode_list = g_slist_remove_link(g_winnode_list, f);
330
331         free(f->data);
332
333         t = calloc(1, sizeof(struct win_node));
334         if (t == NULL)
335                 return FALSE;
336
337         t->win = win;
338         t->bfobscured = bfobscured;
339
340         g_winnode_list = g_slist_append(g_winnode_list, t);
341         
342         return TRUE;
343
344 }
345
346 static Eina_Bool __show_cb(void *data, int type, void *event)
347 {
348         Ecore_X_Event_Window_Show *ev;
349
350         ev = event;
351
352         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x\n", ev->win);
353
354         if (!__exist_win((unsigned int)ev->win))
355                 __add_win((unsigned int)ev->win);
356         else
357                 __update_win((unsigned int)ev->win, FALSE);
358
359         return ECORE_CALLBACK_RENEW;
360 }
361
362 static Eina_Bool __hide_cb(void *data, int type, void *event)
363 {
364         Ecore_X_Event_Window_Hide *ev;
365         int bvisibility = 0;
366
367         ev = event;
368
369         _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
370
371         if (__exist_win((unsigned int)ev->win)) {
372                 __delete_win((unsigned int)ev->win);
373                 
374                 bvisibility = __check_visible();
375                 if (!bvisibility && b_active == 1) {
376                         _DBG(" Go to Pasue state \n");
377                         b_active = 0;
378                         __do_app(AE_PAUSE, data, NULL);
379                 }
380         }
381
382         return ECORE_CALLBACK_RENEW;
383 }
384
385 static Eina_Bool __visibility_cb(void *data, int type, void *event)
386 {
387         Ecore_X_Event_Window_Visibility_Change *ev;
388         int bvisibility = 0;
389
390         ev = event;
391
392         __update_win((unsigned int)ev->win, ev->fully_obscured);
393         bvisibility = __check_visible();
394
395         if (bvisibility && b_active == 0) {
396                 _DBG(" Go to Resume state\n");
397                 b_active = 1;
398                 __do_app(AE_RESUME, data, NULL);
399
400         } else if (!bvisibility && b_active == 1) {
401                 _DBG(" Go to Pasue state \n");
402                 b_active = 0;
403                 __do_app(AE_PAUSE, data, NULL);
404         } else
405                 _DBG(" No change state \n");
406
407         return ECORE_CALLBACK_RENEW;
408
409 }
410
411 static void __add_climsg_cb(struct ui_priv *ui)
412 {
413         _ret_if(ui == NULL);
414
415         ui->hshow =
416             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHOW, __show_cb, ui);
417         ui->hhide =
418             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_HIDE, __hide_cb, ui);
419         ui->hvchange =
420             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE,
421                                     __visibility_cb, ui);
422
423 }
424
425 static int __before_loop(struct ui_priv *ui, int *argc, char ***argv)
426 {
427         int r;
428
429         if (argc == NULL || argv == NULL) {
430                 _ERR("argc/argv is NULL");
431                 errno = EINVAL;
432                 return -1;
433         }
434
435         g_type_init();
436         elm_init(*argc, *argv);
437
438         r = appcore_init(ui->name, &efl_ops, *argc, *argv);
439         _retv_if(r == -1, -1);
440
441         LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:appcore_init:done]", ui->name);
442         if (ui->ops && ui->ops->create) {
443                 r = ui->ops->create(ui->ops->data);
444                 if (r == -1) {
445                         _ERR("create() return error");
446                         appcore_exit();
447                         errno = ECANCELED;
448                         return -1;
449                 }
450                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]",
451                     ui->name);
452         }
453         ui->state = AS_CREATED;
454
455         __add_climsg_cb(ui);
456
457         return 0;
458 }
459
460 static void __after_loop(struct ui_priv *ui)
461 {
462         appcore_unset_rotation_cb();
463         appcore_exit();
464
465         if (ui->ops && ui->ops->terminate)
466                 ui->ops->terminate(ui->ops->data);
467
468         if (ui->hshow)
469                 ecore_event_handler_del(ui->hshow);
470         if (ui->hhide)
471                 ecore_event_handler_del(ui->hhide);
472         if (ui->hvchange)
473                 ecore_event_handler_del(ui->hvchange);
474
475         __appcore_timer_del(ui);
476
477         elm_shutdown();
478 }
479
480 static int __set_data(struct ui_priv *ui, const char *name,
481                     struct appcore_ops *ops)
482 {
483         if (ui->name) {
484                 _ERR("Mainloop already started");
485                 errno = EINPROGRESS;
486                 return -1;
487         }
488
489         if (name == NULL || name[0] == '\0') {
490                 _ERR("Invalid name");
491                 errno = EINVAL;
492                 return -1;
493         }
494
495         if (ops == NULL) {
496                 _ERR("ops is NULL");
497                 errno = EINVAL;
498                 return -1;
499         }
500
501         ui->name = strdup(name);
502         _retv_if(ui->name == NULL, -1);
503
504         ui->ops = ops;
505
506         ui->mfcb = __appcore_efl_memory_flush_cb;
507
508         _pid = getpid();
509
510         return 0;
511 }
512
513 static void __unset_data(struct ui_priv *ui)
514 {
515         if (ui->name)
516                 free((void *)ui->name);
517
518         memset(ui, 0, sizeof(struct ui_priv));
519 }
520
521 EXPORT_API int appcore_efl_main(const char *name, int *argc, char ***argv,
522                                 struct appcore_ops *ops)
523 {
524         int r;
525
526         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", name);
527
528         r = __set_data(&priv, name, ops);
529         _retv_if(r == -1, -1);
530
531         r = __before_loop(&priv, argc, argv);
532         if (r == -1) {
533                 __unset_data(&priv);
534                 return -1;
535         }
536
537         elm_run();
538
539         __after_loop(&priv);
540
541         __unset_data(&priv);
542
543         return 0;
544 }