Update License
[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 <Evas.h>
24 #include <Edje.h>
25 #include <Eina.h>
26 #include <Ecore.h>
27 #include <Ecore_Evas.h>
28 #include <Eet.h>
29 #include <Ecore_X.h>
30
31 #include <dlog.h>
32 #include <debug.h>
33 #include <vconf.h>
34 #include <livebox-errno.h>
35
36 #include "script_port.h"
37
38 #define TEXT_CLASS      "tizen"
39 #define BASE_WIDTH      720.0f
40
41 #define PUBLIC __attribute__((visibility("default")))
42
43 extern void evas_common_font_flush(void);
44 extern int evas_common_font_cache_get(void);
45 extern void evas_common_font_cache_set(int size);
46
47 struct image_option {
48         int orient;
49         int aspect;
50         enum {
51                 FILL_DISABLE,
52                 FILL_IN_SIZE,
53                 FILL_OVER_SIZE,
54         } fill;
55
56         int width;
57         int height;
58 };
59
60 struct info {
61         char *file;
62         char *group;
63         char *category;
64         int w;
65         int h;
66
67         Evas *e;
68
69         Eina_List *obj_list;
70 };
71
72 struct child {
73         Evas_Object *obj;
74         char *part;
75 };
76
77 struct obj_info {
78         char *id;
79         Eina_List *children;
80 };
81
82 static struct {
83         Ecore_Event_Handler *property_handler;
84         char *font;
85         int size;
86 } s_info = {
87         .property_handler = NULL,
88         .font = NULL,
89         .size = -100,
90 };
91
92 static inline double scale_get(void)
93 {
94         int width;
95         int height;
96         ecore_x_window_size_get(0, &width, &height);
97         return (double)width / BASE_WIDTH;
98 }
99
100 /*!
101  * \NOTE
102  * Reservce this for future use
103 static inline void common_cache_flush(void *evas)
104 {
105         int file_cache;
106         int collection_cache;
107         int image_cache;
108         int font_cache;
109
110         file_cache = edje_file_cache_get();
111         collection_cache = edje_collection_cache_get();
112         image_cache = evas_image_cache_get(evas);
113         font_cache = evas_font_cache_get(evas);
114
115         edje_file_cache_set(file_cache);
116         edje_collection_cache_set(collection_cache);
117         evas_image_cache_set(evas, 0);
118         evas_font_cache_set(evas, 0);
119
120         evas_image_cache_flush(evas);
121         evas_render_idle_flush(evas);
122         evas_font_cache_flush(evas);
123
124         edje_file_cache_flush();
125         edje_collection_cache_flush();
126
127         edje_file_cache_set(file_cache);
128         edje_collection_cache_set(collection_cache);
129         evas_image_cache_set(evas, image_cache);
130         evas_font_cache_set(evas, font_cache);
131
132         eet_clearcache();
133 }
134  */
135
136 static inline Evas_Object *find_edje(struct info *handle, const char *id)
137 {
138         Eina_List *l;
139         Evas_Object *edje;
140         struct obj_info *obj_info;
141
142         EINA_LIST_FOREACH(handle->obj_list, l, edje) {
143                 obj_info = evas_object_data_get(edje, "obj_info");
144                 if (!obj_info) {
145                         ErrPrint("Object info is not valid\n");
146                         continue;
147                 }
148
149                 if (!id) {
150                         if (!obj_info->id)
151                                 return edje;
152
153                         continue;
154                 } else if (!obj_info->id) {
155                         continue;
156                 }
157
158                 if (!strcmp(obj_info->id, id))
159                         return edje;
160         }
161
162         DbgPrint("EDJE[%s] is not found\n", id);
163         return NULL;
164 }
165
166 PUBLIC const char *script_magic_id(void)
167 {
168         return "edje";
169 }
170
171 PUBLIC int script_update_color(void *h, Evas *e, const char *id, const char *part, const char *rgba)
172 {
173         struct info *handle = h;
174         Evas_Object *edje;
175         int r[3], g[3], b[3], a[3];
176         int ret;
177
178         edje = find_edje(handle, id);
179         if (!edje)
180                 return LB_STATUS_ERROR_NOT_EXIST;
181
182         ret = sscanf(rgba, "%d %d %d %d %d %d %d %d %d %d %d %d",
183                                         r, g, b, a,                     /* OBJECT */
184                                         r + 1, g + 1, b + 1, a + 1,     /* OUTLINE */
185                                         r + 2, g + 2, b + 2, a + 2);    /* SHADOW */
186         if (ret != 12) {
187                 DbgPrint("id[%s] part[%s] rgba[%s]\n", id, part, rgba);
188                 return LB_STATUS_ERROR_INVALID;
189         }
190
191         ret = edje_object_color_class_set(edje, part,
192                                 r[0], g[0], b[0], a[0], /* OBJECT */
193                                 r[1], g[1], b[1], a[1], /* OUTLINE */
194                                 r[2], g[2], b[2], a[2]); /* SHADOW */
195
196         DbgPrint("EDJE[%s] color class is %s changed", id, ret == EINA_TRUE ? "successfully" : "not");
197         return LB_STATUS_SUCCESS;
198 }
199
200 PUBLIC int script_update_text(void *h, Evas *e, const char *id, const char *part, const char *text)
201 {
202         struct info *handle = h;
203         Evas_Object *edje;
204
205         edje = find_edje(handle, id);
206         if (!edje)
207                 return LB_STATUS_ERROR_NOT_EXIST;
208
209         edje_object_part_text_set(edje, part, text);
210         return LB_STATUS_SUCCESS;
211 }
212
213 static void parse_aspect(struct image_option *img_opt, const char *value, int len)
214 {
215         while (len > 0 && *value == ' ') {
216                 value++;
217                 len--;
218         }
219
220         if (len < 4)
221                 return;
222
223         img_opt->aspect = !strncasecmp(value, "true", 4);
224         DbgPrint("Parsed ASPECT: %d (%s)\n", img_opt->aspect, value);
225 }
226
227 static void parse_orient(struct image_option *img_opt, const char *value, int len)
228 {
229         while (len > 0 && *value == ' ') {
230                 value++;
231                 len--;
232         }
233
234         if (len < 4)
235                 return;
236
237         img_opt->orient = !strncasecmp(value, "true", 4);
238         DbgPrint("Parsed ORIENT: %d (%s)\n", img_opt->aspect, value);
239 }
240
241 static void parse_size(struct image_option *img_opt, const char *value, int len)
242 {
243         int width;
244         int height;
245         char *buf;
246
247         while (len > 0 && *value == ' ') {
248                 value++;
249                 len--;
250         }
251
252         buf = strndup(value, len);
253         if (!buf) {
254                 ErrPrint("Heap: %s\n", strerror(errno));
255                 return;
256         }
257
258         if (sscanf(buf, "%dx%d", &width, &height) == 2) {
259                 img_opt->width = width;
260                 img_opt->height = height;
261                 DbgPrint("Parsed size : %dx%d (%s)\n", width, height, buf);
262         } else {
263                 DbgPrint("Invalid size tag[%s]\n", buf);
264         }
265
266         free(buf);
267 }
268
269 static void parse_fill(struct image_option *img_opt, const char *value, int len)
270 {
271         while (len > 0 && *value == ' ') {
272                 value++;
273                 len--;
274         }
275
276         if (!strncasecmp(value, "in-size", len))
277                 img_opt->fill = FILL_IN_SIZE;
278         else if (!strncasecmp(value, "over-size", len))
279                 img_opt->fill = FILL_OVER_SIZE;
280         else
281                 img_opt->fill = FILL_DISABLE;
282
283         DbgPrint("Parsed FILL: %d (%s)\n", img_opt->fill, value);
284 }
285
286 static inline void parse_image_option(const char *option, struct image_option *img_opt)
287 {
288         const char *ptr;
289         const char *cmd;
290         const char *value;
291         struct {
292                 const char *cmd;
293                 void (*handler)(struct image_option *img_opt, const char *value, int len);
294         } cmd_list[] = {
295                 {
296                         .cmd = "aspect", /* Keep the aspect ratio */
297                         .handler = parse_aspect,
298                 },
299                 {
300                         .cmd = "orient", /* Keep the orientation value: for the rotated images */
301                         .handler = parse_orient,
302                 },
303                 {
304                         .cmd = "fill", /* Fill the image to its container */
305                         .handler = parse_fill, /* Value: in-size, over-size, disable(default) */
306                 },
307                 {
308                         .cmd = "size",
309                         .handler = parse_size,
310                 },
311         };
312         enum {
313                 STATE_START,
314                 STATE_TOKEN,
315                 STATE_DATA,
316                 STATE_IGNORE,
317                 STATE_ERROR,
318                 STATE_END,
319         } state;
320         int idx;
321         int tag;
322
323         if (!option || !*option)
324                 return;
325
326         state = STATE_START;
327         /*!
328          * \note
329          * GCC 4.7 warnings uninitialized idx and tag value.
330          * But it will be initialized by the state machine. :(
331          * Anyway, I just reset idx and tag for reducing the GCC4.7 complains.
332          */
333         idx = 0;
334         tag = 0;
335         cmd = NULL;
336         value = NULL;
337
338         for (ptr = option; state != STATE_END; ptr++) {
339                 switch (state) {
340                 case STATE_START:
341                         if (*ptr == '\0') {
342                                 state = STATE_END;
343                                 continue;
344                         }
345
346                         if (isalpha(*ptr)) {
347                                 state = STATE_TOKEN;
348                                 ptr--;
349                         }
350                         tag = 0;
351                         idx = 0;
352
353                         cmd = cmd_list[tag].cmd;
354                         break;
355                 case STATE_IGNORE:
356                         if (*ptr == '=') {
357                                 state = STATE_DATA;
358                                 value = ptr;
359                         } else if (*ptr == '\0') {
360                                 state = STATE_END;
361                         }
362                         break;
363                 case STATE_TOKEN:
364                         if (cmd[idx] == '\0' && (*ptr == ' ' || *ptr == '\t' || *ptr == '=')) {
365                                 if (*ptr == '=') {
366                                         value = ptr;
367                                         state = STATE_DATA;
368                                 } else {
369                                         state = STATE_IGNORE;
370                                 }
371                                 idx = 0;
372                         } else if (*ptr == '\0') {
373                                 state = STATE_END;
374                         } else if (cmd[idx] == *ptr) {
375                                 idx++;
376                         } else {
377                                 ptr -= (idx + 1);
378
379                                 tag++;
380                                 if (tag == sizeof(cmd_list) / sizeof(cmd_list[0])) {
381                                         tag = 0;
382                                         state = STATE_ERROR;
383                                 } else {
384                                         cmd = cmd_list[tag].cmd;
385                                 }
386                                 idx = 0;
387                         }
388                         break;
389                 case STATE_DATA:
390                         if (*ptr == ';' || *ptr == '\0') {
391                                 cmd_list[tag].handler(img_opt, value + 1, idx);
392                                 state = *ptr ? STATE_START : STATE_END;
393                         } else {
394                                 idx++;
395                         }
396                         break;
397                 case STATE_ERROR:
398                         if (*ptr == ';')
399                                 state = STATE_START;
400                         else if (*ptr == '\0')
401                                 state = STATE_END;
402                         break;
403                 default:
404                         break;
405                 }
406         }
407 }
408
409 PUBLIC int script_update_image(void *_h, Evas *e, const char *id, const char *part, const char *path, const char *option)
410 {
411         struct info *handle = _h;
412         Evas_Load_Error err;
413         Evas_Object *edje;
414         Evas_Object *img;
415         Evas_Coord w, h;
416         struct obj_info *obj_info;
417         struct child *child;
418         struct image_option img_opt = {
419                 .aspect = 0,
420                 .orient = 0,
421                 .fill = FILL_DISABLE,
422                 .width = -1,
423                 .height = -1,
424         };
425
426         edje = find_edje(handle, id);
427         if (!edje) {
428                 ErrPrint("No such object: %s\n", id);
429                 return LB_STATUS_ERROR_NOT_EXIST;
430         }
431
432         obj_info = evas_object_data_get(edje, "obj_info");
433         if (!obj_info) {
434                 ErrPrint("Object info is not available\n");
435                 return LB_STATUS_ERROR_FAULT;
436         }
437
438         img = edje_object_part_swallow_get(edje, part);
439         if (img) {
440                 Eina_List *l;
441                 Eina_List *n;
442
443                 edje_object_part_unswallow(edje, img);
444
445                 EINA_LIST_FOREACH_SAFE(obj_info->children, l, n, child) {
446                         if (child->obj != img)
447                                 continue;
448
449                         obj_info->children = eina_list_remove(obj_info->children, child);
450                         free(child->part);
451                         free(child);
452                         break;
453                 }
454
455                 DbgPrint("delete object %s %p\n", part, img);
456                 evas_object_del(img);
457         }
458
459         if (!path || !strlen(path) || access(path, R_OK) != 0) {
460                 DbgPrint("SKIP - Path: [%s]\n", path);
461                 return LB_STATUS_SUCCESS;
462         }
463
464         child = malloc(sizeof(*child));
465         if (!child) {
466                 ErrPrint("Heap: %s\n", strerror(errno));
467                 return LB_STATUS_ERROR_MEMORY;
468         }
469
470         child->part = strdup(part);
471         if (!child->part) {
472                 ErrPrint("Heap: %s\n", strerror(errno));
473                 free(child);
474                 return LB_STATUS_ERROR_MEMORY;
475         }
476
477         img = evas_object_image_add(e);
478         if (!img) {
479                 ErrPrint("Failed to add an image object\n");
480                 free(child->part);
481                 free(child);
482                 return LB_STATUS_ERROR_FAULT;
483         }
484
485         evas_object_image_preload(img, EINA_FALSE);
486         parse_image_option(option, &img_opt);
487         evas_object_image_load_orientation_set(img, img_opt.orient);
488
489         evas_object_image_file_set(img, path, NULL);
490         err = evas_object_image_load_error_get(img);
491         if (err != EVAS_LOAD_ERROR_NONE) {
492                 ErrPrint("Load error: %s\n", evas_load_error_str(err));
493                 evas_object_del(img);
494                 free(child->part);
495                 free(child);
496                 return LB_STATUS_ERROR_IO;
497         }
498
499         evas_object_image_size_get(img, &w, &h);
500         if (img_opt.aspect) {
501                 if (img_opt.fill == FILL_OVER_SIZE) {
502                         Evas_Coord part_w;
503                         Evas_Coord part_h;
504
505                         if (img_opt.width >= 0 && img_opt.height >= 0) {
506                                 part_w = img_opt.width * scale_get();
507                                 part_h = img_opt.height * scale_get();
508                         } else {
509                                 part_w = 0;
510                                 part_h = 0;
511                                 edje_object_part_geometry_get(edje, part, NULL, NULL, &part_w, &part_h);
512                         }
513                         DbgPrint("Original %dx%d (part: %dx%d)\n", w, h, part_w, part_h);
514
515                         if (part_w > w || part_h > h) {
516                                 double fw;
517                                 double fh;
518
519                                 fw = (double)part_w / (double)w;
520                                 fh = (double)part_h / (double)h;
521
522                                 if (fw > fh) {
523                                         w = part_w;
524                                         h = (double)h * fw;
525                                 } else {
526                                         h = part_h;
527                                         w = (double)w * fh;
528                                 }
529                         }
530                         DbgPrint("Size: %dx%d\n", w, h);
531
532                         evas_object_image_load_size_set(img, w, h);
533                         evas_object_image_load_region_set(img, (w - part_w) / 2, (h - part_h) / 2, part_w, part_h);
534                         evas_object_image_fill_set(img, 0, 0, part_w, part_h);
535                         evas_object_image_reload(img);
536                 } else {
537                         evas_object_image_fill_set(img, 0, 0, w, h);
538                         evas_object_size_hint_fill_set(img, EVAS_HINT_FILL, EVAS_HINT_FILL);
539                         evas_object_size_hint_aspect_set(img, EVAS_ASPECT_CONTROL_BOTH, w, h);
540                 }
541         } else {
542                 if (img_opt.width >= 0 && img_opt.height >= 0) {
543                         w = img_opt.width;
544                         h = img_opt.height;
545                         DbgPrint("Using given image size: %dx%d\n", w, h);
546                 }
547
548                 evas_object_image_fill_set(img, 0, 0, w, h);
549                 evas_object_size_hint_fill_set(img, EVAS_HINT_FILL, EVAS_HINT_FILL);
550                 evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
551         }
552
553         /*!
554          * \note
555          * object will be shown by below statement automatically
556          */
557         DbgPrint("%s part swallow image %p (%dx%d)\n", part, img, w, h);
558         child->obj = img;
559         edje_object_part_swallow(edje, part, img);
560         obj_info->children = eina_list_append(obj_info->children, child);
561
562         return LB_STATUS_SUCCESS;
563 }
564
565 static void script_signal_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
566 {
567         struct info *handle = data;
568         Evas_Coord w;
569         Evas_Coord h;
570         Evas_Coord px = 0;
571         Evas_Coord py = 0;
572         Evas_Coord pw = 0;
573         Evas_Coord ph = 0;
574         double sx;
575         double sy;
576         double ex;
577         double ey;
578
579         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
580         edje_object_part_geometry_get(obj, source, &px, &py, &pw, &ph);
581
582         sx = ex = 0.0f;
583         if (w) {
584                 sx = (double)px / (double)w;
585                 ex = (double)(px + pw) / (double)w;
586         }
587
588         sy = ey = 0.0f;
589         if (h) {
590                 sy = (double)py / (double)h;
591                 ey = (double)(py + ph) / (double)h;
592         }
593
594         DbgPrint("Signal emit: source[%s], emission[%s]\n", source, emission);
595         script_signal_emit(handle->e, source, emission, sx, sy, ex, ey);
596 }
597
598 static void edje_del_cb(void *_info, Evas *e, Evas_Object *obj, void *event_info)
599 {
600         struct info *handle = _info;
601         struct obj_info *obj_info;
602         struct child *child;
603
604         handle->obj_list = eina_list_remove(handle->obj_list, obj);
605
606         obj_info = evas_object_data_del(obj, "obj_info");
607         if (!obj_info) {
608                 ErrPrint("Object info is not valid\n");
609                 return;
610         }
611
612         DbgPrint("delete object %s %p\n", obj_info->id, obj);
613
614         edje_object_signal_callback_del_full(obj, "*", "*", script_signal_cb, handle);
615
616         EINA_LIST_FREE(obj_info->children, child) {
617                 DbgPrint("delete object %s %p\n", child->part, child->obj);
618                 if (child->obj)
619                         evas_object_del(child->obj);
620                 free(child->part);
621                 free(child);
622         }
623
624         free(obj_info->id);
625         free(obj_info);
626 }
627
628 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)
629 {
630         struct info *handle = h;
631         Evas_Object *edje;
632         Evas_Object *obj;
633         struct obj_info *obj_info;
634         struct child *child;
635
636         DbgPrint("src_id[%s] target_id[%s] part[%s] path[%s] group[%s]\n", src_id, target_id, part, path, group);
637
638         edje = find_edje(handle, src_id);
639         if (!edje) {
640                 ErrPrint("Edje is not exists\n");
641                 return LB_STATUS_ERROR_NOT_EXIST;
642         }
643
644         obj_info = evas_object_data_get(edje, "obj_info");
645         if (!obj_info) {
646                 ErrPrint("Object info is not valid\n");
647                 return LB_STATUS_ERROR_INVALID;
648         }
649
650         obj = edje_object_part_swallow_get(edje, part);
651         if (obj) {
652                 Eina_List *l;
653                 Eina_List *n;
654
655                 edje_object_part_unswallow(edje, obj);
656
657                 EINA_LIST_FOREACH_SAFE(obj_info->children, l, n, child) {
658                         if (child->obj != obj)
659                                 continue;
660
661                         obj_info->children = eina_list_remove(obj_info->children, child);
662                         free(child->part);
663                         free(child);
664                         break;
665                 }
666
667                 DbgPrint("delete object %s %p\n", part, obj);
668                 evas_object_del(obj);
669         }
670
671         if (!path || !strlen(path) || access(path, R_OK) != 0) {
672                 DbgPrint("SKIP - Path: [%s]\n", path);
673                 return LB_STATUS_SUCCESS;
674         }
675
676         obj = edje_object_add(e);
677         if (!obj) {
678                 ErrPrint("Failed to add a new edje object\n");
679                 return LB_STATUS_ERROR_FAULT;
680         }
681
682         if (!edje_object_file_set(obj, path, group)) {
683                 int err;
684                 const char *errmsg;
685
686                 err = edje_object_load_error_get(obj);
687                 errmsg = edje_load_error_str(err);
688                 ErrPrint("Could not load %s from %s: %s\n", group, path, errmsg);
689                 evas_object_del(obj);
690                 return LB_STATUS_ERROR_IO;
691         }
692
693         evas_object_show(obj);
694
695         obj_info = calloc(1, sizeof(*obj_info));
696         if (!obj_info) {
697                 ErrPrint("Failed to add a obj_info\n");
698                 evas_object_del(obj);
699                 return LB_STATUS_ERROR_MEMORY;
700         }
701
702         obj_info->id = strdup(target_id);
703         if (!obj_info->id) {
704                 ErrPrint("Failed to add a obj_info\n");
705                 free(obj_info);
706                 evas_object_del(obj);
707                 return LB_STATUS_ERROR_MEMORY;
708         }
709
710         child = malloc(sizeof(*child));
711         if (!child) {
712                 ErrPrint("Error: %s\n", strerror(errno));
713                 free(obj_info->id);
714                 free(obj_info);
715                 evas_object_del(obj);
716                 return LB_STATUS_ERROR_MEMORY;
717         }
718
719         child->part = strdup(part);
720         if (!child->part) {
721                 ErrPrint("Error: %s\n", strerror(errno));
722                 free(child);
723                 free(obj_info->id);
724                 free(obj_info);
725                 evas_object_del(obj);
726                 return LB_STATUS_ERROR_MEMORY;
727         }
728
729         child->obj = obj;
730
731         evas_object_data_set(obj, "obj_info", obj_info);
732         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, edje_del_cb, handle);
733         edje_object_signal_callback_add(obj, "*", "*", script_signal_cb, handle);
734         handle->obj_list = eina_list_append(handle->obj_list, obj);
735
736         DbgPrint("%s part swallow edje %p\n", part, obj);
737         edje_object_part_swallow(edje, part, obj);
738         obj_info = evas_object_data_get(edje, "obj_info");
739         obj_info->children = eina_list_append(obj_info->children, child);
740         return LB_STATUS_SUCCESS;
741 }
742
743 PUBLIC int script_update_signal(void *h, Evas *e, const char *id, const char *part, const char *signal)
744 {
745         struct info *handle = h;
746         Evas_Object *edje;
747
748         DbgPrint("id[%s], part[%s], signal[%s]\n", id, part, signal);
749
750         edje = find_edje(handle, id);
751         if (!edje)
752                 return LB_STATUS_ERROR_NOT_EXIST;
753
754         edje_object_signal_emit(edje, signal, part);
755         return LB_STATUS_SUCCESS;
756 }
757
758 PUBLIC int script_update_drag(void *h, Evas *e, const char *id, const char *part, double x, double y)
759 {
760         struct info *handle = h;
761         Evas_Object *edje;
762
763         DbgPrint("id[%s], part[%s], %lfx%lf\n", id, part, x, y);
764
765         edje = find_edje(handle, id);
766         if (!edje)
767                 return LB_STATUS_ERROR_NOT_EXIST;
768
769         edje_object_part_drag_value_set(edje, part, x, y);
770         return LB_STATUS_SUCCESS;
771 }
772
773 PUBLIC int script_update_size(void *han, Evas *e, const char *id, int w, int h)
774 {
775         struct info *handle = han;
776         Evas_Object *edje;
777
778         edje = find_edje(handle, id);
779         if (!edje)
780                 return LB_STATUS_ERROR_NOT_EXIST;
781
782         if (!id) {
783                 handle->w = w;
784                 handle->h = h;
785         }
786
787         DbgPrint("Resize object to %dx%d\n", w, h);
788         evas_object_resize(edje, w, h);
789         return LB_STATUS_SUCCESS;
790 }
791
792 PUBLIC int script_update_category(void *h, Evas *e, const char *id, const char *category)
793 {
794         struct info *handle = h;
795
796         DbgPrint("id[%s], category[%s]\n", id, category);
797
798         if (handle->category) {
799                 free(handle->category);
800                 handle->category = NULL;
801         }
802
803         if (!category)
804                 return LB_STATUS_SUCCESS;
805
806         handle->category = strdup(category);
807         if (!handle->category) {
808                 ErrPrint("Error: %s\n", strerror(errno));
809                 return LB_STATUS_ERROR_MEMORY;
810         }
811
812         return LB_STATUS_SUCCESS;
813 }
814
815 PUBLIC void *script_create(const char *file, const char *group)
816 {
817         struct info *handle;
818
819         DbgPrint("file[%s], group[%s]\n", file, group);
820
821         handle = calloc(1, sizeof(*handle));
822         if (!handle) {
823                 ErrPrint("Error: %s\n", strerror(errno));
824                 return NULL;
825         }
826
827         handle->file = strdup(file);
828         if (!handle->file) {
829                 ErrPrint("Error: %s\n", strerror(errno));
830                 free(handle);
831                 return NULL;
832         }
833
834         handle->group = strdup(group);
835         if (!handle->group) {
836                 ErrPrint("Error: %s\n", strerror(errno));
837                 free(handle->file);
838                 free(handle);
839                 return NULL;
840         }
841
842         return handle;
843 }
844
845 PUBLIC int script_destroy(void *_handle)
846 {
847         struct info *handle;
848         Evas_Object *edje;
849
850         handle = _handle;
851
852         edje = eina_list_nth(handle->obj_list, 0);
853         if (edje)
854                 evas_object_del(edje);
855
856         free(handle->category);
857         free(handle->file);
858         free(handle->group);
859         free(handle);
860         return LB_STATUS_SUCCESS;
861 }
862
863 PUBLIC int script_load(void *_handle, Evas *e, int w, int h)
864 {
865         struct info *handle;
866         Evas_Object *edje;
867         struct obj_info *obj_info;
868
869         handle = _handle;
870
871         obj_info = calloc(1, sizeof(*obj_info));
872         if (!obj_info) {
873                 ErrPrint("Heap: %s\n", strerror(errno));
874                 return LB_STATUS_ERROR_MEMORY;
875         }
876
877         edje = edje_object_add(e);
878         if (!edje) {
879                 ErrPrint("Failed to create an edje object\n");
880                 free(obj_info);
881                 return LB_STATUS_ERROR_FAULT;
882         }
883
884         DbgPrint("Load edje: %s - %s\n", handle->file, handle->group);
885         if (!edje_object_file_set(edje, handle->file, handle->group)) {
886                 int err;
887                 const char *errmsg;
888
889                 err = edje_object_load_error_get(edje);
890                 errmsg = edje_load_error_str(err);
891                 ErrPrint("Could not load %s from %s: %s\n", handle->group, handle->file, errmsg);
892                 evas_object_del(edje);
893                 free(obj_info);
894                 return LB_STATUS_ERROR_IO;
895         }
896
897         handle->e = e;
898         handle->w = w;
899         handle->h = h;
900
901         edje_object_signal_callback_add(edje, "*", "*", script_signal_cb, handle);
902         evas_object_event_callback_add(edje, EVAS_CALLBACK_DEL, edje_del_cb, handle);
903         evas_object_size_hint_weight_set(edje, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
904         evas_object_size_hint_fill_set(edje, EVAS_HINT_FILL, EVAS_HINT_FILL);
905         evas_object_resize(edje, handle->w, handle->h);
906         evas_object_show(edje);
907         evas_object_data_set(edje, "obj_info", obj_info);
908
909         handle->obj_list = eina_list_append(handle->obj_list, edje);
910         return LB_STATUS_SUCCESS;
911 }
912
913 PUBLIC int script_unload(void *_handle, Evas *e)
914 {
915         struct info *handle;
916         Evas_Object *edje;
917
918         handle = _handle;
919
920         DbgPrint("Unload edje: %s - %s\n", handle->file, handle->group);
921         edje = eina_list_nth(handle->obj_list, 0);
922         if (edje)
923                 evas_object_del(edje);
924         handle->e = NULL;
925         return LB_STATUS_SUCCESS;
926 }
927
928 static inline int update_font(const char *font)
929 {
930         Eina_List *list;
931         char *text;
932         int cache;
933
934         cache = evas_common_font_cache_get();
935         evas_common_font_cache_set(0);
936         evas_common_font_flush();
937
938         list = edje_text_class_list();
939         EINA_LIST_FREE(list, text) {
940                 if (!strncasecmp(text, TEXT_CLASS, strlen(TEXT_CLASS))) {
941                         edje_text_class_del(text);
942                         edje_text_class_set(text, s_info.font, s_info.size);
943                         DbgPrint("Update text class %s (%s, %d)\n", text, s_info.font, s_info.size);
944                 } else {
945                         DbgPrint("Skip text class %s\n", text);
946                 }
947         }
948         DbgPrint("Font for text_class is updated\n");
949
950         evas_common_font_cache_set(cache);
951         return LB_STATUS_SUCCESS;
952 }
953
954 static Eina_Bool property_cb(void *data, int type, void *event)
955 {
956         Ecore_X_Event_Window_Property *info = (Ecore_X_Event_Window_Property *)event;
957
958         if (info->atom == ecore_x_atom_get("FONT_TYPE_change") || info->atom == ecore_x_atom_get("BADA_FONT_change")) {
959                 char *font;
960
961                 font = vconf_get_str("db/setting/accessibility/font_name");
962                 if (!font)
963                         return ECORE_CALLBACK_PASS_ON;
964
965                 if (s_info.font && !strcmp(s_info.font, font)) {
966                         DbgPrint("Font is not changed (%s)\n", font);
967                         free(font);
968                         return ECORE_CALLBACK_PASS_ON;
969                 }
970
971                 if (s_info.font)
972                         free(s_info.font);
973
974                 s_info.font = font;
975
976                 update_font(font);
977         }
978
979         return ECORE_CALLBACK_PASS_ON;
980 }
981
982 static void font_name_cb(keynode_t *node, void *user_data)
983 {
984         const char *font;
985
986         if (!node)
987                 return;
988
989         font = vconf_keynode_get_str(node);
990         if (!font)
991                 return;
992
993         if (s_info.font && !strcmp(s_info.font, font)) {
994                 DbgPrint("Font is not changed\n");
995                 return;
996         }
997
998         DbgPrint("Font changed to %s\n", font);
999
1000         if (s_info.font)
1001                 free(s_info.font);
1002
1003         s_info.font = strdup(font);
1004         if (!s_info.font)
1005                 ErrPrint("Heap: %s\n", strerror(errno));
1006
1007         update_font(font);
1008 }
1009
1010 static void font_size_cb(keynode_t *node, void *user_data)
1011 {
1012         if (!node)
1013                 return;
1014         /*!
1015          * \TODO
1016          * Implementing me.
1017          */
1018         DbgPrint("Size type: %d\n", vconf_keynode_get_int(node));
1019 }
1020
1021 PUBLIC int script_init(void)
1022 {
1023         int ret;
1024         /* ecore is already initialized */
1025         edje_init();
1026         edje_scale_set(scale_get());
1027
1028         s_info.property_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, property_cb, NULL);
1029         if (!s_info.property_handler)
1030                 ErrPrint("Failed to add a property change event handler\n");
1031
1032         ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, font_size_cb, NULL);
1033         if (ret < 0)
1034                 ErrPrint("Failed to add vconf for font size change\n");
1035
1036         ret = vconf_notify_key_changed("db/setting/accessibility/font_name", font_name_cb, NULL);
1037         if (ret < 0)
1038                 ErrPrint("Failed to add vconf for font name change\n");
1039
1040         return LB_STATUS_SUCCESS;
1041 }
1042
1043 PUBLIC int script_fini(void)
1044 {
1045         vconf_ignore_key_changed("db/setting/accessibility/font_name", font_name_cb);
1046         vconf_ignore_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, font_size_cb);
1047         ecore_event_handler_del(s_info.property_handler);
1048         s_info.property_handler = NULL;
1049         edje_shutdown();
1050         return LB_STATUS_SUCCESS;
1051 }
1052
1053 /* End of a file */