Initialize the project.
[platform/framework/web/livebox-edje.git] / src / script_port.c
1 /*
2  * Copyright 2012  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
22 #include <Evas.h>
23 #include <Edje.h>
24 #include <Eina.h>
25 #include <Ecore.h>
26 #include <Ecore_Evas.h>
27 #include <Eet.h>
28 #include <Ecore_X.h>
29
30 #include <dlog.h>
31 #include <debug.h>
32 #include <vconf.h>
33
34 #include "script_port.h"
35
36 #define TEXT_CLASS      "slp"
37
38 extern void evas_common_font_flush(void);
39 extern int evas_common_font_cache_get(void);
40 extern void evas_common_font_cache_set(int size);
41
42 struct info {
43         char *file;
44         char *group;
45         char *category;
46         int w;
47         int h;
48
49         Evas *e;
50
51         Eina_List *obj_list;
52 };
53
54 struct child {
55         Evas_Object *obj;
56         char *part;
57 };
58
59 struct obj_info {
60         char *id;
61         Eina_List *children;
62 };
63
64 struct {
65         Ecore_Event_Handler *property_handler;
66         char *font;
67         int size;
68 } s_info = {
69         .property_handler = NULL,
70         .font = NULL,
71         .size = -100,
72 };
73
74 /*!
75  * \NOTE
76  * Reservce this for future use
77 static inline void common_cache_flush(void *evas)
78 {
79         int file_cache;
80         int collection_cache;
81         int image_cache;
82         int font_cache;
83
84         file_cache = edje_file_cache_get();
85         collection_cache = edje_collection_cache_get();
86         image_cache = evas_image_cache_get(evas);
87         font_cache = evas_font_cache_get(evas);
88
89         edje_file_cache_set(file_cache);
90         edje_collection_cache_set(collection_cache);
91         evas_image_cache_set(evas, 0);
92         evas_font_cache_set(evas, 0);
93
94         evas_image_cache_flush(evas);
95         evas_render_idle_flush(evas);
96         evas_font_cache_flush(evas);
97
98         edje_file_cache_flush();
99         edje_collection_cache_flush();
100
101         edje_file_cache_set(file_cache);
102         edje_collection_cache_set(collection_cache);
103         evas_image_cache_set(evas, image_cache);
104         evas_font_cache_set(evas, font_cache);
105
106         eet_clearcache();
107 }
108  */
109
110 static inline Evas_Object *find_edje(struct info *handle, const char *id)
111 {
112         Eina_List *l;
113         Evas_Object *edje;
114         struct obj_info *obj_info;
115
116         EINA_LIST_FOREACH(handle->obj_list, l, edje) {
117                 obj_info = evas_object_data_get(edje, "obj_info");
118                 if (!obj_info) {
119                         ErrPrint("Object info is not valid\n");
120                         continue;
121                 }
122
123                 if (!id) {
124                         if (!obj_info->id)
125                                 return edje;
126
127                         continue;
128                 } else if (!obj_info->id) {
129                         continue;
130                 }
131
132                 if (!strcmp(obj_info->id, id))
133                         return edje;
134         }
135
136         DbgPrint("EDJE[%s] is not found\n", id);
137         return NULL;
138 }
139
140 const char *script_magic_id(void)
141 {
142         return "edje";
143 }
144
145 int script_update_text(void *h, Evas *e, const char *id, const char *part, const char *text)
146 {
147         struct info *handle = h;
148         Evas_Object *edje;
149
150         edje = find_edje(handle, id);
151         if (!edje)
152                 return -ENOENT;
153
154         edje_object_part_text_set(edje, part, text);
155         return 0;
156 }
157
158 int script_update_image(void *_h, Evas *e, const char *id, const char *part, const char *path)
159 {
160         struct info *handle = _h;
161         Evas_Load_Error err;
162         Evas_Object *edje;
163         Evas_Object *img;
164         Evas_Coord w, h;
165         struct obj_info *obj_info;
166         struct child *child;
167
168         edje = find_edje(handle, id);
169         if (!edje) {
170                 ErrPrint("No such object: %s\n", id);
171                 return -ENOENT;
172         }
173
174         obj_info = evas_object_data_get(edje, "obj_info");
175         if (!obj_info) {
176                 ErrPrint("Object info is not available\n");
177                 return -EFAULT;
178         }
179
180         img = edje_object_part_swallow_get(edje, part);
181         if (img) {
182                 Eina_List *l;
183                 Eina_List *n;
184
185                 edje_object_part_unswallow(edje, img);
186
187                 EINA_LIST_FOREACH_SAFE(obj_info->children, l, n, child) {
188                         if (child->obj != img)
189                                 continue;
190
191                         obj_info->children = eina_list_remove(obj_info->children, child);
192                         free(child->part);
193                         free(child);
194                         break;
195                 }
196
197                 DbgPrint("delete object %s %p\n", part, img);
198                 evas_object_del(img);
199         }
200
201         if (!path || !strlen(path) || access(path, R_OK) != 0) {
202                 DbgPrint("SKIP - Path: [%s]\n", path);
203                 return 0;
204         }
205
206         child = malloc(sizeof(*child));
207         if (!child) {
208                 ErrPrint("Heap: %s\n", strerror(errno));
209                 return -ENOMEM;
210         }
211
212         child->part = strdup(part);
213         if (!child->part) {
214                 ErrPrint("Heap: %s\n", strerror(errno));
215                 free(child);
216                 return -ENOMEM;
217         }
218
219         img = evas_object_image_filled_add(e);
220         if (!img) {
221                 ErrPrint("Failed to add an image object\n");
222                 free(child->part);
223                 free(child);
224                 return -EFAULT;
225         }
226
227         child->obj = img;
228
229         evas_object_image_file_set(img, path, NULL);
230         err = evas_object_image_load_error_get(img);
231         if (err != EVAS_LOAD_ERROR_NONE) {
232                 ErrPrint("Load error: %s\n", evas_load_error_str(err));
233                 evas_object_del(img);
234                 free(child->part);
235                 free(child);
236                 return -EIO;
237         }
238
239         evas_object_image_size_get(img, &w, &h);
240         evas_object_image_fill_set(img, 0, 0, w, h);
241         evas_object_size_hint_fill_set(img, EVAS_HINT_FILL, EVAS_HINT_FILL);
242         evas_object_size_hint_weight_set(img, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
243         evas_object_resize(img, w, h);
244
245         /*!
246          * \note
247          * object will be shown by below statement automatically
248          */
249         DbgPrint("%s part swallow image %p\n", part, img);
250         edje_object_part_swallow(edje, part, img);
251         obj_info->children = eina_list_append(obj_info->children, child);
252
253         return 0;
254 }
255
256 static void script_signal_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
257 {
258         struct info *handle = data;
259         Evas_Coord w;
260         Evas_Coord h;
261         Evas_Coord px = 0;
262         Evas_Coord py = 0;
263         Evas_Coord pw = 0;
264         Evas_Coord ph = 0;
265         double sx;
266         double sy;
267         double ex;
268         double ey;
269
270         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
271         edje_object_part_geometry_get(obj, source, &px, &py, &pw, &ph);
272
273         sx = ex = 0.0f;
274         if (w) {
275                 sx = (double)px / (double)w;
276                 ex = (double)(px + pw) / (double)w;
277         }
278
279         sy = ey = 0.0f;
280         if (h) {
281                 sy = (double)py / (double)h;
282                 ey = (double)(py + ph) / (double)h;
283         }
284
285         DbgPrint("Signal emit: source[%s], emission[%s]\n", source, emission);
286         script_signal_emit(handle->e, source, emission, sx, sy, ex, ey);
287 }
288
289 static void edje_del_cb(void *_info, Evas *e, Evas_Object *obj, void *event_info)
290 {
291         struct info *handle = _info;
292         struct obj_info *obj_info;
293         struct child *child;
294
295         handle->obj_list = eina_list_remove(handle->obj_list, obj);
296
297         obj_info = evas_object_data_del(obj, "obj_info");
298         if (!obj_info) {
299                 ErrPrint("Object info is not valid\n");
300                 return;
301         }
302
303         DbgPrint("delete object %s %p\n", obj_info->id, obj);
304
305         edje_object_signal_callback_del_full(obj, "*", "*", script_signal_cb, handle);
306
307         EINA_LIST_FREE(obj_info->children, child) {
308                 DbgPrint("delete object %s %p\n", child->part, child->obj);
309                 if (child->obj)
310                         evas_object_del(child->obj);
311                 free(child->part);
312                 free(child);
313         }
314
315         free(obj_info->id);
316         free(obj_info);
317 }
318
319 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)
320 {
321         struct info *handle = h;
322         Evas_Object *edje;
323         Evas_Object *obj;
324         struct obj_info *obj_info;
325         struct child *child;
326
327         DbgPrint("src_id[%s] target_id[%s] part[%s] path[%s] group[%s]\n", src_id, target_id, part, path, group);
328
329         edje = find_edje(handle, src_id);
330         if (!edje) {
331                 ErrPrint("Edje is not exists\n");
332                 return -ENOENT;
333         }
334
335         obj_info = evas_object_data_get(edje, "obj_info");
336         if (!obj_info) {
337                 ErrPrint("Object info is not valid\n");
338                 return -EINVAL;
339         }
340
341         obj = edje_object_part_swallow_get(edje, part);
342         if (obj) {
343                 Eina_List *l;
344                 Eina_List *n;
345
346                 edje_object_part_unswallow(edje, obj);
347
348                 EINA_LIST_FOREACH_SAFE(obj_info->children, l, n, child) {
349                         if (child->obj != obj)
350                                 continue;
351
352                         obj_info->children = eina_list_remove(obj_info->children, child);
353                         free(child->part);
354                         free(child);
355                         break;
356                 }
357
358                 DbgPrint("delete object %s %p\n", part, obj);
359                 evas_object_del(obj);
360         }
361
362         if (!path || !strlen(path) || access(path, R_OK) != 0) {
363                 DbgPrint("SKIP - Path: [%s]\n", path);
364                 return 0;
365         }
366
367         obj = edje_object_add(e);
368         if (!obj) {
369                 ErrPrint("Failed to add a new edje object\n");
370                 return -EFAULT;
371         }
372
373         //edje_object_text_class_set(obj, TEXT_CLASS, s_info.font, s_info.size);
374         if (!edje_object_file_set(obj, path, group)) {
375                 int err;
376                 const char *errmsg;
377
378                 err = edje_object_load_error_get(obj);
379                 errmsg = edje_load_error_str(err);
380                 ErrPrint("Could not load %s from %s: %s\n", group, path, errmsg);
381                 evas_object_del(obj);
382                 return -EIO;
383         }
384
385         evas_object_show(obj);
386
387         obj_info = calloc(1, sizeof(*obj_info));
388         if (!obj_info) {
389                 ErrPrint("Failed to add a obj_info\n");
390                 evas_object_del(obj);
391                 return -ENOMEM;
392         }
393
394         obj_info->id = strdup(target_id);
395         if (!obj_info->id) {
396                 ErrPrint("Failed to add a obj_info\n");
397                 free(obj_info);
398                 evas_object_del(obj);
399                 return -ENOMEM;
400         }
401
402         child = malloc(sizeof(*child));
403         if (!child) {
404                 ErrPrint("Error: %s\n", strerror(errno));
405                 free(obj_info->id);
406                 free(obj_info);
407                 evas_object_del(obj);
408                 return -ENOMEM;
409         }
410
411         child->part = strdup(part);
412         if (!child->part) {
413                 ErrPrint("Error: %s\n", strerror(errno));
414                 free(child);
415                 free(obj_info->id);
416                 free(obj_info);
417                 evas_object_del(obj);
418                 return -ENOMEM;
419         }
420
421         child->obj = obj;
422
423         evas_object_data_set(obj, "obj_info", obj_info);
424         evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, edje_del_cb, handle);
425         edje_object_signal_callback_add(obj, "*", "*", script_signal_cb, handle);
426         handle->obj_list = eina_list_append(handle->obj_list, obj);
427
428         DbgPrint("%s part swallow edje %p\n", part, obj);
429         edje_object_part_swallow(edje, part, obj);
430         obj_info = evas_object_data_get(edje, "obj_info");
431         obj_info->children = eina_list_append(obj_info->children, child);
432         return 0;
433 }
434
435 int script_update_signal(void *h, Evas *e, const char *id, const char *part, const char *signal)
436 {
437         struct info *handle = h;
438         Evas_Object *edje;
439
440         DbgPrint("id[%s], part[%s], signal[%s]\n", id, part, signal);
441
442         edje = find_edje(handle, id);
443         if (!edje)
444                 return -ENOENT;
445
446         edje_object_signal_emit(edje, signal, part);
447         return 0;
448 }
449
450 int script_update_drag(void *h, Evas *e, const char *id, const char *part, double x, double y)
451 {
452         struct info *handle = h;
453         Evas_Object *edje;
454
455         DbgPrint("id[%s], part[%s], %lfx%lf\n", id, part, x, y);
456
457         edje = find_edje(handle, id);
458         if (!edje)
459                 return -ENOENT;
460
461         edje_object_part_drag_value_set(edje, part, x, y);
462         return 0;
463 }
464
465 int script_update_size(void *han, Evas *e, const char *id, int w, int h)
466 {
467         struct info *handle = han;
468         Evas_Object *edje;
469
470         edje = find_edje(handle, id);
471         if (!edje)
472                 return -ENOENT;
473
474         if (!id) {
475                 handle->w = w;
476                 handle->h = h;
477         }
478
479         DbgPrint("Resize object to %dx%d\n", w, h);
480         evas_object_resize(edje, w, h);
481         return 0;
482 }
483
484 int script_update_category(void *h, Evas *e, const char *id, const char *category)
485 {
486         struct info *handle = h;
487
488         DbgPrint("id[%s], category[%s]\n", id, category);
489
490         if (handle->category) {
491                 free(handle->category);
492                 handle->category = NULL;
493         }
494
495         if (!category)
496                 return 0;
497
498         handle->category = strdup(category);
499         if (!handle->category) {
500                 ErrPrint("Error: %s\n", strerror(errno));
501                 return -ENOMEM;
502         }
503
504         return 0;
505 }
506
507 void *script_create(const char *file, const char *group)
508 {
509         struct info *handle;
510
511         DbgPrint("file[%s], group[%s]\n", file, group);
512
513         handle = calloc(1, sizeof(*handle));
514         if (!handle) {
515                 ErrPrint("Error: %s\n", strerror(errno));
516                 return NULL;
517         }
518
519         handle->file = strdup(file);
520         if (!handle->file) {
521                 ErrPrint("Error: %s\n", strerror(errno));
522                 free(handle);
523                 return NULL;
524         }
525
526         handle->group = strdup(group);
527         if (!handle->group) {
528                 ErrPrint("Error: %s\n", strerror(errno));
529                 free(handle->file);
530                 free(handle);
531                 return NULL;
532         }
533
534         return handle;
535 }
536
537 int script_destroy(void *_handle)
538 {
539         struct info *handle;
540         Evas_Object *edje;
541
542         handle = _handle;
543
544         edje = eina_list_nth(handle->obj_list, 0);
545         if (edje)
546                 evas_object_del(edje);
547
548         free(handle->category);
549         free(handle->file);
550         free(handle->group);
551         free(handle);
552         return 0;
553 }
554
555 int script_load(void *_handle, Evas *e, int w, int h)
556 {
557         struct info *handle;
558         Evas_Object *edje;
559         struct obj_info *obj_info;
560
561         handle = _handle;
562
563         obj_info = calloc(1, sizeof(*obj_info));
564         if (!obj_info) {
565                 ErrPrint("Heap: %s\n", strerror(errno));
566                 return -ENOMEM;
567         }
568
569         edje = edje_object_add(e);
570         if (!edje) {
571                 ErrPrint("Failed to create an edje object\n");
572                 free(obj_info);
573                 return -EFAULT;
574         }
575
576         //edje_object_text_class_set(edje, TEXT_CLASS, s_info.font, s_info.size);
577         DbgPrint("Load edje: %s - %s\n", handle->file, handle->group);
578         if (!edje_object_file_set(edje, handle->file, handle->group)) {
579                 int err;
580                 const char *errmsg;
581
582                 err = edje_object_load_error_get(edje);
583                 errmsg = edje_load_error_str(err);
584                 ErrPrint("Could not load %s from %s: %s\n", handle->group, handle->file, errmsg);
585                 evas_object_del(edje);
586                 free(obj_info);
587                 return -EIO;
588         }
589
590         handle->e = e;
591         handle->w = w;
592         handle->h = h;
593
594         edje_object_signal_callback_add(edje, "*", "*", script_signal_cb, handle);
595         evas_object_event_callback_add(edje, EVAS_CALLBACK_DEL, edje_del_cb, handle);
596         evas_object_size_hint_weight_set(edje, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
597         evas_object_size_hint_fill_set(edje, EVAS_HINT_FILL, EVAS_HINT_FILL);
598         evas_object_resize(edje, handle->w, handle->h);
599         evas_object_show(edje);
600         evas_object_data_set(edje, "obj_info", obj_info);
601
602         handle->obj_list = eina_list_append(handle->obj_list, edje);
603         return 0;
604 }
605
606 int script_unload(void *_handle, Evas *e)
607 {
608         struct info *handle;
609         Evas_Object *edje;
610
611         handle = _handle;
612
613         DbgPrint("Unload edje: %s - %s\n", handle->file, handle->group);
614         edje = eina_list_nth(handle->obj_list, 0);
615         if (edje)
616                 evas_object_del(edje);
617         handle->e = NULL;
618         return 0;
619 }
620
621 static Eina_Bool property_cb(void *data, int type, void *event)
622 {
623         Ecore_X_Event_Window_Property *info = (Ecore_X_Event_Window_Property *)event;
624
625         if (info->atom == ecore_x_atom_get("FONT_TYPE_change") || info->atom == ecore_x_atom_get("BADA_FONT_change")) {
626                 Eina_List *list;
627                 char *text;
628                 char *font;
629                 int cache;
630
631                 font = vconf_get_str("db/setting/accessibility/font_name");
632                 if (!font)
633                         return ECORE_CALLBACK_PASS_ON;
634
635                 if (s_info.font)
636                         free(s_info.font);
637
638                 s_info.font = font;
639
640                 cache = evas_common_font_cache_get();
641                 evas_common_font_cache_set(0);
642                 evas_common_font_flush();
643
644                 list = edje_text_class_list();
645                 EINA_LIST_FREE(list, text) {
646                         if (!strncasecmp(text, TEXT_CLASS, strlen(TEXT_CLASS))) {
647                                 edje_text_class_del(text);
648                                 edje_text_class_set(text, s_info.font, s_info.size);
649                                 DbgPrint("Update text class %s (%s, %d)\n", text, s_info.font, s_info.size);
650                         } else {
651                                 DbgPrint("Skip text class %s\n", text);
652                         }
653                 }
654
655                 evas_common_font_cache_set(cache);
656         }
657
658         return ECORE_CALLBACK_PASS_ON;
659 }
660
661 static void font_name_cb(keynode_t *node, void *user_data)
662 {
663         const char *font;
664
665         if (!node)
666                 return;
667
668         font = vconf_keynode_get_str(node);
669         if (!font)
670                 return;
671
672         DbgPrint("Font changed to %s\n", font);
673 }
674
675 static void font_size_cb(keynode_t *node, void *user_data)
676 {
677         if (!node)
678                 return;
679         /*!
680          * \TODO
681          * Implementing me.
682          */
683         DbgPrint("Size type: %d\n", vconf_keynode_get_int(node));
684 }
685
686 int script_init(void)
687 {
688         int ret;
689         /* ecore is already initialized */
690         edje_init();
691
692         s_info.property_handler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, property_cb, NULL);
693         if (!s_info.property_handler)
694                 ErrPrint("Failed to add a property change event handler\n");
695
696         ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, font_size_cb, NULL);
697         if (ret < 0)
698                 ErrPrint("Failed to add vconf for font size change\n");
699
700         ret = vconf_notify_key_changed("db/setting/accessibility/font_name", font_name_cb, NULL);
701         if (ret < 0)
702                 ErrPrint("Failed to add vconf for font name change\n");
703
704         return 0;
705 }
706
707 int script_fini(void)
708 {
709
710         vconf_ignore_key_changed("db/setting/accessibility/font_name", font_name_cb);
711         vconf_ignore_key_changed(VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, font_size_cb);
712         ecore_event_handler_del(s_info.property_handler);
713         s_info.property_handler = NULL;
714         edje_shutdown();
715         return 0;
716 }
717
718 /* End of a file */