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