Initialize Tizen 2.3
[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 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <sys/un.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <stdarg.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <X11/Xatom.h>
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34 #include <X11/extensions/Xcomposite.h>
35 #include <X11/extensions/XShm.h>
36 #include <sys/shm.h>
37
38 #include <Ecore_X.h>
39 #include <Ecore.h>
40 #include <Ecore_Evas.h>
41 #include <Ecore_Input_Evas.h>
42 #include <Elementary.h>
43 #include <glib-object.h>
44 #include <malloc.h>
45 #include <glib.h>
46 #include <stdbool.h>
47 #include <aul.h>
48 #ifdef WEARABLE_PROFILE
49 #include <proc_stat.h>
50 #endif
51 #include "appcore-internal.h"
52 #include "appcore-efl.h"
53 #include "virtual_canvas.h"
54
55 #define SYSMAN_MAXSTR 100
56 #define SYSMAN_MAXARG 16
57 #define SYSNOTI_SOCKET_PATH "/tmp/sn"
58 #define RETRY_READ_COUNT        10
59
60 #define PREDEF_BACKGRD                          "backgrd"
61 #define PREDEF_FOREGRD                          "foregrd"
62
63 enum sysnoti_cmd {
64         ADD_SYSMAN_ACTION,
65         CALL_SYSMAN_ACTION
66 };
67
68 struct sysnoti {
69         int pid;
70         int cmd;
71         char *type;
72         char *path;
73         int argc;
74         char *argv[SYSMAN_MAXARG];
75 };
76
77 static pid_t _pid;
78
79 static bool resource_reclaiming = TRUE;
80 static int tmp_val = 0;
81
82
83 struct ui_priv {
84         const char *name;
85         enum app_state state;
86
87         Ecore_Event_Handler *hshow;
88         Ecore_Event_Handler *hhide;
89         Ecore_Event_Handler *hvchange;
90         Ecore_Event_Handler *hcmsg; /* WM_ROTATE */
91
92         Ecore_Timer *mftimer;   /* Ecore Timer for memory flushing */
93
94         struct appcore_ops *ops;
95         void (*mfcb) (void);    /* Memory Flushing Callback */
96
97         /* WM_ROTATE */
98         int wm_rot_supported;
99         int rot_started;
100         int (*rot_cb) (enum appcore_rm, void *);
101         void *rot_cb_data;
102         enum appcore_rm rot_mode;
103 };
104
105 static struct ui_priv priv;
106
107 static const char *_ae_name[AE_MAX] = {
108         [AE_UNKNOWN] = "UNKNOWN",
109         [AE_CREATE] = "CREATE",
110         [AE_TERMINATE] = "TERMINATE",
111         [AE_PAUSE] = "PAUSE",
112         [AE_RESUME] = "RESUME",
113         [AE_RESET] = "RESET",
114         [AE_LOWMEM_POST] = "LOWMEM_POST",
115         [AE_MEM_FLUSH] = "MEM_FLUSH",
116 };
117
118 static const char *_as_name[] = {
119         [AS_NONE] = "NONE",
120         [AS_CREATED] = "CREATED",
121         [AS_RUNNING] = "RUNNING",
122         [AS_PAUSED] = "PAUSED",
123         [AS_DYING] = "DYING",
124 };
125
126 static bool b_active = 0;
127 struct win_node {
128         unsigned int win;
129         bool bfobscured;
130 };
131
132 static struct ui_wm_rotate wm_rotate;
133
134 static inline int send_int(int fd, int val)
135 {
136         return write(fd, &val, sizeof(int));
137 }
138
139 static inline int send_str(int fd, char *str)
140 {
141         int len;
142         int ret;
143         if (str == NULL) {
144                 len = 0;
145                 ret = write(fd, &len, sizeof(int));
146         } else {
147                 len = strlen(str);
148                 if (len > SYSMAN_MAXSTR)
149                         len = SYSMAN_MAXSTR;
150                 write(fd, &len, sizeof(int));
151                 ret = write(fd, str, len);
152         }
153         return ret;
154 }
155
156 static int sysnoti_send(struct sysnoti *msg)
157 {
158         int client_len;
159         int client_sockfd;
160         int result;
161         int r;
162         int retry_count = 0;
163         struct sockaddr_un clientaddr;
164         int i;
165
166         client_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
167         if (client_sockfd == -1) {
168                 _ERR("%s: socket create failed\n", __FUNCTION__);
169                 return -1;
170         }
171         bzero(&clientaddr, sizeof(clientaddr));
172         clientaddr.sun_family = AF_UNIX;
173         strncpy(clientaddr.sun_path, SYSNOTI_SOCKET_PATH, sizeof(clientaddr.sun_path) - 1);
174         client_len = sizeof(clientaddr);
175
176         if (connect(client_sockfd, (struct sockaddr *)&clientaddr, client_len) <
177             0) {
178                 _ERR("%s: connect failed\n", __FUNCTION__);
179                 close(client_sockfd);
180                 return -1;
181         }
182
183         send_int(client_sockfd, msg->pid);
184         send_int(client_sockfd, msg->cmd);
185         send_str(client_sockfd, msg->type);
186         send_str(client_sockfd, msg->path);
187         send_int(client_sockfd, msg->argc);
188         for (i = 0; i < msg->argc; i++)
189                 send_str(client_sockfd, msg->argv[i]);
190
191         while (retry_count < RETRY_READ_COUNT) {
192                 r = read(client_sockfd, &result, sizeof(int));
193                 if (r < 0) {
194                         if (errno == EINTR) {
195                                 _ERR("Re-read for error(EINTR)");
196                                 retry_count++;
197                                 continue;
198                         }
199                         _ERR("Read fail for str length");
200                         result = -1;
201                         break;
202
203                 }
204                 break;
205         }
206         if (retry_count == RETRY_READ_COUNT) {
207                 _ERR("Read retry failed");
208         }
209
210         close(client_sockfd);
211         return result;
212 }
213
214 static int _call_predef_action(const char *type, int num, ...)
215 {
216         struct sysnoti *msg;
217         int ret;
218         va_list argptr;
219
220         int i;
221         char *args = NULL;
222
223         if (type == NULL || num > SYSMAN_MAXARG) {
224                 errno = EINVAL;
225                 return -1;
226         }
227
228         msg = malloc(sizeof(struct sysnoti));
229
230         if (msg == NULL) {
231                 /* Do something for not enought memory error */
232                 return -1;
233         }
234
235         msg->pid = getpid();
236         msg->cmd = CALL_SYSMAN_ACTION;
237         msg->type = (char *)type;
238         msg->path = NULL;
239
240         msg->argc = num;
241         va_start(argptr, num);
242         for (i = 0; i < num; i++) {
243                 args = va_arg(argptr, char *);
244                 msg->argv[i] = args;
245         }
246         va_end(argptr);
247
248         ret = sysnoti_send(msg);
249         free(msg);
250
251         return ret;
252 }
253
254 static int _inform_foregrd(void)
255 {
256         char buf[255];
257         snprintf(buf, sizeof(buf), "%d", getpid());
258         return _call_predef_action(PREDEF_FOREGRD, 1, buf);
259 }
260
261 static int _inform_backgrd(void)
262 {
263         char buf[255];
264         snprintf(buf, sizeof(buf), "%d", getpid());
265         return _call_predef_action(PREDEF_BACKGRD, 1, buf);
266 }
267
268
269
270 char appid[APPID_MAX];
271 bool taskmanage;
272
273 static void _capture_and_make_file(Ecore_X_Window win, int pid, const char *package);
274
275 static int WIN_COMP(gconstpointer data1, gconstpointer data2)
276 {
277         struct win_node *a = (struct win_node *)data1;
278         struct win_node *b = (struct win_node *)data2;
279         return (int)((a->win)-(b->win));
280 }
281
282 GSList *g_winnode_list = NULL;
283
284 #if defined(MEMORY_FLUSH_ACTIVATE)
285 static Eina_Bool __appcore_memory_flush_cb(void *data)
286 {
287         struct ui_priv *ui = (struct ui_priv *)data;
288
289         appcore_flush_memory();
290         ui->mftimer = NULL;
291
292         return ECORE_CALLBACK_CANCEL;
293 }
294
295 static int __appcore_low_memory_post_cb(struct ui_priv *ui)
296 {
297         if (ui->state == AS_PAUSED) {
298         //      appcore_flush_memory();
299         } else {
300                 malloc_trim(0);
301         }
302
303         return 0;
304 }
305
306 static void __appcore_timer_add(struct ui_priv *ui)
307 {
308         ui->mftimer = ecore_timer_add(5, __appcore_memory_flush_cb, ui);
309 }
310
311 static void __appcore_timer_del(struct ui_priv *ui)
312 {
313         if (ui->mftimer) {
314                 ecore_timer_del(ui->mftimer);
315                 ui->mftimer = NULL;
316         }
317 }
318
319 #else
320
321 static int __appcore_low_memory_post_cb(ui_priv *ui)
322 {
323         return -1;
324 }
325
326 #define __appcore_timer_add(ui) 0
327 #define __appcore_timer_del(ui) 0
328
329 #endif
330
331 static void __appcore_efl_memory_flush_cb(void)
332 {
333         //_DBG("[APP %d]   __appcore_efl_memory_flush_cb()", _pid);
334         elm_cache_all_flush();
335 }
336
337 static void __do_app(enum app_event event, void *data, bundle * b)
338 {
339         int r = -1;
340         struct ui_priv *ui = data;
341
342         _ret_if(ui == NULL || event >= AE_MAX);
343         _DBG("[APP %d] Event: %s State: %s", _pid, _ae_name[event],
344              _as_name[ui->state]);
345
346         if (event == AE_MEM_FLUSH) {
347                 ui->mfcb();
348                 return;
349         }
350
351         if (event == AE_LOWMEM_POST) {
352                 if (__appcore_low_memory_post_cb(ui) == 0)
353                         return;
354         }
355
356         if (!(ui->state == AS_PAUSED && event == AE_PAUSE))
357                 __appcore_timer_del(ui);
358
359         if (event == AE_TERMINATE) {
360                 _DBG("[APP %d] TERMINATE", _pid);
361                 ui->state = AS_DYING;
362                 elm_exit();
363                 return;
364         }
365
366         _ret_if(ui->ops == NULL);
367
368         switch (event) {
369         case AE_RESET:
370                 _DBG("[APP %d] RESET", _pid);
371                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:start]",
372                     ui->name);
373                 if (ui->ops->reset)
374                         r = ui->ops->reset(b, ui->ops->data);
375                 ui->state = AS_RUNNING;
376                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:reset:done]",
377                     ui->name);
378                 break;
379         case AE_PAUSE:
380                 if (ui->state == AS_RUNNING) {
381                         _DBG("[APP %d] PAUSE", _pid);
382                         if (ui->ops->pause)
383                                 r = ui->ops->pause(ui->ops->data);
384                         ui->state = AS_PAUSED;
385                         if(r >= 0 && resource_reclaiming == TRUE)
386                                 __appcore_timer_add(ui);
387                 }
388                 /* TODO : rotation stop */
389                 //r = appcore_pause_rotation_cb();
390 #ifdef WEARABLE_PROFILE
391                 proc_group_change_status(PROC_CGROUP_SET_BACKGRD, getpid(), NULL);
392 #else
393                 _inform_backgrd();
394 #endif
395
396                 break;
397         case AE_RESUME:
398                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:start]",
399                     ui->name);
400                 if (ui->state == AS_PAUSED) {
401                         _DBG("[APP %d] RESUME", _pid);
402                         if (ui->ops->resume)
403                                 r = ui->ops->resume(ui->ops->data);
404                         ui->state = AS_RUNNING;
405                 }
406                 /*TODO : rotation start*/
407                 //r = appcore_resume_rotation_cb();
408                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:resume:done]",
409                     ui->name);
410                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:Launching:done]",
411                     ui->name);
412 #ifdef WEARABLE_PROFILE
413                 proc_group_change_status(PROC_CGROUP_SET_FOREGRD, getpid(), NULL);
414 #else
415                 _inform_foregrd();
416 #endif
417
418                 break;
419         default:
420                 /* do nothing */
421                 break;
422         }
423 }
424
425 static struct ui_ops efl_ops = {
426         .data = &priv,
427         .cb_app = __do_app,
428 };
429
430
431 static bool __check_visible(void)
432 {
433         GSList *iter = NULL;
434         struct win_node *entry = NULL;
435
436         for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
437                 entry = iter->data;     
438                 //_DBG("win : %x obscured : %d\n", entry->win, entry->bfobscured);
439                 if(entry->bfobscured == FALSE)
440                         return TRUE;            
441         }
442         return FALSE;
443 }
444
445 static bool __check_skip(Ecore_X_Window xwin)
446 {
447         unsigned int i, num;
448         Ecore_X_Window_State *state;
449         int ret;
450
451         ret = ecore_x_netwm_window_state_get(xwin, &state, &num);
452         _DBG("ret(%d), win(%x), state(%x), num(%d)", ret, xwin, state, num);
453         if (state) {
454                 for (i = 0; i < num; i++) {
455                         _DBG("state[%d] : %d", i, state[i]);
456                         switch (state[i]) {
457                                 case ECORE_X_WINDOW_STATE_SKIP_TASKBAR:
458                                         free(state);
459                                         return TRUE;
460                                         break;
461                                 case ECORE_X_WINDOW_STATE_SKIP_PAGER:
462                                         free(state);
463                                         return TRUE;
464                                         break;
465                                 default:
466                                         /* Ignore */
467                                         break;
468                         }
469                 }
470         }
471         free(state);
472         return FALSE;
473 }
474
475 static bool __exist_win(unsigned int win)
476 {
477         struct win_node temp;
478         GSList *f;
479
480         temp.win = win;
481
482         f = g_slist_find_custom(g_winnode_list, &temp, WIN_COMP);
483         if (f == NULL) {
484                 return FALSE;
485         } else {
486                 return TRUE;
487         }
488
489 }
490
491 static bool __add_win(unsigned int win)
492 {
493         struct win_node *t;
494         GSList *f;
495
496         t = calloc(1, sizeof(struct win_node));
497         if (t == NULL)
498                 return FALSE;
499
500         t->win = win;
501         t->bfobscured = FALSE;
502
503         _DBG("[EVENT_TEST][EVENT] __add_win WIN:%x\n", win);
504
505         f = g_slist_find_custom(g_winnode_list, t, WIN_COMP);
506
507         if (f) {
508                 errno = ENOENT;
509                 _DBG("[EVENT_TEST][EVENT] ERROR There is already window : %x \n", win);
510                 free(t);
511                 return 0;
512         }
513
514         g_winnode_list = g_slist_append(g_winnode_list, t);
515
516         return TRUE;
517
518 }
519
520 static bool __delete_win(unsigned int win)
521 {
522         struct win_node temp;
523         GSList *f;
524
525         temp.win = win;
526
527         f = g_slist_find_custom(g_winnode_list, &temp, WIN_COMP);
528         if (f == NULL) {
529                 errno = ENOENT;
530                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n",
531                      win);
532                 return 0;
533         }
534
535         g_winnode_list = g_slist_remove_link(g_winnode_list, f);
536
537         free(f->data);
538
539         return TRUE;
540 }
541
542 static bool __update_win(unsigned int win, bool bfobscured)
543 {
544         struct win_node temp;
545         GSList *f;
546
547         struct win_node *t;
548
549         _DBG("[EVENT_TEST][EVENT] __update_win WIN:%x fully_obscured %d\n", win,
550              bfobscured);
551
552         temp.win = win;
553
554         f = g_slist_find_custom(g_winnode_list, &temp, WIN_COMP);
555
556         if (f == NULL) {
557                 errno = ENOENT;
558                 _DBG("[EVENT_TEST][EVENT] ERROR There is no window : %x \n", win);
559                 return FALSE;
560         }
561
562         g_winnode_list = g_slist_remove_link(g_winnode_list, f);
563
564         free(f->data);
565
566         t = calloc(1, sizeof(struct win_node));
567         if (t == NULL)
568                 return FALSE;
569
570         t->win = win;
571         t->bfobscured = bfobscured;
572
573         g_winnode_list = g_slist_append(g_winnode_list, t);
574         
575         return TRUE;
576
577 }
578
579 /* WM_ROTATE */
580 static Ecore_X_Atom _WM_WINDOW_ROTATION_SUPPORTED = 0;
581 static Ecore_X_Atom _WM_WINDOW_ROTATION_CHANGE_REQUEST = 0;
582
583 static int __check_wm_rotation_support(void)
584 {
585         _DBG("Disable window manager rotation");
586         return -1;
587 #if 0
588         Ecore_X_Window root, win, win2;
589         int ret;
590
591         if (!_WM_WINDOW_ROTATION_SUPPORTED) {
592                 _WM_WINDOW_ROTATION_SUPPORTED =
593                                         ecore_x_atom_get("_E_WINDOW_ROTATION_SUPPORTED");
594         }
595
596         if (!_WM_WINDOW_ROTATION_CHANGE_REQUEST) {
597                 _WM_WINDOW_ROTATION_CHANGE_REQUEST =
598                                         ecore_x_atom_get("_E_WINDOW_ROTATION_CHANGE_REQUEST");
599         }
600
601         root = ecore_x_window_root_first_get();
602         ret = ecore_x_window_prop_xid_get(root,
603                         _WM_WINDOW_ROTATION_SUPPORTED,
604                         ECORE_X_ATOM_WINDOW,
605                         &win, 1);
606         if ((ret == 1) && (win))
607         {
608                 ret = ecore_x_window_prop_xid_get(win,
609                                 _WM_WINDOW_ROTATION_SUPPORTED,
610                                 ECORE_X_ATOM_WINDOW,
611                                 &win2, 1);
612                 if ((ret == 1) && (win2 == win))
613                         return 0;
614         }
615
616         return -1;
617 #endif
618 }
619
620 static void __set_wm_rotation_support(unsigned int win, unsigned int set)
621 {
622         GSList *iter = NULL;
623         struct win_node *entry = NULL;
624
625         if (0 == win) {
626                 for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
627                         entry = iter->data;
628                         if (entry->win) {
629                                 ecore_x_window_prop_card32_set(entry->win,
630                                                 _WM_WINDOW_ROTATION_SUPPORTED,
631                                                 &set, 1);
632                         }
633                 }
634         } else {
635                 ecore_x_window_prop_card32_set(win,
636                                 _WM_WINDOW_ROTATION_SUPPORTED,
637                                 &set, 1);
638         }
639 }
640
641 Ecore_X_Atom atom_parent;
642
643 static Eina_Bool __show_cb(void *data, int type, void *event)
644 {
645         Ecore_X_Event_Window_Show *ev;
646         int ret;
647         Ecore_X_Window parent;
648
649         ev = event;
650
651         ret = ecore_x_window_prop_window_get(ev->win, atom_parent, &parent, 1);
652         if (ret != 1)
653         {
654                 // This is child window. Skip!!!
655                 return ECORE_CALLBACK_PASS_ON;
656         }
657
658         _DBG("[EVENT_TEST][EVENT] GET SHOW EVENT!!!. WIN:%x\n", ev->win);
659
660         if (!__exist_win((unsigned int)ev->win)) {
661                 /* WM_ROTATE */
662                 if ((priv.wm_rot_supported) && (1 == priv.rot_started)) {
663                         __set_wm_rotation_support(ev->win, 1);
664                 }
665                 __add_win((unsigned int)ev->win);
666         }
667         else
668                 __update_win((unsigned int)ev->win, FALSE);
669
670         return ECORE_CALLBACK_RENEW;
671 }
672
673 static Eina_Bool __hide_cb(void *data, int type, void *event)
674 {
675         Ecore_X_Event_Window_Hide *ev;
676         int bvisibility = 0;
677
678         ev = event;
679
680         _DBG("[EVENT_TEST][EVENT] GET HIDE EVENT!!!. WIN:%x\n", ev->win);
681
682         if (__exist_win((unsigned int)ev->win)) {
683                 __delete_win((unsigned int)ev->win);
684                 
685                 bvisibility = __check_visible();
686                 if (!bvisibility && b_active == 1) {
687                         _DBG(" Go to Pasue state \n");
688                         b_active = 0;
689                         __do_app(AE_PAUSE, data, NULL);
690                         if(taskmanage) {
691                                 _capture_and_make_file(ev->win, getpid(), appid);
692                         } else if ( aul_is_subapp() ) {
693                                 _capture_and_make_file(ev->win, getpid(), appcore_get_caller_appid());
694                         }
695                 }
696         }
697
698         return ECORE_CALLBACK_RENEW;
699 }
700
701 static Eina_Bool __visibility_cb(void *data, int type, void *event)
702 {
703         Ecore_X_Event_Window_Visibility_Change *ev;
704         int bvisibility = 0;
705
706         ev = event;
707
708         __update_win((unsigned int)ev->win, ev->fully_obscured);
709         bvisibility = __check_visible();
710
711         if (bvisibility && b_active == 0) {
712                 _DBG(" Go to Resume state\n");
713                 b_active = 1;
714
715                 __do_app(AE_RESUME, data, NULL);
716
717         } else if (!bvisibility && b_active == 1) {
718                 _DBG(" Go to Pasue state \n");
719                 b_active = 0;
720                 __do_app(AE_PAUSE, data, NULL);
721                 if(taskmanage) {
722                         _capture_and_make_file(ev->win, getpid(), appid);
723                 } else if ( aul_is_subapp() ) {
724                         _capture_and_make_file(ev->win, getpid(), appcore_get_caller_appid());
725                 }
726         } else
727                 _DBG(" No change state \n");
728
729         return ECORE_CALLBACK_RENEW;
730
731 }
732
733 /* WM_ROTATE */
734 static Eina_Bool __cmsg_cb(void *data, int type, void *event)
735 {
736         struct ui_priv *ui = (struct ui_priv *)data;
737         Ecore_X_Event_Client_Message *e = event;
738
739         if (!ui) return ECORE_CALLBACK_PASS_ON;
740         if (e->format != 32) return ECORE_CALLBACK_PASS_ON;
741         if (e->message_type == _WM_WINDOW_ROTATION_CHANGE_REQUEST) {
742                 if ((0 == ui->wm_rot_supported) ||
743                         (0 == ui->rot_started) ||
744                         (NULL == ui->rot_cb)) {
745                         return ECORE_CALLBACK_PASS_ON;
746                 }
747
748                 enum appcore_rm rm;
749                 switch (e->data.l[1])
750                 {
751                         case   0: rm = APPCORE_RM_PORTRAIT_NORMAL;   break;
752                         case  90: rm = APPCORE_RM_LANDSCAPE_REVERSE; break;
753                         case 180: rm = APPCORE_RM_PORTRAIT_REVERSE;  break;
754                         case 270: rm = APPCORE_RM_LANDSCAPE_NORMAL;  break;
755                         default:  rm = APPCORE_RM_UNKNOWN;           break;
756                 }
757
758                 ui->rot_mode = rm;
759
760                 if (APPCORE_RM_UNKNOWN != rm) {
761                         ui->rot_cb(rm, ui->rot_cb_data);
762                 }
763         }
764
765         return ECORE_CALLBACK_PASS_ON;
766 }
767
768 static void __add_climsg_cb(struct ui_priv *ui)
769 {
770         _ret_if(ui == NULL);
771
772         atom_parent = ecore_x_atom_get("_E_PARENT_BORDER_WINDOW");
773         if (!atom_parent)
774         {
775                 // Do Error Handling
776         }
777
778         ui->hshow =
779             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHOW, __show_cb, ui);
780         ui->hhide =
781             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_HIDE, __hide_cb, ui);
782         ui->hvchange =
783             ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE,
784                                     __visibility_cb, ui);
785
786         /* Add client message callback for WM_ROTATE */
787         if(!__check_wm_rotation_support())
788         {
789                 ui->hcmsg =
790                         ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, __cmsg_cb, ui);
791                 ui->wm_rot_supported = 1;
792                 appcore_set_wm_rotation(&wm_rotate);
793         }
794 }
795
796 static int __before_loop(struct ui_priv *ui, int *argc, char ***argv)
797 {
798         int r;
799         char *hwacc = NULL;
800         char *tm_tmp = NULL;
801
802         if (argc == NULL || argv == NULL) {
803                 _ERR("argc/argv is NULL");
804                 errno = EINVAL;
805                 return -1;
806         }
807
808         g_type_init();
809         elm_init(*argc, *argv);
810
811         hwacc = getenv("HWACC");
812         if(hwacc == NULL) {
813                 _DBG("elm_config_preferred_engine_set is not called");
814         } else if(strcmp(hwacc, "USE") == 0) {
815                 elm_config_preferred_engine_set("opengl_x11");
816                 _DBG("elm_config_preferred_engine_set : opengl_x11");
817         } else if(strcmp(hwacc, "NOT_USE") == 0) {
818                 elm_config_preferred_engine_set("software_x11");
819                 _DBG("elm_config_preferred_engine_set : software_x11");
820         } else {
821                 _DBG("elm_config_preferred_engine_set is not called");
822         }
823
824         tm_tmp = getenv("TASKMANAGE");
825         if(tm_tmp == NULL) {
826                 _DBG("taskmanage is null");
827                 taskmanage = 1;
828         } else if(strcmp(tm_tmp, "false") == 0) {
829                 _DBG("taskmanage is false");
830                 taskmanage = 0;
831         } else {
832                 _DBG("taskmanage is true %s", tm_tmp);
833                 taskmanage = 1;
834         }
835
836         r = appcore_init(ui->name, &efl_ops, *argc, *argv);
837         _retv_if(r == -1, -1);
838
839         LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:appcore_init:done]", ui->name);
840         if (ui->ops && ui->ops->create) {
841                 r = ui->ops->create(ui->ops->data);
842                 if (r == -1) {
843                         _ERR("create() return error");
844                         appcore_exit();
845                         errno = ECANCELED;
846                         return -1;
847                 }
848                 LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:create:done]",
849                     ui->name);
850         }
851         ui->state = AS_CREATED;
852
853         __add_climsg_cb(ui);
854
855         return 0;
856 }
857
858 static void __after_loop(struct ui_priv *ui)
859 {
860         appcore_unset_rotation_cb();
861         appcore_exit();
862
863         if (ui->ops && ui->ops->terminate)
864                 ui->ops->terminate(ui->ops->data);
865
866         if (ui->hshow)
867                 ecore_event_handler_del(ui->hshow);
868         if (ui->hhide)
869                 ecore_event_handler_del(ui->hhide);
870         if (ui->hvchange)
871                 ecore_event_handler_del(ui->hvchange);
872
873         __appcore_timer_del(ui);
874
875         elm_shutdown();
876 }
877
878 static int __set_data(struct ui_priv *ui, const char *name,
879                     struct appcore_ops *ops)
880 {
881         if (ui->name) {
882                 _ERR("Mainloop already started");
883                 errno = EINPROGRESS;
884                 return -1;
885         }
886
887         if (name == NULL || name[0] == '\0') {
888                 _ERR("Invalid name");
889                 errno = EINVAL;
890                 return -1;
891         }
892
893         if (ops == NULL) {
894                 _ERR("ops is NULL");
895                 errno = EINVAL;
896                 return -1;
897         }
898
899         ui->name = strdup(name);
900         _retv_if(ui->name == NULL, -1);
901
902         ui->ops = ops;
903
904         ui->mfcb = __appcore_efl_memory_flush_cb;
905
906         _pid = getpid();
907
908         /* WM_ROTATE */
909         ui->wm_rot_supported = 0;
910         ui->rot_started = 0;
911         ui->rot_cb = NULL;
912         ui->rot_cb_data = NULL;
913         ui->rot_mode = APPCORE_RM_UNKNOWN;
914
915         return 0;
916 }
917
918 static void __unset_data(struct ui_priv *ui)
919 {
920         if (ui->name)
921                 free((void *)ui->name);
922
923         memset(ui, 0, sizeof(struct ui_priv));
924 }
925
926 /* WM_ROTATE */
927 static int __wm_set_rotation_cb(int (*cb) (enum appcore_rm, void *), void *data)
928 {
929         if (cb == NULL) {
930                 errno = EINVAL;
931                 return -1;
932         }
933
934         if ((priv.wm_rot_supported) && (0 == priv.rot_started)) {
935                 __set_wm_rotation_support(0, 1);
936         }
937
938         priv.rot_cb = cb;
939         priv.rot_cb_data = data;
940         priv.rot_started = 1;
941
942         return 0;
943 }
944
945 static int __wm_unset_rotation_cb(void)
946 {
947         if ((priv.wm_rot_supported) && (1 == priv.rot_started)) {
948                 __set_wm_rotation_support(0, 0);
949         }
950
951         priv.rot_cb = NULL;
952         priv.rot_cb_data = NULL;
953         priv.rot_started = 0;
954
955         return 0;
956 }
957
958 static int __wm_get_rotation_state(enum appcore_rm *curr)
959 {
960         if (curr == NULL) {
961                 errno = EINVAL;
962                 return -1;
963         }
964
965         *curr = priv.rot_mode;
966
967         return 0;
968 }
969
970 static int __wm_pause_rotation_cb(void)
971 {
972         if ((1 == priv.rot_started) && (priv.wm_rot_supported)) {
973                 __set_wm_rotation_support(0, 0);
974         }
975
976         priv.rot_started = 0;
977
978         return 0;
979 }
980
981 static int __wm_resume_rotation_cb(void)
982 {
983         if ((0 == priv.rot_started) && (priv.wm_rot_supported)) {
984                 __set_wm_rotation_support(0, 1);
985         }
986
987         priv.rot_started = 1;
988
989         return 0;
990 }
991
992 static struct ui_wm_rotate wm_rotate = {
993         __wm_set_rotation_cb,
994         __wm_unset_rotation_cb,
995         __wm_get_rotation_state,
996         __wm_pause_rotation_cb,
997         __wm_resume_rotation_cb
998 };
999
1000 static Window _get_parent_window(Window id)
1001 {
1002         Window root;
1003         Window parent;
1004         Window *children;
1005         unsigned int num;
1006
1007         if (!XQueryTree(ecore_x_display_get(), id, &root, &parent, &children, &num)) {
1008                 return 0;
1009         }
1010
1011         if (children) {
1012                 XFree(children);
1013         }
1014
1015         return parent;
1016 }
1017
1018 static Window _find_capture_window(Window id, Visual **visual, int *depth, int *width, int *height)
1019 {
1020         XWindowAttributes attr;
1021         Window parent = id;
1022         Window orig_id = id;
1023
1024         if (id == 0) {
1025                 return (Window)-1;
1026         }
1027
1028         do {
1029                 id = parent;
1030
1031                 if (!XGetWindowAttributes(ecore_x_display_get(), id, &attr)) {
1032                         return (Window)-1;
1033                 }
1034
1035                 parent = _get_parent_window(id);
1036
1037                 if (attr.map_state == IsViewable
1038                     && attr.override_redirect == True
1039                     && attr.class == InputOutput && parent == attr.root) {
1040                         *depth = attr.depth;
1041                         *width = attr.width;
1042                         *height = attr.height;
1043                         *visual = attr.visual;
1044                         return id;
1045                 }
1046         } while (parent != attr.root && parent != 0);
1047
1048         XGetWindowAttributes(ecore_x_display_get(), orig_id, &attr);
1049         *depth = attr.depth;
1050         *width = attr.width;
1051         *height = attr.height;
1052         *visual = attr.visual;
1053
1054         return (Window) 0;
1055
1056 }
1057
1058 static char *_capture_window(Window id, Visual *visual, int width, int height, int depth, int *size)
1059 {
1060         XShmSegmentInfo si;
1061         XImage *xim;
1062         int img_size;
1063         char *captured_img = NULL;
1064
1065         /* (depth >> 3) + 1 == 4 byte */
1066         si.shmid =
1067             shmget(IPC_PRIVATE, width * height * ((depth >> 3) + 1),
1068                    IPC_CREAT | 0666);
1069
1070         if (si.shmid < 0) {
1071                 _ERR("shmget");
1072                 return NULL;
1073         }
1074
1075         si.readOnly = False;
1076         si.shmaddr = shmat(si.shmid, NULL, 0);
1077
1078         if (si.shmaddr == (char *)-1) {
1079                 shmdt(si.shmaddr);
1080                 shmctl(si.shmid, IPC_RMID, 0);
1081                 return NULL;
1082         }
1083
1084         xim = XShmCreateImage(ecore_x_display_get(), visual, depth, ZPixmap, NULL, &si,
1085                             width, height);
1086
1087         if (xim == 0) {
1088                 shmdt(si.shmaddr);
1089                 shmctl(si.shmid, IPC_RMID, 0);
1090
1091                 return NULL;
1092         }
1093
1094         img_size = xim->bytes_per_line * xim->height;
1095         xim->data = si.shmaddr;
1096
1097         XSync(ecore_x_display_get(), False);
1098         XShmAttach(ecore_x_display_get(), &si);
1099         XShmGetImage(ecore_x_display_get(), id, xim, 0, 0, 0xFFFFFFFF);
1100         XSync(ecore_x_display_get(), False);
1101
1102         captured_img = calloc(1, img_size);
1103         if (captured_img) {
1104                 memcpy(captured_img, xim->data, img_size);
1105         } else {
1106                 _ERR("calloc");
1107         }
1108
1109         XShmDetach(ecore_x_display_get(), &si);
1110         XDestroyImage(xim);
1111
1112
1113         shmdt(si.shmaddr);
1114         shmctl(si.shmid, IPC_RMID, 0);
1115
1116         *size = img_size;
1117
1118         return captured_img;
1119
1120 }
1121
1122 #define _WND_REQUEST_ANGLE_IDX 0
1123 #define _WND_CURR_ANGLE_IDX    1
1124 int _get_angle(Ecore_X_Window win)
1125 {
1126         int after = -1;
1127         int before = -1;
1128
1129         do {
1130                 int ret, count;
1131                 int angle[2] = {-1, -1};
1132                 unsigned char* prop_data = NULL;
1133
1134                 ret = ecore_x_window_prop_property_get(win,
1135                                 ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
1136                                 ECORE_X_ATOM_CARDINAL,
1137                                 32,
1138                                 &prop_data,
1139                                 &count);
1140                 if (ret <= 0) {
1141                         if (prop_data) free(prop_data);
1142                         break;
1143                 }
1144
1145                 if (prop_data) {
1146                         memcpy(&angle, prop_data, sizeof (int) *count);
1147                         free(prop_data);
1148                 }
1149
1150                 after= angle[_WND_REQUEST_ANGLE_IDX];
1151                 before = angle[_WND_CURR_ANGLE_IDX];
1152         } while (0);
1153
1154         if (-1 == after) after = 0;
1155
1156         return after;
1157 }
1158
1159 static void _rotate_img(Evas_Object *image_object, int angle, int cx, int cy)
1160 {
1161         Evas_Map *em;
1162
1163         _ret_if(NULL == image_object);
1164
1165         em = evas_map_new(4);
1166         _ret_if(NULL == em);
1167
1168         evas_map_util_points_populate_from_object(em, image_object);
1169         evas_map_util_rotate(em, (double) angle, cx, cy);
1170
1171         evas_object_map_set(image_object, em);
1172         evas_object_map_enable_set(image_object, EINA_TRUE);
1173
1174         evas_map_free(em);
1175 }
1176
1177 #define EXTENSION_LEN 128
1178 #define CAPTURE_FILE_PATH "/opt/share/app_capture"
1179 bool _make_capture_file(const char *package, int width, int height, char *img, int angle)
1180 {
1181         int len;
1182         char *filename;
1183         Evas *e;
1184         Evas_Object *image_object;
1185         int canvas_width, canvas_height;
1186         int cx = 0, cy = 0;
1187         int mx = 0;
1188
1189         _retv_if(NULL == package, false);
1190
1191         len = strlen(package) + EXTENSION_LEN;
1192         filename = malloc(len);
1193         _retv_if(NULL == filename, false);
1194         snprintf(filename, len, CAPTURE_FILE_PATH"/%s.jpg", package);
1195
1196         if (90 == angle || 270 == angle) {
1197                 canvas_width = height;
1198                 canvas_height = width;
1199         } else {
1200                 canvas_width = width;
1201                 canvas_height = height;
1202         }
1203
1204         e = virtual_canvas_create(canvas_width, canvas_height);
1205         goto_if(NULL == e, error);
1206
1207         image_object = evas_object_image_add(e);
1208         goto_if(NULL == image_object, error);
1209
1210         evas_object_image_size_set(image_object, width, height);
1211         evas_object_image_data_set(image_object, img);
1212         evas_object_image_data_update_add(image_object, 0, 0, width, height);
1213         evas_object_resize(image_object, width, height);
1214         evas_object_image_filled_set(image_object, EINA_TRUE);
1215         switch (angle) {
1216                 case 90:
1217                         cx = canvas_width - width / 2;
1218                         cy = canvas_height / 2;
1219                         mx = canvas_width - width;
1220                         break;
1221                 case 180:
1222                         cx = width / 2;
1223                         cy = height / 2;
1224                         break;
1225                 case 270:
1226                         cx = width / 2;
1227                         cy = canvas_height / 2;
1228                         break;
1229                 default:
1230                         break;
1231         }
1232         evas_object_move(image_object, mx, 0);
1233         _rotate_img(image_object, angle, cx, cy);
1234         evas_object_show(image_object);
1235
1236         if (access(CAPTURE_FILE_PATH, F_OK) != 0) {
1237                 mkdir(CAPTURE_FILE_PATH, 0777);
1238         }
1239         goto_if(false == virtual_canvas_flush_to_file(e, filename, canvas_width, canvas_height), error);
1240
1241         evas_object_del(image_object);
1242         virtual_canvas_destroy(e);
1243         free(filename);
1244
1245         return true;
1246
1247 error:
1248         do {
1249                 free(filename);
1250
1251                 if (!e) break;
1252                 virtual_canvas_destroy(e);
1253
1254                 if (!image_object) break;
1255                 evas_object_del(image_object);
1256         } while (0);
1257
1258         return false;
1259 }
1260
1261 int __resize8888(const char* pDataIn, char* pDataOut, int inWidth, int inHeight, int outWidth, int outHeight)
1262 {
1263         int scaleX = 0;
1264         int scaleY = 0;
1265         int i = 0;
1266         int j = 0;
1267         int iRow = 0;
1268         int iIndex = 0;
1269         char* pOutput = pDataOut;
1270         char* pOut = pDataOut;
1271         const char* pIn = NULL;
1272         int *pColLUT = malloc(sizeof(int) * outWidth);
1273
1274         /* Calculate X Scale factor */
1275         scaleX = inWidth * 256 / outWidth;
1276         /* Calculate Y Scale factor, aspect ratio is not maintained */
1277         scaleY = inHeight * 256 / outHeight;
1278         for (j = 0; j < outWidth; j++)
1279         {
1280         /* Get input index based on column scale factor */
1281         /* To get more optimization, this is calculated once and
1282         * is placed in a LUT and used for indexing
1283         */
1284         pColLUT [j] = ((j * scaleX) >> 8) * 4;
1285         }
1286         pOut = pOutput;
1287         for (i = 0; i < outHeight; i++)
1288         {
1289                 /* Get input routWidth index based on routWidth scale factor */
1290                 iRow = (i * scaleY >> 8) * inWidth * 4;
1291                 /* Loop could be unrolled for more optimization */
1292                 for (j = 0; j < (outWidth); j++)
1293                 {
1294                         /* Get input index based on column scale factor */
1295                         iIndex = iRow + pColLUT [j];
1296                         pIn = pDataIn + iIndex;
1297                         *pOut++ = *pIn++;
1298                         *pOut++ = *pIn++;
1299                         *pOut++ = *pIn++;
1300                         *pOut++ = *pIn++;
1301                 }
1302         }
1303
1304         free(pColLUT);
1305         return 0;
1306 }
1307
1308
1309 static void _capture_and_make_file(Ecore_X_Window win, int pid, const char *package)
1310 {
1311         Visual *visual;
1312         Window redirected_id;
1313
1314         int width, height, depth;
1315         int width_out, height_out;
1316         int size = 0;
1317         int angle;
1318
1319         char *img;
1320
1321         redirected_id = _find_capture_window(win, &visual, &depth, &width, &height);
1322         _ret_if(redirected_id == (Window) -1 ||
1323                                 redirected_id == (Window) 0);
1324
1325         SECURE_LOGD("Capture : win[%x] -> redirected win[%x] for %s[%d]", win, redirected_id, package, pid);
1326
1327         img = _capture_window(redirected_id, visual, width, height, depth, &size);
1328         _ret_if(NULL == img);
1329
1330         width_out = width/2;
1331         height_out = height/2;
1332
1333         if ( width_out < 1 || height_out < 1 ) {
1334                 free(img);
1335                 return;
1336         }
1337
1338         __resize8888(img, img, width, height, width_out, height_out);
1339
1340         angle = _get_angle(win);
1341         if (false == _make_capture_file(package, width_out, height_out, img, angle)) {
1342                 _ERR("cannot a capture file for the package of [%s]", package);
1343         }
1344
1345         free(img);
1346 }
1347
1348
1349 EXPORT_API int appcore_efl_main(const char *name, int *argc, char ***argv,
1350                                 struct appcore_ops *ops)
1351 {
1352         int r;
1353         GSList *iter = NULL;
1354         struct win_node *entry = NULL;
1355         int pid;
1356         int ret;
1357
1358         LOG(LOG_DEBUG, "LAUNCH", "[%s:Application:main:done]", name);
1359
1360         pid = getpid();
1361         aul_app_get_appid_bypid(pid, appid, APPID_MAX);
1362
1363         r = __set_data(&priv, name, ops);
1364         _retv_if(r == -1, -1);
1365
1366         r = __before_loop(&priv, argc, argv);
1367         if (r == -1) {
1368                 __unset_data(&priv);
1369                 return -1;
1370         }
1371
1372         elm_run();
1373
1374         aul_status_update(STATUS_DYING);
1375
1376         for (iter = g_winnode_list; iter != NULL; iter = g_slist_next(iter)) {
1377                 entry = iter->data;
1378                 if(__check_skip(entry->win) == FALSE)
1379                         break;
1380         }
1381         if(iter) {
1382                 entry = iter->data;
1383                 if(taskmanage) {
1384                         _capture_and_make_file(entry->win, pid, appid);
1385                 }
1386         }
1387
1388         __after_loop(&priv);
1389
1390         __unset_data(&priv);
1391
1392         return 0;
1393 }
1394
1395 EXPORT_API int appcore_set_system_resource_reclaiming(bool enable)
1396 {
1397         resource_reclaiming = enable;
1398
1399         return 0;
1400 }
1401
1402 EXPORT_API int appcore_set_app_state(int state)
1403 {
1404         priv.state = state;
1405
1406         return 0;
1407 }