Update accessibility event handling codes.
[apps/livebox/livebox-edje.git] / src / script_port.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.tizenopensource.org/license
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <libgen.h>
19 #include <errno.h>
20 #include <unistd.h>
21 #include <ctype.h>
22
23 #include <Elementary.h>
24 #include <Evas.h>
25 #include <Edje.h>
26 #include <Eina.h>
27 #include <Ecore.h>
28 #include <Ecore_Evas.h>
29 #include <Eet.h>
30 #include <Ecore_X.h>
31
32 #include <dlog.h>
33 #include <debug.h>
34 #include <vconf.h>
35 #include <livebox-errno.h>
36 #include <livebox-service.h>
37
38 #include "script_port.h"
39
40 #define TEXT_CLASS      "tizen"
41 #define BASE_WIDTH      720.0f
42
43 #define PUBLIC __attribute__((visibility("default")))
44
45 struct image_option {
46         int orient;
47         int aspect;
48         enum {
49                 FILL_DISABLE,
50                 FILL_IN_SIZE,
51                 FILL_OVER_SIZE,
52         } fill;
53
54         int width;
55         int height;
56 };
57
58 struct info {
59         char *file;
60         char *group;
61         char *category;
62         int w;
63         int h;
64
65         Evas *e;
66
67         Eina_List *obj_list;
68 };
69
70 struct child {
71         Evas_Object *obj;
72         char *part;
73 };
74
75 struct obj_info {
76         char *id;
77         Eina_List *children;
78         Evas_Object *win;
79         Eina_List *access_chain;
80 };
81
82 static inline double scale_get(void)
83 {
84         int width;
85         int height;
86         ecore_x_window_size_get(0, &width, &height);
87         return (double)width / BASE_WIDTH;
88 }
89
90 static inline Evas_Object *find_edje(struct info *handle, const char *id)
91 {
92         Eina_List *l;
93         Evas_Object *edje;
94         struct obj_info *obj_info;
95
96         EINA_LIST_FOREACH(handle->obj_list, l, edje) {
97                 obj_info = evas_object_data_get(edje, "obj_info");
98                 if (!obj_info) {
99                         ErrPrint("Object info is not valid\n");
100                         continue;
101                 }
102
103                 if (!id) {
104                         if (!obj_info->id)
105                                 return edje;
106
107                         continue;
108                 } else if (!obj_info->id) {
109                         continue;
110                 }
111
112                 if (!strcmp(obj_info->id, id))
113                         return edje;
114         }
115
116         DbgPrint("EDJE[%s] is not found\n", id);
117         return NULL;
118 }
119
120 static inline void rebuild_focus_chain(Evas_Object *obj)
121 {
122         struct obj_info *obj_info;
123         Evas_Object *ao;
124         Eina_List *l;
125
126         obj_info = evas_object_data_get(obj, "obj_info");
127         if (!obj_info) {
128                 ErrPrint("Object info is not available\n");
129                 return;
130         }
131
132         elm_object_focus_custom_chain_unset(obj);
133
134         DbgPrint("Rebuild focus chain begin\n");
135         EINA_LIST_FOREACH(obj_info->access_chain, l, ao) {
136                 DbgPrint("Append %p\n", ao);
137                 elm_object_focus_custom_chain_append(obj, ao, NULL);
138         }
139         DbgPrint("Rebuild focus chain done\n");
140 }
141
142 PUBLIC const char *script_magic_id(void)
143 {
144         return "edje";
145 }
146
147 PUBLIC int script_update_color(void *h, Evas *e, const char *id, const char *part, const char *rgba)
148 {
149         struct info *handle = h;
150         Evas_Object *edje;
151         int r[3], g[3], b[3], a[3];
152         int ret;
153
154         edje = find_edje(handle, id);
155         if (!edje)
156                 return LB_STATUS_ERROR_NOT_EXIST;
157
158         ret = sscanf(rgba, "%d %d %d %d %d %d %d %d %d %d %d %d",
159                                         r, g, b, a,                     /* OBJECT */
160                                         r + 1, g + 1, b + 1, a + 1,     /* OUTLINE */
161                                         r + 2, g + 2, b + 2, a + 2);    /* SHADOW */
162         if (ret != 12) {
163                 DbgPrint("id[%s] part[%s] rgba[%s]\n", id, part, rgba);
164                 return LB_STATUS_ERROR_INVALID;
165         }
166
167         ret = edje_object_color_class_set(elm_layout_edje_get(edje), part,
168                                 r[0], g[0], b[0], a[0], /* OBJECT */
169                                 r[1], g[1], b[1], a[1], /* OUTLINE */
170                                 r[2], g[2], b[2], a[2]); /* SHADOW */
171
172         DbgPrint("EDJE[%s] color class is %s changed", id, ret == EINA_TRUE ? "successfully" : "not");
173         return LB_STATUS_SUCCESS;
174 }
175
176 static void activate_cb(void *data, Evas_Object *part_obj, Elm_Object_Item *item)
177 {
178         Evas_Object *ao;
179         Evas_Object *edje;
180         Evas *e;
181         int x;
182         int y;
183         int w;
184         int h;
185         struct timeval tv;
186         double timestamp;
187
188         ao = evas_object_data_get(part_obj, "ao");
189         if (!ao)
190                 return;
191
192         edje = evas_object_data_get(ao, "edje");
193         if (!edje)
194                 return;
195
196         e = evas_object_evas_get(part_obj);
197         evas_object_geometry_get(part_obj, &x, &y, &w, &h);
198         x += w / 2;
199         y += h / 2;
200
201         if (gettimeofday(&tv, NULL) < 0) {
202                 ErrPrint("Failed to get time\n");
203                 timestamp = 0.0f;
204         } else {
205                 timestamp = (double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0f);
206         }
207
208         DbgPrint("Cursor is on %dx%d\n", x, y);
209         evas_event_feed_mouse_move(e, x, y, timestamp, NULL);
210         evas_event_feed_mouse_down(e, 1, EVAS_BUTTON_NONE, timestamp + 0.01f, NULL);
211         evas_event_feed_mouse_move(e, x, y, timestamp + 0.02f, NULL);
212         evas_event_feed_mouse_up(e, 1, EVAS_BUTTON_NONE, timestamp + 0.03f, NULL);
213 }
214
215 PUBLIC int script_update_text(void *h, Evas *e, const char *id, const char *part, const char *text)
216 {
217         struct obj_info *obj_info;
218         struct info *handle = h;
219         Evas_Object *edje;
220         Evas_Object *to;
221
222         edje = find_edje(handle, id);
223         if (!edje) {
224                 ErrPrint("Failed to find EDJE\n");
225                 return LB_STATUS_ERROR_NOT_EXIST;
226         }
227
228         obj_info = evas_object_data_get(edje, "obj_info");
229         if (!obj_info) {
230                 ErrPrint("Object info is not available\n");
231                 return LB_STATUS_ERROR_FAULT;
232         }
233
234         elm_object_part_text_set(edje, part, text ? text : "");
235
236         to = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(edje), part);
237         if (to) {
238                 Evas_Object *ao;
239                 char *utf8;
240
241                 ao = evas_object_data_get(to, "ao");
242                 if (!ao) {
243                         ao = elm_access_object_register(to, edje);
244                         if (!ao) {
245                                 ErrPrint("Unable to add ao: %s\n", part);
246                                 goto out;
247                         }
248                         obj_info->access_chain = eina_list_append(obj_info->access_chain, ao);
249                         evas_object_data_set(to, "ao", ao);
250                         evas_object_data_set(ao, "edje", edje);
251                         elm_access_activate_cb_set(ao, activate_cb, NULL);
252                         elm_object_focus_custom_chain_append(edje, ao, NULL);
253                 }
254
255                 if (!text || !strlen(text)) {
256                         obj_info->access_chain = eina_list_remove(obj_info->access_chain, ao);
257                         evas_object_data_del(to, "ao");
258                         evas_object_data_del(ao, "edje");
259                         elm_access_object_unregister(ao);
260                         DbgPrint("[%s] Remove access object\n", part);
261
262                         rebuild_focus_chain(edje);
263                         goto out;
264                 }
265
266                 utf8 = elm_entry_markup_to_utf8(text);
267                 if ((!utf8 || !strlen(utf8))) {
268                         free(utf8);
269
270                         obj_info->access_chain = eina_list_remove(obj_info->access_chain, ao);
271                         evas_object_data_del(to, "ao");
272                         evas_object_data_del(ao, "edje");
273                         elm_access_object_unregister(ao);
274                         DbgPrint("[%s] Remove access object\n", part);
275
276                         rebuild_focus_chain(edje);
277                         goto out;
278                 }
279
280                 elm_access_info_set(ao, ELM_ACCESS_INFO, utf8);
281                 DbgPrint("[%s] Update access object (%s)\n", part, utf8);
282                 free(utf8);
283         } else {
284                 ErrPrint("Unable to get text part[%s]\n", part);
285         }
286
287 out:
288         return LB_STATUS_SUCCESS;
289 }
290
291 static void parse_aspect(struct image_option *img_opt, const char *value, int len)
292 {
293         while (len > 0 && *value == ' ') {
294                 value++;
295                 len--;
296         }
297
298         if (len < 4)
299                 return;
300
301         img_opt->aspect = !strncasecmp(value, "true", 4);
302         DbgPrint("Parsed ASPECT: %d (%s)\n", img_opt->aspect, value);
303 }
304
305 static void parse_orient(struct image_option *img_opt, const char *value, int len)
306 {
307         while (len > 0 && *value == ' ') {
308                 value++;
309                 len--;
310         }
311
312         if (len < 4)
313                 return;
314
315         img_opt->orient = !strncasecmp(value, "true", 4);
316         DbgPrint("Parsed ORIENT: %d (%s)\n", img_opt->aspect, value);
317 }
318
319 static void parse_size(struct image_option *img_opt, const char *value, int len)
320 {
321         int width;
322         int height;
323         char *buf;
324
325         while (len > 0 && *value == ' ') {
326                 value++;
327                 len--;
328         }
329
330         buf = strndup(value, len);
331         if (!buf) {
332                 ErrPrint("Heap: %s\n", strerror(errno));
333                 return;
334         }
335
336         if (sscanf(buf, "%dx%d", &width, &height) == 2) {
337                 img_opt->width = width;
338                 img_opt->height = height;
339                 DbgPrint("Parsed size : %dx%d (%s)\n", width, height, buf);
340         } else {
341                 DbgPrint("Invalid size tag[%s]\n", buf);
342         }
343
344         free(buf);
345 }
346
347 static void parse_fill(struct image_option *img_opt, const char *value, int len)
348 {
349         while (len > 0 && *value == ' ') {
350                 value++;
351                 len--;
352         }
353
354         if (!strncasecmp(value, "in-size", len))
355                 img_opt->fill = FILL_IN_SIZE;
356         else if (!strncasecmp(value, "over-size", len))
357                 img_opt->fill = FILL_OVER_SIZE;
358         else
359                 img_opt->fill = FILL_DISABLE;
360
361         DbgPrint("Parsed FILL: %d (%s)\n", img_opt->fill, value);
362 }
363
364 static inline void parse_image_option(const char *option, struct image_option *img_opt)
365 {
366         const char *ptr;
367         const char *cmd;
368         const char *value;
369         struct {
370                 const char *cmd;
371                 void (*handler)(struct image_option *img_opt, const char *value, int len);
372         } cmd_list[] = {
373                 {
374                         .cmd = "aspect", /* Keep the aspect ratio */
375                         .handler = parse_aspect,
376                 },
377                 {
378                         .cmd = "orient", /* Keep the orientation value: for the rotated images */
379                         .handler = parse_orient,
380                 },
381                 {
382                         .cmd = "fill", /* Fill the image to its container */
383                         .handler = parse_fill, /* Value: in-size, over-size, disable(default) */
384                 },
385                 {
386                         .cmd = "size",
387                         .handler = parse_size,
388                 },
389         };
390         enum {
391                 STATE_START,
392                 STATE_TOKEN,
393                 STATE_DATA,
394                 STATE_IGNORE,
395                 STATE_ERROR,
396                 STATE_END,
397         } state;
398         int idx;
399         int tag;
400
401         if (!option || !*option)
402                 return;
403
404         state = STATE_START;
405         /*!
406          * \note
407          * GCC 4.7 warnings uninitialized idx and tag value.
408          * But it will be initialized by the state machine. :(
409          * Anyway, I just reset idx and tag for reducing the GCC4.7 complains.
410          */
411         idx = 0;
412         tag = 0;
413         cmd = NULL;
414         value = NULL;
415
416         for (ptr = option; state != STATE_END; ptr++) {
417                 switch (state) {
418                 case STATE_START:
419                         if (*ptr == '\0') {
420                                 state = STATE_END;
421                                 continue;
422                         }
423
424                         if (isalpha(*ptr)) {
425                                 state = STATE_TOKEN;
426                                 ptr--;
427                         }
428                         tag = 0;
429                         idx = 0;
430
431                         cmd = cmd_list[tag].cmd;
432                         break;
433                 case STATE_IGNORE:
434                         if (*ptr == '=') {
435                                 state = STATE_DATA;
436                                 value = ptr;
437                         } else if (*ptr == '\0') {
438                                 state = STATE_END;
439                         }
440                         break;
441                 case STATE_TOKEN:
442                         if (cmd[idx] == '\0' && (*ptr == ' ' || *ptr == '\t' || *ptr == '=')) {
443                                 if (*ptr == '=') {
444                                         value = ptr;
445                                         state = STATE_DATA;
446                                 } else {
447                                         state = STATE_IGNORE;
448                                 }
449                                 idx = 0;
450                         } else if (*ptr == '\0') {
451                                 state = STATE_END;
452                         } else if (cmd[idx] == *ptr) {
453                                 idx++;
454                         } else {
455                                 ptr -= (idx + 1);
456
457                                 tag++;
458                                 if (tag == sizeof(cmd_list) / sizeof(cmd_list[0])) {
459                                         tag = 0;
460                                         state = STATE_ERROR;
461                                 } else {
462                                         cmd = cmd_list[tag].cmd;
463                                 }
464                                 idx = 0;
465                         }
466                         break;
467                 case STATE_DATA:
468                         if (*ptr == ';' || *ptr == '\0') {
469                                 cmd_list[tag].handler(img_opt, value + 1, idx);
470                                 state = *ptr ? STATE_START : STATE_END;
471                         } else {
472                                 idx++;
473                         }
474                         break;
475                 case STATE_ERROR:
476                         if (*ptr == ';')
477                                 state = STATE_START;
478                         else if (*ptr == '\0')
479                                 state = STATE_END;
480                         break;
481                 default:
482                         break;
483                 }
484         }
485 }
486
487 PUBLIC int script_update_access(void *_h, Evas *e, const char *id, const char *part, const char *text, const char *option)
488 {
489         struct info *handle = _h;
490         Evas_Object *edje;
491         struct obj_info *obj_info;
492         Evas_Object *to;
493
494         edje = find_edje(handle, id);
495         if (!edje) {
496                 ErrPrint("No such object: %s\n", id);
497                 return LB_STATUS_ERROR_NOT_EXIST;
498         }
499
500         obj_info = evas_object_data_get(edje, "obj_info");
501         if (!obj_info) {
502                 ErrPrint("Object info is not available\n");
503                 return LB_STATUS_ERROR_FAULT;
504         }
505
506         to = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(edje), part);
507         if (to) {
508                 Evas_Object *ao;
509
510                 ao = evas_object_data_get(to, "ao");
511                 if (ao) {
512                         DbgPrint("[%s] Update access object (%s)\n", part, text);
513                         if (text && strlen(text)) {
514                                 elm_access_info_set(ao, ELM_ACCESS_INFO, text);
515                         } else {
516                                 obj_info->access_chain = eina_list_remove(obj_info->access_chain, ao);
517                                 evas_object_data_del(to, "ao");
518                                 evas_object_data_del(ao, "edje");
519                                 elm_access_object_unregister(ao);
520                                 DbgPrint("Successfully unregistered\n");
521
522                                 rebuild_focus_chain(edje);
523                         }
524                 } else if (text && strlen(text)) {
525                         ao = elm_access_object_register(to, edje);
526                         if (!ao) {
527                                 ErrPrint("Unable to register access object\n");
528                         } else {
529                                 elm_access_info_set(ao, ELM_ACCESS_INFO, text);
530                                 obj_info->access_chain = eina_list_append(obj_info->access_chain, ao);
531                                 evas_object_data_set(to, "ao", ao);
532                                 elm_object_focus_custom_chain_append(edje, ao, NULL);
533                                 DbgPrint("[%s] Register access info: (%s)\n", part, text);
534                                 evas_object_data_set(ao, "edje", edje);
535                                 elm_access_activate_cb_set(ao, activate_cb, NULL);
536                         }
537                 }
538         } else {
539                 ErrPrint("[%s] is not exists\n", part);
540         }
541
542         return LB_STATUS_SUCCESS;
543 }
544
545 PUBLIC int script_update_image(void *_h, Evas *e, const char *id, const char *part, const char *path, const char *option)
546 {
547         struct info *handle = _h;
548         Evas_Load_Error err;
549         Evas_Object *edje;
550         Evas_Object *img;
551         Evas_Coord w, h;
552         struct obj_info *obj_info;
553         struct child *child;
554         struct image_option img_opt = {
555                 .aspect = 0,
556                 .orient = 0,
557                 .fill = FILL_DISABLE,
558                 .width = -1,
559                 .height = -1,
560         };
561
562         edje = find_edje(handle, id);
563         if (!edje) {
564                 ErrPrint("No such object: %s\n", id);
565                 return LB_STATUS_ERROR_NOT_EXIST;
566         }
567
568         obj_info = evas_object_data_get(edje, "obj_info");
569         if (!obj_info) {
570                 ErrPrint("Object info is not available\n");
571                 return LB_STATUS_ERROR_FAULT;
572         }
573
574         img = elm_object_part_content_unset(edje, part);
575         if (img) {
576                 Eina_List *l;
577                 Eina_List *n;
578                 Evas_Object *ao;
579
580                 EINA_LIST_FOREACH_SAFE(obj_info->children, l, n, child) {
581                         if (child->obj != img)
582                                 continue;
583
584                         obj_info->children = eina_list_remove(obj_info->children, child);
585                         free(child->part);
586                         free(child);
587                         break;
588                 }
589
590                 DbgPrint("delete object %s %p\n", part, img);
591                 ao = evas_object_data_del(img, "ao");
592                 if (ao) {
593                         obj_info->access_chain = eina_list_remove(obj_info->access_chain, ao);
594                         evas_object_data_del(ao, "edje");
595                         elm_access_object_unregister(ao);
596                         DbgPrint("Successfully unregistered\n");
597                 }
598                 evas_object_del(img);
599
600                 rebuild_focus_chain(edje);
601         }
602
603         if (!path || !strlen(path) || access(path, R_OK) != 0) {
604                 DbgPrint("SKIP - Path: [%s]\n", path);
605                 return LB_STATUS_SUCCESS;
606         }
607
608         child = malloc(sizeof(*child));
609         if (!child) {
610                 ErrPrint("Heap: %s\n", strerror(errno));
611                 return LB_STATUS_ERROR_MEMORY;
612         }
613
614         child->part = strdup(part);
615         if (!child->part) {
616                 ErrPrint("Heap: %s\n", strerror(errno));
617                 free(child);
618                 return LB_STATUS_ERROR_MEMORY;
619         }
620
621         img = evas_object_image_add(e);
622         if (!img) {
623                 ErrPrint("Failed to add an image object\n");
624                 free(child->part);
625                 free(child);
626                 return LB_STATUS_ERROR_FAULT;
627         }
628
629         evas_object_image_preload(img, EINA_FALSE);
630         parse_image_option(option, &img_opt);
631         evas_object_image_load_orientation_set(img, img_opt.orient);
632
633         evas_object_image_file_set(img, path, NULL);
634         err = evas_object_image_load_error_get(img);
635         if (err != EVAS_LOAD_ERROR_NONE) {
636                 ErrPrint("Load error: %s\n", evas_load_error_str(err));
637                 evas_object_del(img);
638                 free(child->part);
639                 free(child);
640                 return LB_STATUS_ERROR_IO;
641         }
642
643         evas_object_image_size_get(img, &w, &h);
644         if (img_opt.aspect) {
645                 if (img_opt.fill == FILL_OVER_SIZE) {
646                         Evas_Coord part_w;
647                         Evas_Coord part_h;
648
649                         if (img_opt.width >= 0 && img_opt.height >= 0) {
650                                 part_w = img_opt.width * scale_get();
651                                 part_h = img_opt.height * scale_get();
652                         } else {
653                                 part_w = 0;
654                                 part_h = 0;
655                                 edje_object_part_geometry_get(elm_layout_edje_get(edje), part, NULL, NULL, &part_w, &part_h);
656                         }
657                         DbgPrint("Original %dx%d (part: %dx%d)\n", w, h, part_w, part_h);
658
659                         if (part_w > w || part_h > h) {
660                                 double fw;
661                                 double fh;
662
663                                 fw = (double)part_w / (double)w;
664                                 fh = (double)part_h / (double)h;
665
666                                 if (fw > fh) {
667                                         w = part_w;
668                                         h = (double)h * fw;
669                                 } else {
670                                         h = part_h;
671                                         w = (double)w * fh;
672                                 }
673                         }
674                         DbgPrint("Size: %dx%d\n", w, h);
675
676                         evas_object_image_load_size_set(img, w, h);
677                         evas_object_image_load_region_set(img, (w - part_w) / 2, (h - part_h) / 2, part_w, part_h);
678                         evas_object_image_fill_set(img, 0, 0, part_w, part_h);
679                         evas_object_image_reload(img);
680                 } else {
681                         evas_object_image_fill_set(img, 0, 0, w, h);
682                         evas_object_size_hint_fill_set(img, EVAS_HINT_FILL, EVAS_HINT_FILL);
683                         evas_object_size_hint_aspect_set(img, EVAS_ASPECT_CONTROL_BOTH, w, h);
684                 }
685         } else {
686                 if (img_opt.width >= 0 && img_opt.height >= 0) {
687                         w = img_opt.width;
688                         h = img_opt.height;
689                         DbgPrint("Using given image size: %dx%d\n", w, h);
690                 }
691
692                 evas_object_image_fill_set(img, 0, 0, w, h);
693                 evas_object_size_hint_fill_set(img, EVAS_HINT_FILL, EVAS_HINT_FILL);
694                 evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
695         }
696
697         /*!
698          * \note
699          * object will be shown by below statement automatically
700          */
701         DbgPrint("%s part swallow image %p (%dx%d)\n", part, img, w, h);
702         child->obj = img;
703         elm_object_part_content_set(edje, part, img);
704         obj_info->children = eina_list_append(obj_info->children, child);
705
706         /*!
707          * \note
708          * This object is not registered as an access object.
709          * So the developer should add it to access list manually, using DESC_ACCESS block.
710          */
711         return LB_STATUS_SUCCESS;
712 }
713
714 static void script_signal_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
715 {
716         struct info *handle = data;
717         Evas_Coord w;
718         Evas_Coord h;
719         Evas_Coord px = 0;
720         Evas_Coord py = 0;
721         Evas_Coord pw = 0;
722         Evas_Coord ph = 0;
723         double sx;
724         double sy;
725         double ex;
726         double ey;
727
728         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
729         edje_object_part_geometry_get(elm_layout_edje_get(obj), source, &px, &py, &pw, &ph);
730
731         sx = ex = 0.0f;
732         if (w) {
733                 sx = (double)px / (double)w;
734                 ex = (double)(px + pw) / (double)w;
735         }
736
737         sy = ey = 0.0f;
738         if (h) {
739                 sy = (double)py / (double)h;
740                 ey = (double)(py + ph) / (double)h;
741         }
742
743         DbgPrint("Signal emit: source[%s], emission[%s]\n", source, emission);
744         script_signal_emit(handle->e, source, emission, sx, sy, ex, ey);
745 }
746
747 static void edje_del_cb(void *_info, Evas *e, Evas_Object *obj, void *event_info)
748 {
749         struct info *handle = _info;
750         struct obj_info *obj_info;
751         struct child *child;
752         Evas_Object *ao;
753
754         handle->obj_list = eina_list_remove(handle->obj_list, obj);
755
756         obj_info = evas_object_data_del(obj, "obj_info");
757         if (!obj_info) {
758                 ErrPrint("Object info is not valid\n");
759                 return;
760         }
761
762         DbgPrint("delete object %s %p\n", obj_info->id, obj);
763
764         elm_object_signal_callback_del(obj, "*", "*", script_signal_cb);
765
766         elm_object_focus_custom_chain_unset(obj);
767
768         EINA_LIST_FREE(obj_info->children, child) {
769                 DbgPrint("delete object %s %p\n", child->part, child->obj);
770                 if (child->obj) {
771                         Evas_Object *ao;
772                         ao = evas_object_data_del(child->obj, "ao");
773                         if (ao) {
774                                 obj_info->access_chain = eina_list_remove(obj_info->access_chain, ao);
775                                 evas_object_data_del(ao, "edje");
776                                 elm_access_object_unregister(ao);
777                         }
778                         evas_object_del(child->obj);
779                 }
780                 free(child->part);
781                 free(child);
782         }
783
784         EINA_LIST_FREE(obj_info->access_chain, ao) {
785                 evas_object_data_del(ao, "edje");
786                 elm_access_object_unregister(ao);
787         }
788
789         free(obj_info->id);
790         free(obj_info);
791 }
792
793 /*!
794         LB_ACCESS_HIGHLIGHT             0
795         LB_ACCESS_HIGHLIGHT_NEXT        1
796         LB_ACCESS_HIGHLIGHT_PREV        2
797         LB_ACCESS_ACTIVATE              3
798         LB_ACCESS_VALUE_CHANGE          4
799         LB_ACCESS_SCROLL                5
800 */
801 PUBLIC int script_feed_event(void *h, Evas *e, int event_type, int x, int y, double timestamp)
802 {
803         struct info *handle = h;
804         Evas_Object *edje;
805         struct obj_info *obj_info;
806         int ret = LB_STATUS_SUCCESS;
807
808         DbgPrint("event: %d, x: %d, y: %d\n", event_type, x, y);
809
810         edje = find_edje(handle, NULL); /*!< Get the base layout */
811         if (!edje) {
812                 ErrPrint("Base layout is not exist\n");
813                 return LB_STATUS_ERROR_NOT_EXIST;
814         }
815
816         obj_info = evas_object_data_get(edje, "obj_info");
817         if (!obj_info) {
818                 ErrPrint("Object info is not valid\n");
819                 return LB_STATUS_ERROR_INVALID;
820         }
821
822         if (event_type & LB_SCRIPT_ACCESS_EVENT) {
823                 Elm_Access_Action_Info *info;
824                 Elm_Access_Action_Type action;
825                 const Eina_List *chain;
826
827                 info = calloc(1, sizeof(*info));
828                 if (!info) {
829                         ErrPrint("Error: %s\n", strerror(errno));
830                         return LB_STATUS_ERROR_MEMORY;
831                 }
832
833                 chain = elm_object_focus_custom_chain_get(edje);
834                 DbgPrint("Focus chain : %d\n", eina_list_count(chain));
835
836                 if ((event_type & LB_SCRIPT_ACCESS_HIGHLIGHT) == LB_SCRIPT_ACCESS_HIGHLIGHT) {
837                         action = ELM_ACCESS_ACTION_HIGHLIGHT;
838                         info->x = x;
839                         info->y = y;
840                         ret = elm_access_action(edje, action, info);
841                         DbgPrint("ACCESS_HIGHLIGHT: %dx%d returns %d\n", x, y, ret);
842                         ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
843                 } else if ((event_type & LB_SCRIPT_ACCESS_HIGHLIGHT_NEXT) == LB_SCRIPT_ACCESS_HIGHLIGHT_NEXT) {
844                         action = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
845                         info->highlight_cycle = EINA_FALSE;
846                         ret = elm_access_action(edje, action, info);
847                         DbgPrint("ACCESS_HIGHLIGHT_NEXT, returns %d\n", ret);
848                         ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_LAST : LB_ACCESS_STATUS_DONE;
849                 } else if ((event_type & LB_SCRIPT_ACCESS_HIGHLIGHT_PREV) == LB_SCRIPT_ACCESS_HIGHLIGHT_PREV) {
850                         action = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
851                         info->highlight_cycle = EINA_FALSE;
852                         ret = elm_access_action(edje, action, info);
853                         DbgPrint("ACCESS_HIGHLIGHT_PREV, returns %d\n", ret);
854                         ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_FIRST : LB_ACCESS_STATUS_DONE;
855                 } else if ((event_type & LB_SCRIPT_ACCESS_ACTIVATE) == LB_SCRIPT_ACCESS_ACTIVATE) {
856                         action = ELM_ACCESS_ACTION_ACTIVATE;
857                         ret = elm_access_action(edje, action, info);
858                         DbgPrint("ACCESS_HIGHLIGHT_ACTIVATE, returns %d\n", ret);
859                         ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
860                 } else if ((event_type & LB_SCRIPT_ACCESS_VALUE_CHANGE) == LB_SCRIPT_ACCESS_VALUE_CHANGE) {
861                         action = ELM_ACCESS_ACTION_VALUE_CHANGE;
862                         ret = elm_access_action(edje, action, info);
863                         DbgPrint("ACCESS_HIGHLIGHT_VALUE_CHANGE, returns %d\n", ret);
864                         ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
865                 } else if ((event_type & LB_SCRIPT_ACCESS_SCROLL) == LB_SCRIPT_ACCESS_SCROLL) {
866                         action = ELM_ACCESS_ACTION_SCROLL;
867                         ret = elm_access_action(edje, action, info);
868                         DbgPrint("ACCESS_HIGHLIGHT_SCROLL, returns %d\n", ret);
869                         ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
870                 } else if ((event_type & LB_SCRIPT_ACCESS_UNHIGHLIGHT) == LB_SCRIPT_ACCESS_UNHIGHLIGHT) {
871                         action = ELM_ACCESS_ACTION_UNHIGHLIGHT;
872                         ret = elm_access_action(edje, action, info);
873                         DbgPrint("ACCESS_UNHIGHLIGHT, returns %d\n", ret);
874                         ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
875                 } else {
876                         DbgPrint("Invalid event\n");
877                         ret = LB_ACCESS_STATUS_ERROR;
878                 }
879
880                 free(info);
881         } else if (event_type & LB_SCRIPT_MOUSE_EVENT) {
882                 switch (event_type) {
883                 case LB_SCRIPT_MOUSE_DOWN:
884                         evas_event_feed_mouse_move(e, x, y, timestamp, NULL);
885                         evas_event_feed_mouse_down(e, 1, EVAS_BUTTON_NONE, timestamp + 0.01f, NULL);
886                         break;
887                 case LB_SCRIPT_MOUSE_MOVE:
888                         evas_event_feed_mouse_move(e, x, y, timestamp, NULL);
889                         break;
890                 case LB_SCRIPT_MOUSE_UP:
891                         evas_event_feed_mouse_move(e, x, y, timestamp, NULL);
892                         evas_event_feed_mouse_up(e, 1, EVAS_BUTTON_NONE, timestamp + 0.1f, NULL);
893                         break;
894                 case LB_SCRIPT_MOUSE_IN:
895                         evas_event_feed_mouse_in(e, timestamp, NULL);
896                         break;
897                 case LB_SCRIPT_MOUSE_OUT:
898                         evas_event_feed_mouse_out(e, timestamp, NULL);
899                         break;
900                 default:
901                         return LB_STATUS_ERROR_INVALID;
902                 }
903         } else if (event_type & LB_SCRIPT_KEY_EVENT) {
904                 DbgPrint("Key event is not implemented\n");
905                 return LB_STATUS_ERROR_NOT_IMPLEMENTED;
906         }
907
908         return ret;
909 }
910
911 PUBLIC int script_update_script(void *h, Evas *e, const char *src_id, const char *target_id, const char *part, const char *path, const char *group)
912 {
913         struct info *handle = h;
914         Evas_Object *edje;
915         Evas_Object *obj;
916         struct obj_info *obj_info;
917         struct child *child;
918
919         DbgPrint("src_id[%s] target_id[%s] part[%s] path[%s] group[%s]\n", src_id, target_id, part, path, group);
920
921         edje = find_edje(handle, src_id);
922         if (!edje) {
923                 ErrPrint("Edje is not exists\n");
924                 return LB_STATUS_ERROR_NOT_EXIST;
925         }
926
927         obj_info = evas_object_data_get(edje, "obj_info");
928         if (!obj_info) {
929                 ErrPrint("Object info is not valid\n");
930                 return LB_STATUS_ERROR_INVALID;
931         }
932
933         obj = elm_object_part_content_unset(edje, part);
934         if (obj) {
935                 Eina_List *l;
936                 Eina_List *n;
937
938                 EINA_LIST_FOREACH_SAFE(obj_info->children, l, n, child) {
939                         if (child->obj != obj)
940                                 continue;
941
942                         obj_info->children = eina_list_remove(obj_info->children, child);
943
944                         free(child->part);
945                         free(child);
946                         break;
947                 }
948
949                 DbgPrint("delete object %s %p\n", part, obj);
950                 /*!
951                  * \note
952                  * This will call the edje_del_cb.
953                  * It will delete all access objects
954                  */
955                 evas_object_del(obj);
956         }
957
958         if (!path || !strlen(path) || access(path, R_OK) != 0) {
959                 DbgPrint("SKIP - Path: [%s]\n", path);
960                 return LB_STATUS_SUCCESS;
961         }
962
963         obj = elm_layout_add(edje);
964         if (!obj) {
965                 ErrPrint("Failed to add a new edje object\n");
966                 return LB_STATUS_ERROR_FAULT;
967         }
968
969         if (!elm_layout_file_set(obj, path, group)) {
970                 int err;
971                 const char *errmsg;
972
973                 err = edje_object_load_error_get(elm_layout_edje_get(obj));
974                 errmsg = edje_load_error_str(err);
975                 ErrPrint("Could not load %s from %s: %s\n", group, path, errmsg);
976                 evas_object_del(obj);
977                 return LB_STATUS_ERROR_IO;
978         }
979
980         evas_object_show(obj);
981
982         obj_info = calloc(1, sizeof(*obj_info));
983         if (!obj_info) {
984                 ErrPrint("Failed to add a obj_info\n");
985                 evas_object_del(obj);
986                 return LB_STATUS_ERROR_MEMORY;
987         }
988
989         obj_info->id = strdup(target_id);
990         if (!obj_info->id) {
991                 ErrPrint("Failed to add a obj_info\n");
992                 free(obj_info);
993                 evas_object_del(obj);
994                 return LB_STATUS_ERROR_MEMORY;
995         }
996
997         child = malloc(sizeof(*child));
998         if (!child) {
999                 ErrPrint("Error: %s\n", strerror(errno));
1000                 free(obj_info->id);
1001                 free(obj_info);
1002                 evas_object_del(obj);
1003                 return LB_STATUS_ERROR_MEMORY;
1004         }
1005
1006         child->part = strdup(part);
1007         if (!child->part) {
1008                 ErrPrint("Error: %s\n", strerror(errno));
1009                 free(child);
1010                 free(obj_info->id);
1011                 free(obj_info);
1012                 evas_object_del(obj);
1013                 return LB_STATUS_ERROR_MEMORY;
1014         }
1015
1016         child->obj = obj;
1017
1018         evas_object_data_set(obj, "obj_info", obj_info);
1019         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, edje_del_cb, handle);
1020         elm_object_signal_callback_add(obj, "*", "*", script_signal_cb, handle);
1021         handle->obj_list = eina_list_append(handle->obj_list, obj);
1022
1023         DbgPrint("%s part swallow edje %p\n", part, obj);
1024         elm_object_part_content_set(edje, part, obj);
1025         obj_info = evas_object_data_get(edje, "obj_info");
1026         obj_info->children = eina_list_append(obj_info->children, child);
1027         return LB_STATUS_SUCCESS;
1028 }
1029
1030 PUBLIC int script_update_signal(void *h, Evas *e, const char *id, const char *part, const char *signal)
1031 {
1032         struct info *handle = h;
1033         Evas_Object *edje;
1034
1035         DbgPrint("id[%s], part[%s], signal[%s]\n", id, part, signal);
1036
1037         edje = find_edje(handle, id);
1038         if (!edje)
1039                 return LB_STATUS_ERROR_NOT_EXIST;
1040
1041         elm_object_signal_emit(edje, signal, part);
1042         return LB_STATUS_SUCCESS;
1043 }
1044
1045 PUBLIC int script_update_drag(void *h, Evas *e, const char *id, const char *part, double x, double y)
1046 {
1047         struct info *handle = h;
1048         Evas_Object *edje;
1049
1050         DbgPrint("id[%s], part[%s], %lfx%lf\n", id, part, x, y);
1051
1052         edje = find_edje(handle, id);
1053         if (!edje)
1054                 return LB_STATUS_ERROR_NOT_EXIST;
1055
1056         edje_object_part_drag_value_set(elm_layout_edje_get(edje), part, x, y);
1057         return LB_STATUS_SUCCESS;
1058 }
1059
1060 PUBLIC int script_update_size(void *han, Evas *e, const char *id, int w, int h)
1061 {
1062         struct info *handle = han;
1063         Evas_Object *edje;
1064
1065         edje = find_edje(handle, id);
1066         if (!edje)
1067                 return LB_STATUS_ERROR_NOT_EXIST;
1068
1069         if (!id) {
1070                 handle->w = w;
1071                 handle->h = h;
1072         }
1073
1074         DbgPrint("Resize object to %dx%d\n", w, h);
1075         evas_object_resize(edje, w, h);
1076         return LB_STATUS_SUCCESS;
1077 }
1078
1079 PUBLIC int script_update_category(void *h, Evas *e, const char *id, const char *category)
1080 {
1081         struct info *handle = h;
1082
1083         DbgPrint("id[%s], category[%s]\n", id, category);
1084
1085         if (handle->category) {
1086                 free(handle->category);
1087                 handle->category = NULL;
1088         }
1089
1090         if (!category)
1091                 return LB_STATUS_SUCCESS;
1092
1093         handle->category = strdup(category);
1094         if (!handle->category) {
1095                 ErrPrint("Error: %s\n", strerror(errno));
1096                 return LB_STATUS_ERROR_MEMORY;
1097         }
1098
1099         return LB_STATUS_SUCCESS;
1100 }
1101
1102 PUBLIC void *script_create(const char *file, const char *group)
1103 {
1104         struct info *handle;
1105
1106         DbgPrint("file[%s], group[%s]\n", file, group);
1107
1108         handle = calloc(1, sizeof(*handle));
1109         if (!handle) {
1110                 ErrPrint("Error: %s\n", strerror(errno));
1111                 return NULL;
1112         }
1113
1114         handle->file = strdup(file);
1115         if (!handle->file) {
1116                 ErrPrint("Error: %s\n", strerror(errno));
1117                 free(handle);
1118                 return NULL;
1119         }
1120
1121         handle->group = strdup(group);
1122         if (!handle->group) {
1123                 ErrPrint("Error: %s\n", strerror(errno));
1124                 free(handle->file);
1125                 free(handle);
1126                 return NULL;
1127         }
1128
1129         return handle;
1130 }
1131
1132 PUBLIC int script_destroy(void *_handle)
1133 {
1134         struct info *handle;
1135         Evas_Object *edje;
1136
1137         handle = _handle;
1138
1139         edje = eina_list_nth(handle->obj_list, 0);
1140         if (edje)
1141                 evas_object_del(edje);
1142
1143         free(handle->category);
1144         free(handle->file);
1145         free(handle->group);
1146         free(handle);
1147         return LB_STATUS_SUCCESS;
1148 }
1149
1150 PUBLIC int script_load(void *_handle, Evas *e, int w, int h)
1151 {
1152         struct info *handle;
1153         Evas_Object *edje;
1154         struct obj_info *obj_info;
1155
1156         handle = _handle;
1157
1158         obj_info = calloc(1, sizeof(*obj_info));
1159         if (!obj_info) {
1160                 ErrPrint("Heap: %s\n", strerror(errno));
1161                 return LB_STATUS_ERROR_MEMORY;
1162         }
1163
1164         obj_info->win = evas_object_rectangle_add(e);
1165         if (!obj_info->win) {
1166                 free(obj_info);
1167                 return LB_STATUS_ERROR_FAULT;
1168         }
1169
1170         edje = elm_layout_add(obj_info->win);
1171         if (!edje) {
1172                 ErrPrint("Failed to create an edje object\n");
1173                 evas_object_del(obj_info->win);
1174                 free(obj_info);
1175                 return LB_STATUS_ERROR_FAULT;
1176         }
1177
1178         DbgPrint("Load edje: %s - %s\n", handle->file, handle->group);
1179         if (!elm_layout_file_set(edje, handle->file, handle->group)) {
1180                 int err;
1181                 const char *errmsg;
1182
1183                 err = edje_object_load_error_get(elm_layout_edje_get(edje));
1184                 errmsg = edje_load_error_str(err);
1185                 ErrPrint("Could not load %s from %s: %s\n", handle->group, handle->file, errmsg);
1186                 evas_object_del(edje);
1187                 evas_object_del(obj_info->win);
1188                 free(obj_info);
1189                 return LB_STATUS_ERROR_IO;
1190         }
1191
1192         handle->e = e;
1193         handle->w = w;
1194         handle->h = h;
1195
1196         elm_object_signal_callback_add(edje, "*", "*", script_signal_cb, handle);
1197         evas_object_event_callback_add(edje, EVAS_CALLBACK_DEL, edje_del_cb, handle);
1198         evas_object_size_hint_weight_set(edje, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1199         evas_object_size_hint_fill_set(edje, EVAS_HINT_FILL, EVAS_HINT_FILL);
1200         evas_object_resize(edje, handle->w, handle->h);
1201         evas_object_show(edje);
1202         evas_object_data_set(edje, "obj_info", obj_info);
1203
1204         handle->obj_list = eina_list_append(handle->obj_list, edje);
1205         return LB_STATUS_SUCCESS;
1206 }
1207
1208 PUBLIC int script_unload(void *_handle, Evas *e)
1209 {
1210         struct info *handle;
1211         Evas_Object *edje;
1212
1213         handle = _handle;
1214
1215         DbgPrint("Unload edje: %s - %s\n", handle->file, handle->group);
1216         edje = eina_list_nth(handle->obj_list, 0);
1217         if (edje)
1218                 evas_object_del(edje);
1219         handle->e = NULL;
1220         return LB_STATUS_SUCCESS;
1221 }
1222
1223 static void access_cb(keynode_t *node, void *user_data)
1224 {
1225         int state;
1226
1227         if (!node) {
1228                 if (vconf_get_bool(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &state) != 0) {
1229                         ErrPrint("Idle lock state is not valid\n");
1230                         state = 0; /* DISABLED */
1231                 }
1232         } else {
1233                 state = vconf_keynode_get_bool(node);
1234         }
1235
1236         DbgPrint("ELM CONFIG ACCESS: %d\n", state);
1237         elm_config_access_set(state);
1238 }
1239
1240 PUBLIC int script_init(void)
1241 {
1242         int ret;
1243         char *argv[] = {
1244                 "livebox.edje",
1245                 NULL,
1246         };
1247         /* ecore is already initialized */
1248         elm_init(1, argv);
1249         elm_config_scale_set(scale_get());
1250
1251         ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, access_cb, NULL);
1252         if (ret < 0)
1253                 ErrPrint("Failed to access cb\n");
1254
1255         access_cb(NULL, NULL);
1256         return LB_STATUS_SUCCESS;
1257 }
1258
1259 PUBLIC int script_fini(void)
1260 {
1261         vconf_ignore_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, access_cb);
1262         elm_shutdown();
1263         return LB_STATUS_SUCCESS;
1264 }
1265
1266 /* End of a file */