tizen 2.3 release
[apps/livebox/data-provider-master.git] / src / script_handler.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.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 <errno.h>
19 #include <stdlib.h> /* free */
20 #include <ctype.h>
21 #include <dlfcn.h>
22 #include <sys/types.h>
23 #include <dirent.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29
30 #include <Ecore.h>
31 #include <Eina.h>
32
33 #include <dlog.h>
34 #include <packet.h>
35 #include <dynamicbox_errno.h>
36 #include <dynamicbox_service.h>
37 #include <dynamicbox_conf.h>
38
39 #include "slave_life.h"
40 #include "slave_rpc.h"
41 #include "client_life.h"
42 #include "package.h"
43 #include "instance.h"
44 #include "buffer_handler.h"
45 #include "script_handler.h"
46 #include "debug.h"
47 #include "conf.h"
48 #include "util.h"
49
50 #define INFO_SIZE "size"
51 #define INFO_CATEGORY "category"
52
53 static const char *type_list[] = {
54         "access",
55         "access,operation",
56         "color",
57         "drag",
58         "image",
59         "info",
60         "script",
61         "signal",
62         "text",
63         NULL
64 };
65
66 static const char *field_list[] = {
67         "type",
68         "part",
69         "data",
70         "option",
71         "id",
72         "target",
73         "file",
74         NULL
75 };
76
77 int errno;
78
79 static struct info {
80         Eina_List *script_port_list;
81         enum dynamicbox_fb_type env_buf_type;
82 } s_info = {
83         .script_port_list = NULL,
84         .env_buf_type = DBOX_FB_TYPE_FILE,
85 };
86
87 struct script_port {
88         void *handle;
89
90         const char *(*magic_id)(void);
91         int (*update_color)(void *handle, const char *id, const char *part, const char *rgba);
92         int (*update_text)(void *handle, const char *id, const char *part, const char *text);
93         int (*update_image)(void *handle, const char *id, const char *part, const char *path, const char *option);
94         int (*update_access)(void *handle, const char *id, const char *part, const char *text, const char *option);
95         int (*operate_access)(void *handle, const char *id, const char *part, const char *operation, const char *option);
96         int (*update_script)(void *handle, const char *src_id, const char *target_id, const char *part, const char *path, const char *option);
97         int (*update_signal)(void *handle, const char *id, const char *part, const char *signal);
98         int (*update_drag)(void *handle, const char *id, const char *part, double x, double y);
99         int (*update_size)(void *handle, const char *id, int w, int h);
100         int (*update_category)(void *handle, const char *id, const char *category);
101         int (*feed_event)(void *handle, int event_type, int x, int y, int down, unsigned int keycode, double timestamp);
102
103         void *(*create)(void *buffer_info, const char *file, const char *option);
104         int (*destroy)(void *handle);
105
106         int (*load)(void *handle, int (*render_pre)(void *buffer_info, void *data), int (*render_post)(void *buffer_info, void *data), void *data);
107         int (*unload)(void *handle);
108
109         int (*init)(double scale, int premultiplied);
110         int (*fini)(void);
111 };
112
113 enum block_type {
114         TYPE_ACCESS,
115         TYPE_ACCESS_OP,
116         TYPE_COLOR,
117         TYPE_DRAG,
118         TYPE_IMAGE,
119         TYPE_INFO,
120         TYPE_SCRIPT,
121         TYPE_SIGNAL,
122         TYPE_TEXT,
123         TYPE_MAX
124 };
125
126 enum field_type {
127         FIELD_TYPE,
128         FIELD_PART,
129         FIELD_DATA,
130         FIELD_OPTION,
131         FIELD_ID,
132         FIELD_TARGET,
133         FIELD_FILE
134 };
135
136 struct block {
137         enum block_type type;
138         char *part;
139         char *data;
140         char *option;
141         char *id;
142         char *target;
143         char *file;
144
145         /* Should be released */
146         char *filebuf;
147         const char *filename;
148 };
149
150 struct script_info {
151         struct buffer_info *buffer_handle; 
152         int loaded;
153
154         int w;
155         int h;
156
157         int x;
158         int y;
159         int down;
160
161         unsigned int keycode;
162
163         struct script_port *port;
164         void *port_data;
165
166         Eina_List *cached_blocks;
167 };
168
169 static inline void consuming_parsed_block(struct inst_info *inst, int is_pd, struct block *block);
170
171 static int load_all_ports(void)
172 {
173         struct script_port *item;
174         struct dirent *ent;
175         DIR *dir;
176         char *path;
177         int pathlen;
178
179         dir = opendir(DYNAMICBOX_CONF_SCRIPT_PORT_PATH);
180         if (!dir) {
181                 ErrPrint("Error: %s\n", strerror(errno));
182                 return DBOX_STATUS_ERROR_IO_ERROR;
183         }
184
185         while ((ent = readdir(dir))) {
186                 if (ent->d_name[0] == '.') {
187                         continue;
188                 }
189
190                 pathlen = strlen(ent->d_name) + strlen(DYNAMICBOX_CONF_SCRIPT_PORT_PATH) + 1;
191                 path = malloc(pathlen);
192                 if (!path) {
193                         ErrPrint("Heap: %s %d\n", strerror(errno), pathlen);
194                         if (closedir(dir) < 0) {
195                                 ErrPrint("closedir: %s\n", strerror(errno));
196                         }
197                         return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
198                 }
199
200                 snprintf(path, pathlen, "%s%s", DYNAMICBOX_CONF_SCRIPT_PORT_PATH, ent->d_name);
201
202                 item = malloc(sizeof(*item));
203                 if (!item) {
204                         ErrPrint("Heap: %s\n", strerror(errno));
205                         DbgFree(path);
206                         if (closedir(dir) < 0) {
207                                 ErrPrint("closedir: %s\n", strerror(errno));
208                         }
209                         return DBOX_STATUS_ERROR_OUT_OF_MEMORY;
210                 }
211
212                 DbgPrint("Open SCRIPT PORT: %s\n", path);
213                 item->handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW | RTLD_DEEPBIND);
214                 DbgFree(path);
215                 if (!item->handle) {
216                         ErrPrint("Error: %s\n", dlerror());
217                         DbgFree(item);
218                         if (closedir(dir) < 0) {
219                                 ErrPrint("closedir: %s\n", strerror(errno));
220                         }
221                         return DBOX_STATUS_ERROR_FAULT;
222                 }
223
224                 item->magic_id = dlsym(item->handle, "script_magic_id");
225                 if (!item->magic_id) {
226                         goto errout;
227                 }
228
229                 DbgPrint("SCRIPT PORT magic id: %s\n", item->magic_id());
230
231                 item->update_color = dlsym(item->handle, "script_update_color");
232                 if (!item->update_color) {
233                         goto errout;
234                 }
235
236                 item->update_text = dlsym(item->handle, "script_update_text");
237                 if (!item->update_text) {
238                         goto errout;
239                 }
240
241                 item->update_image = dlsym(item->handle, "script_update_image");
242                 if (!item->update_image) {
243                         goto errout;
244                 }
245
246                 item->update_access = dlsym(item->handle, "script_update_access");
247                 if (!item->update_access) {
248                         goto errout;
249                 }
250
251                 item->operate_access = dlsym(item->handle, "script_operate_access");
252                 if (!item->operate_access) {
253                         goto errout;
254                 }
255
256                 item->update_script = dlsym(item->handle, "script_update_script");
257                 if (!item->update_script) {
258                         goto errout;
259                 }
260
261                 item->update_signal = dlsym(item->handle, "script_update_signal");
262                 if (!item->update_signal) {
263                         goto errout;
264                 }
265
266                 item->update_drag = dlsym(item->handle, "script_update_drag");
267                 if (!item->update_drag) {
268                         goto errout;
269                 }
270
271                 item->update_size = dlsym(item->handle, "script_update_size");
272                 if (!item->update_size) {
273                         goto errout;
274                 }
275
276                 item->update_category = dlsym(item->handle, "script_update_category");
277                 if (!item->update_category) {
278                         goto errout;
279                 }
280
281                 item->create = dlsym(item->handle, "script_create");
282                 if (!item->create) {
283                         goto errout;
284                 }
285
286                 item->destroy = dlsym(item->handle, "script_destroy");
287                 if (!item->destroy) {
288                         goto errout;
289                 }
290
291                 item->load = dlsym(item->handle, "script_load");
292                 if (!item->load) {
293                         goto errout;
294                 }
295
296                 item->unload = dlsym(item->handle, "script_unload");
297                 if (!item->unload) {
298                         goto errout;
299                 }
300
301                 item->init = dlsym(item->handle, "script_init");
302                 if (!item->init) {
303                         goto errout;
304                 }
305
306                 item->fini = dlsym(item->handle, "script_fini");
307                 if (!item->fini) {
308                         goto errout;
309                 }
310
311                 item->feed_event = dlsym(item->handle, "script_feed_event");
312                 if (!item->feed_event) {
313                         goto errout;
314                 }
315
316                 if (item->init(DYNAMICBOX_CONF_SCALE_WIDTH_FACTOR, DYNAMICBOX_CONF_PREMULTIPLIED_COLOR) < 0) {
317                         ErrPrint("Failed to initialize script engine\n");
318                         goto errout;
319                 }
320
321                 s_info.script_port_list = eina_list_append(s_info.script_port_list, item);
322         }
323
324         if (closedir(dir) < 0) {
325                 ErrPrint("closedir: %s\n", strerror(errno));
326         }
327
328         return DBOX_STATUS_ERROR_NONE;
329
330 errout:
331         ErrPrint("Error: %s\n", dlerror());
332         if (dlclose(item->handle) != 0) {
333                 ErrPrint("dlclose: %s\n", strerror(errno));
334         }
335         DbgFree(item);
336         if (closedir(dir) < 0) {
337                 ErrPrint("closedir: %s\n", strerror(errno));
338         }
339         return DBOX_STATUS_ERROR_FAULT;
340 }
341
342 static inline struct script_port *find_port(const char *magic_id)
343 {
344         Eina_List *l;
345         struct script_port *item;
346
347         if (!s_info.script_port_list) {
348                 int ret;
349
350                 ret = load_all_ports();
351                 if (ret < 0) {
352                         ErrPrint("load_all_ports: %d\n", ret);
353                 }
354         }
355
356         EINA_LIST_FOREACH(s_info.script_port_list, l, item) {
357                 if (!strcmp(item->magic_id(), magic_id)) {
358                         return item;
359                 }
360         }
361
362         return NULL;
363 }
364
365 static inline void delete_block(struct block *block)
366 {
367         DbgFree(block->filebuf);
368         DbgFree(block);
369 }
370
371 static int render_post_cb(void *_buffer_handle, void *data)
372 {
373         PERF_INIT();
374         PERF_BEGIN();
375         struct inst_info *inst;
376         struct buffer_info *buffer_handle = _buffer_handle;
377         struct script_info *info;
378
379         inst = buffer_handler_instance(buffer_handle);
380         if (!inst) {
381                 goto out;
382         }
383
384         if (instance_state(inst) != INST_ACTIVATED) {
385                 ErrPrint("Render post invoked but instance is not activated\n");
386                 PERF_MARK(__func__);
387                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
388         }
389
390         info = instance_dbox_script(inst);
391         if (info && info == data) {
392                 buffer_handler_flush(buffer_handle);
393                 instance_dbox_updated_by_instance(inst, NULL, info->x, info->y, info->w, info->h);
394                 PERF_MARK("lb,update");
395                 return DBOX_STATUS_ERROR_NONE;
396         }
397
398         info = instance_gbar_script(inst);
399         if (info && info == data) {
400                 buffer_handler_flush(buffer_handle);
401                 instance_gbar_updated_by_instance(inst, NULL, info->x, info->y, info->w, info->h);
402                 PERF_MARK("pd,update");
403                 return DBOX_STATUS_ERROR_NONE;
404         }
405
406 out:
407         ErrPrint("Failed to sync\n");
408         PERF_MARK(__func__);
409         return DBOX_STATUS_ERROR_FAULT;
410 }
411
412 /*!
413  * \NOTE
414  * Exported API
415  */
416 EAPI int script_signal_emit(void *buffer_handle, const char *part, const char *signal, double sx, double sy, double ex, double ey)
417 {
418         struct script_info *info;
419         struct inst_info *inst;
420         int w;
421         int h;
422         double fx;
423         double fy;
424
425         if (!buffer_handle) {
426                 ErrPrint("Invalid handle\n");
427                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
428         }
429
430         info = buffer_handler_data(buffer_handle);
431         if (!info) {
432                 ErrPrint("Invalid handle\n");
433                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
434         }
435
436         inst = buffer_handler_instance(buffer_handle);
437         if (!inst) {
438                 return DBOX_STATUS_ERROR_FAULT;
439         }
440
441         if (!signal || strlen(signal) == 0) {
442                 signal = "";
443         }
444
445         if (!part || strlen(part) == 0) {
446                 part = "";
447         }
448
449         buffer_handler_get_size(buffer_handle, &w, &h);
450
451         fx = (double)info->x / (double)w;
452         fy = (double)info->y / (double)h;
453
454         return instance_signal_emit(inst, signal, part, sx, sy, ex, ey, fx, fy, info->down);
455 }
456
457 static inline void flushing_cached_block(struct script_info *info)
458 {
459         struct block *block;
460         struct inst_info *inst;
461         int is_pd;
462
463         inst = buffer_handler_instance(info->buffer_handle);
464         if (!inst) {
465                 ErrPrint("Instance is not valid\n");
466                 EINA_LIST_FREE(info->cached_blocks, block) {
467                         delete_block(block);
468                 }
469                 return;
470         }
471
472         is_pd = instance_gbar_script(inst) == info;
473
474         EINA_LIST_FREE(info->cached_blocks, block) {
475                 consuming_parsed_block(inst, is_pd, block);
476         }
477 }
478
479 HAPI int script_handler_load(struct script_info *info, int is_pd)
480 {
481         struct inst_info *inst;
482
483         if (!info || !info->port) {
484                 ErrPrint("Script handler is not created\n");
485                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
486         }
487
488         if (info->loaded > 0) {
489                 info->loaded++;
490                 return DBOX_STATUS_ERROR_NONE;
491         }
492
493         if (info->port->load(info->port_data, NULL, render_post_cb, info) < 0) {
494                 ErrPrint("Unable to load the script\n");
495                 return DBOX_STATUS_ERROR_FAULT;
496         }
497
498         info->loaded = 1;
499         flushing_cached_block(info);
500
501         inst = buffer_handler_instance(info->buffer_handle);
502         if (inst) {
503                 script_signal_emit(info->buffer_handle, instance_id(inst),
504                                 is_pd ? "gbar,show" : "dbox,show", 0.0f, 0.0f, 0.0f, 0.0f);
505         }
506         buffer_handler_flush(info->buffer_handle);
507         return DBOX_STATUS_ERROR_NONE;
508 }
509
510 HAPI int script_handler_unload(struct script_info *info, int is_pd)
511 {
512         struct inst_info *inst;
513
514         if (!info || !info->port) {
515                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
516         }
517
518         info->loaded--;
519         if (info->loaded > 0) {
520                 return DBOX_STATUS_ERROR_BUSY;
521         }
522
523         if (info->loaded < 0) {
524                 info->loaded = 0;
525                 return DBOX_STATUS_ERROR_ALREADY;
526         }
527
528         inst = buffer_handler_instance(info->buffer_handle);
529         if (inst) {
530                 script_signal_emit(info->buffer_handle, instance_id(inst),
531                                 is_pd ? "gbar,hide" : "dbox,hide", 0.0f, 0.0f, 0.0f, 0.0f);
532         }
533
534         if (info->port->unload(info->port_data) < 0) {
535                 ErrPrint("Failed to unload script object. but go ahead\n");
536         }
537
538         return DBOX_STATUS_ERROR_NONE;
539 }
540
541 HAPI struct script_info *script_handler_create(struct inst_info *inst, const char *file, const char *option, int w, int h)
542 {
543         struct script_info *info;
544
545         DbgPrint("Create script: %s (%s) %dx%d\n", file, option, w, h);
546
547         if (!file) {
548                 return NULL;
549         }
550
551         info = calloc(1, sizeof(*info));
552         if (!info) {
553                 ErrPrint("Heap: %s\n", strerror(errno));
554                 return NULL;
555         }
556
557         info->buffer_handle = buffer_handler_create(inst, s_info.env_buf_type, w, h, DYNAMICBOX_CONF_DEFAULT_PIXELS);
558         if (!info->buffer_handle) {
559                 /* buffer_handler_create will prints some log */
560                 DbgFree(info);
561                 return NULL;
562         }
563
564         (void)buffer_handler_set_data(info->buffer_handle, info);
565
566         info->port = find_port(package_script(instance_package(inst)));
567         if (!info->port) {
568                 ErrPrint("Failed to find a proper port for [%s]%s\n",
569                                 instance_package(inst), package_script(instance_package(inst)));
570                 buffer_handler_destroy(info->buffer_handle);
571                 DbgFree(info);
572                 return NULL;
573         }
574
575         info->port_data = info->port->create(info->buffer_handle, file, option);
576         if (!info->port_data) {
577                 ErrPrint("Failed to create a port (%s - %s)\n", file, option);
578                 buffer_handler_destroy(info->buffer_handle);
579                 DbgFree(info);
580                 return NULL;
581         }
582
583         return info;
584 }
585
586 HAPI int script_handler_destroy(struct script_info *info)
587 {
588         struct block *block;
589         int ret;
590
591         if (!info || !info->port) {
592                 ErrPrint("port is not valid\n");
593                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
594         }
595
596         if (info->loaded != 0) {
597                 ErrPrint("Script handler is not unloaded\n");
598                 return DBOX_STATUS_ERROR_BUSY;
599         }
600
601         ret = info->port->destroy(info->port_data);
602         if (ret < 0) {
603                 ErrPrint("Failed to destroy port, but go ahead: %d\n", ret);
604         }
605
606         (void)buffer_handler_destroy(info->buffer_handle);
607
608         EINA_LIST_FREE(info->cached_blocks, block) {
609                 delete_block(block);
610         }
611
612         DbgFree(info);
613         return DBOX_STATUS_ERROR_NONE;
614 }
615
616 HAPI int script_handler_is_loaded(struct script_info *info)
617 {
618         return info ? info->loaded > 0 : 0;
619 }
620
621 HAPI struct buffer_info *script_handler_buffer_info(struct script_info *info)
622 {
623         if (!info) {
624                 return NULL;
625         }
626
627         return info->buffer_handle;
628 }
629
630 static int update_script_color(struct inst_info *inst, struct block *block, int is_pd)
631 {
632         PERF_INIT();
633         PERF_BEGIN();
634         struct script_info *info;
635         int ret;
636
637         if (!block || !block->part || !block->data) {
638                 ErrPrint("Block or part or data is not valid\n");
639                 PERF_MARK("color");
640                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
641         }
642
643         info = is_pd ? instance_gbar_script(inst) : instance_dbox_script(inst);
644         if (!info) {
645                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
646                 PERF_MARK("color");
647                 return DBOX_STATUS_ERROR_FAULT;
648         }
649
650         if (!info->port) {
651                 ErrPrint("info->port is NIL (%d, %s)\n", is_pd, instance_id(inst));
652                 PERF_MARK("color");
653                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
654         }
655
656         ret = info->port->update_color(info->port_data, block->id, block->part, block->data);
657         PERF_MARK("color");
658         return ret;
659 }
660
661 static int update_script_text(struct inst_info *inst, struct block *block, int is_pd)
662 {
663         PERF_INIT();
664         PERF_BEGIN();
665         struct script_info *info;
666         int ret;
667
668         if (!block || !block->part || !block->data) {
669                 ErrPrint("Block or part or data is not valid\n");
670                 PERF_MARK("text");
671                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
672         }
673
674         info = is_pd ? instance_gbar_script(inst) : instance_dbox_script(inst);
675         if (!info) {
676                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
677                 PERF_MARK("text");
678                 return DBOX_STATUS_ERROR_FAULT;
679         }
680
681         if (!info->port) {
682                 ErrPrint("info->port is NIL\n");
683                 PERF_MARK("text");
684                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
685         }
686
687         DbgPrint("[%s] %s (%s)\n", block->id, block->part, block->data);
688         ret = info->port->update_text(info->port_data, block->id, block->part, block->data);
689
690         PERF_MARK("text");
691         return ret;
692 }
693
694 static int update_script_image(struct inst_info *inst, struct block *block, int is_pd)
695 {
696         PERF_INIT();
697         PERF_BEGIN();
698         struct script_info *info;
699         int ret;
700
701         if (!block || !block->part) {
702                 ErrPrint("Block or part is not valid\n");
703                 PERF_MARK("image");
704                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
705         }
706
707         info = is_pd ? instance_gbar_script(inst) : instance_dbox_script(inst);
708         if (!info) {
709                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
710                 PERF_MARK("image");
711                 return DBOX_STATUS_ERROR_FAULT;
712         }
713
714         if (!info->port) {
715                 ErrPrint("info->port is NIL\n");
716                 PERF_MARK("image");
717                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
718         }
719
720         DbgPrint("[%s] %s (%s)\n", block->id, block->part, block->data);
721         ret = info->port->update_image(info->port_data, block->id, block->part, block->data, block->option);
722         PERF_MARK("image");
723         return ret;
724 }
725
726 static int update_access(struct inst_info *inst, struct block *block, int is_pd)
727 {
728         PERF_INIT();
729         PERF_BEGIN();
730         struct script_info *info;
731         int ret;
732
733         if (!block || !block->part) {
734                 ErrPrint("Block or block->part is NIL\n");
735                 PERF_MARK("access");
736                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
737         }
738
739         info = is_pd ? instance_gbar_script(inst) : instance_dbox_script(inst);
740         if (!info) {
741                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
742                 PERF_MARK("access");
743                 return DBOX_STATUS_ERROR_FAULT;
744         }
745
746         if (!info->port) {
747                 ErrPrint("info->port is NIL\n");
748                 PERF_MARK("access");
749                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
750         }
751
752         ret = info->port->update_access(info->port_data, block->id, block->part, block->data, block->option);
753         PERF_MARK("access");
754         return ret;
755 }
756
757 static int operate_access(struct inst_info *inst, struct block *block, int is_pd)
758 {
759         PERF_INIT();
760         PERF_BEGIN();
761         struct script_info *info;
762         int ret;
763
764         if (!block || !block->part) {
765                 ErrPrint("Block or block->part is NIL\n");
766                 PERF_MARK("operate_access");
767                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
768         }
769
770         info = is_pd ? instance_gbar_script(inst) : instance_dbox_script(inst);
771         if (!info) {
772                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
773                 PERF_MARK("operate_access");
774                 return DBOX_STATUS_ERROR_FAULT;
775         }
776
777         if (!info->port) {
778                 ErrPrint("info->port is NIL\n");
779                 PERF_MARK("operate_access");
780                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
781         }
782
783         ret = info->port->operate_access(info->port_data, block->id, block->part, block->data, block->option);
784         PERF_MARK("operate_access");
785         return ret;
786 }
787
788 static int update_script_script(struct inst_info *inst, struct block *block, int is_pd)
789 {
790         PERF_INIT();
791         PERF_BEGIN();
792         struct script_info *info;
793         int ret;
794
795         if (!block || !block->part) {
796                 ErrPrint("Block or part is NIL\n");
797                 PERF_MARK("script");
798                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
799         }
800
801         info = is_pd ? instance_gbar_script(inst) : instance_dbox_script(inst);
802         if (!info) {
803                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
804                 PERF_MARK("script");
805                 return DBOX_STATUS_ERROR_FAULT;
806         }
807
808         if (!info->port) {
809                 ErrPrint("info->port is NIL\n");
810                 PERF_MARK("script");
811                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
812         }
813
814         ret = info->port->update_script(info->port_data, block->id, block->target, block->part, block->data, block->option);
815         PERF_MARK("script");
816         return ret;
817 }
818
819 static int update_script_signal(struct inst_info *inst, struct block *block, int is_pd)
820 {
821         PERF_INIT();
822         PERF_BEGIN();
823         struct script_info *info;
824         int ret;
825
826         if (!block) {
827                 ErrPrint("block is NIL\n");
828                 PERF_MARK("signal");
829                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
830         }
831
832         info = is_pd ? instance_gbar_script(inst) : instance_dbox_script(inst);
833         if (!info) {
834                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
835                 PERF_MARK("signal");
836                 return DBOX_STATUS_ERROR_FAULT;
837         }
838
839         if (!info->port) {
840                 ErrPrint("info->port is NIL\n");
841                 PERF_MARK("signal");
842                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
843         }
844
845         ret = info->port->update_signal(info->port_data, block->id, block->part, block->data);
846         PERF_MARK("signal");
847         return ret;
848 }
849
850 static int update_script_drag(struct inst_info *inst, struct block *block, int is_pd)
851 {
852         PERF_INIT();
853         PERF_BEGIN();
854         struct script_info *info;
855         double dx, dy;
856         int ret;
857
858         if (!block || !block->data || !block->part) {
859                 ErrPrint("block or block->data or block->part is NIL\n");
860                 PERF_MARK("drag");
861                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
862         }
863
864         info = is_pd ? instance_gbar_script(inst) : instance_dbox_script(inst);
865         if (!info) {
866                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
867                 PERF_MARK("drag");
868                 return DBOX_STATUS_ERROR_FAULT;
869         }
870
871         if (sscanf(block->data, "%lfx%lf", &dx, &dy) != 2) {
872                 ErrPrint("Invalid format of data (DRAG data [%s])\n", block->data);
873                 PERF_MARK("drag");
874                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
875         }
876
877         if (!info->port) {
878                 ErrPrint("info->port is NIL\n");
879                 PERF_MARK("drag");
880                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
881         }
882
883         ret = info->port->update_drag(info->port_data, block->id, block->part, dx, dy);
884         PERF_MARK("drag");
885         return ret;
886 }
887
888 static void update_size_for_script(struct script_info *info, struct inst_info *inst, int w, int h)
889 {
890         /*!
891          * \note
892          * After update the buffer size,
893          * If it required to be unload and load.
894          * New size of buffer will be allocated
895          */
896         buffer_handler_update_size(info->buffer_handle, w, h);
897
898         if (info->port->update_size) {
899                 (void)info->port->update_size(info->port_data, NULL, w, h);
900         }
901
902         if (instance_dbox_script(inst) == info) {
903                 instance_set_dbox_size(inst, w, h);
904         } else if (instance_gbar_script(inst) == info) {
905                 instance_set_gbar_size(inst, w, h);
906         } else {
907                 ErrPrint("Unknown script\n");
908         }
909 }
910
911 HAPI int script_handler_resize(struct script_info *info, int w, int h)
912 {
913         PERF_INIT();
914         PERF_BEGIN();
915         struct inst_info *inst;
916
917         if (!info) {
918                 ErrPrint("info[%p] resize is ignored\n", info);
919                 PERF_MARK("resize");
920                 return DBOX_STATUS_ERROR_NONE;
921         }
922
923         inst = buffer_handler_instance(info->buffer_handle);
924         if (!inst) {
925                 ErrPrint("Instance is not valid\n");
926                 PERF_MARK("resize");
927                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
928         }
929
930         update_size_for_script(info, inst, w, h);
931
932         PERF_MARK("resize");
933         return DBOX_STATUS_ERROR_NONE;
934 }
935
936 HAPI const char *script_handler_buffer_id(struct script_info *info)
937 {
938         if (!info || !info->buffer_handle) {
939                 ErrPrint("Invalid info\n");
940                 return "";
941         }
942
943         return buffer_handler_id(info->buffer_handle);
944 }
945
946 static int update_info(struct inst_info *inst, struct block *block, int is_pd)
947 {
948         PERF_INIT();
949         PERF_BEGIN();
950         struct script_info *info;
951
952         if (!block || !block->part || !block->data) {
953                 ErrPrint("block or block->part or block->data is NIL\n");
954                 PERF_MARK("info");
955                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
956         }
957
958         info = is_pd ? instance_gbar_script(inst) : instance_dbox_script(inst);
959         if (!info) {
960                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
961                 PERF_MARK("info");
962                 return DBOX_STATUS_ERROR_FAULT;
963         }
964
965         if (!info->port) {
966                 ErrPrint("info->port is NIL\n");
967                 PERF_MARK("info");
968                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
969         }
970
971         if (!strcasecmp(block->part, INFO_SIZE)) {
972                 int w, h;
973
974                 if (sscanf(block->data, "%dx%d", &w, &h) != 2) {
975                         ErrPrint("Invalid format for SIZE(%s)\n", block->data);
976                         PERF_MARK("info");
977                         return DBOX_STATUS_ERROR_INVALID_PARAMETER;
978                 }
979
980                 if (!block->id) {
981                         update_size_for_script(info, inst, w, h);
982                 } else {
983                         (void)info->port->update_size(info->port_data, block->id, w, h);
984                 }
985         } else if (!strcasecmp(block->part, INFO_CATEGORY)) {
986                 (void)info->port->update_category(info->port_data, block->id, block->data);
987         }
988         PERF_MARK("info");
989
990         return DBOX_STATUS_ERROR_NONE;
991 }
992
993 static inline void consuming_parsed_block(struct inst_info *inst, int is_pd, struct block *block)
994 {
995         struct script_info *info;
996         typedef int (*update_function_t)(struct inst_info *inst, struct block *block, int is_pd);
997         update_function_t updators[] = {
998                 update_access,
999                 operate_access,
1000                 update_script_color,
1001                 update_script_drag,
1002                 update_script_image,
1003                 update_info,
1004                 update_script_script,
1005                 update_script_signal,
1006                 update_script_text,
1007                 NULL
1008         };
1009
1010         info = is_pd ? instance_gbar_script(inst) : instance_dbox_script(inst);
1011         if (!info) {
1012                 ErrPrint("info is NIL (%d, %s)\n", is_pd, instance_id(inst));
1013                 goto free_out;
1014         }
1015
1016         if (script_handler_is_loaded(info)) {
1017                 if (block->type >= 0 || block->type < TYPE_MAX) {
1018                         (void)updators[block->type](inst, block, is_pd);
1019                 } else {
1020                         ErrPrint("Block type[%d] is not valid\n", block->type);
1021                 }
1022         } else {
1023                 info->cached_blocks = eina_list_append(info->cached_blocks, block);
1024                 DbgPrint("Block is cached (%p), %d, %s\n", block, eina_list_count(info->cached_blocks), instance_id(inst));
1025                 return;
1026         }
1027
1028 free_out:
1029         delete_block(block);
1030 }
1031
1032 HAPI int script_init(void)
1033 {
1034         if (!strcasecmp(DYNAMICBOX_CONF_PROVIDER_METHOD, "shm")) {
1035                 s_info.env_buf_type = DBOX_FB_TYPE_SHM;
1036         } else if (!strcasecmp(DYNAMICBOX_CONF_PROVIDER_METHOD, "pixmap")) {
1037                 s_info.env_buf_type = DBOX_FB_TYPE_PIXMAP;
1038         }
1039
1040         return DBOX_STATUS_ERROR_NONE;
1041 }
1042
1043 HAPI int script_fini(void)
1044 {
1045         struct script_port *item;
1046         /*!
1047          * \TODO: Release all handles
1048          */
1049         EINA_LIST_FREE(s_info.script_port_list, item) {
1050                 item->fini();
1051                 if (dlclose(item->handle) != 0) {
1052                         ErrPrint("dlclose: %s\n", strerror(errno));
1053                 }
1054                 DbgFree(item);
1055         }
1056
1057         return 0;
1058 }
1059
1060 HAPI int script_handler_update_pointer(struct script_info *info, int x, int y, int down)
1061 {
1062         if (!info) {
1063                 return DBOX_STATUS_ERROR_NONE;
1064         }
1065
1066         info->x = x;
1067         info->y = y;
1068
1069         if (down == 0) {
1070                 info->down = 0;
1071         } else if (down == 1) {
1072                 info->down = 1;
1073         }
1074
1075         return DBOX_STATUS_ERROR_NONE;
1076 }
1077
1078 HAPI int script_handler_update_keycode(struct script_info *info, unsigned int keycode)
1079 {
1080         if (!info) {
1081                 return DBOX_STATUS_ERROR_NONE;
1082         }
1083
1084         info->keycode = keycode;
1085
1086         return DBOX_STATUS_ERROR_NONE;
1087 }
1088
1089 HAPI int script_handler_feed_event(struct script_info *info, int event, double timestamp)
1090 {
1091         int ret;
1092
1093         if (!info->port) {
1094                 ErrPrint("info->port is NIL\n");
1095                 return DBOX_STATUS_ERROR_INVALID_PARAMETER;
1096         }
1097
1098         ret = info->port->feed_event(info->port_data, event, info->x, info->y, info->down, info->keycode, timestamp);
1099         return ret;
1100 }
1101
1102 static inline char *load_file(const char *filename)
1103 {
1104         char *filebuf = NULL;
1105         int fd;
1106         off_t filesize;
1107         int ret;
1108         size_t readsize = 0;
1109
1110         fd = open(filename, O_RDONLY);
1111         if (fd < 0) {
1112                 ErrPrint("open: %s\n", strerror(errno));
1113                 return NULL;
1114         }
1115
1116         filesize = lseek(fd, 0L, SEEK_END);
1117         if (filesize == (off_t)-1) {
1118                 ErrPrint("lseek: %s\n", strerror(errno));
1119                 goto errout;
1120         }
1121
1122         if (lseek(fd, 0L, SEEK_SET) < 0) {
1123                 ErrPrint("lseek: %s\n", strerror(errno));
1124                 goto errout;
1125         }
1126
1127         filebuf = malloc(filesize + 1);
1128         if (!filebuf) {
1129                 ErrPrint("malloc: %s\n", strerror(errno));
1130                 goto errout;
1131         }
1132
1133         while (readsize < filesize) {
1134                 ret = read(fd, filebuf + readsize, (size_t)filesize - readsize);
1135                 if (ret < 0) {
1136                         if (errno == EINTR) {
1137                                 DbgPrint("Read is interrupted\n");
1138                                 continue;
1139                         }
1140
1141                         ErrPrint("read: %s\n", strerror(errno));
1142                         free(filebuf);
1143                         filebuf = NULL;
1144                         break;
1145                 }
1146
1147                 readsize += ret;
1148         }
1149
1150         if (filebuf) {
1151                 filebuf[readsize] = '\0';
1152         }
1153
1154         /*!
1155          * \note
1156          * Now, we are ready to parse the filebuf.
1157          */
1158
1159 errout:
1160         if (close(fd) < 0) {
1161                 ErrPrint("close: %s\n", strerror(errno));
1162         }
1163
1164         return filebuf;
1165 }
1166
1167 #if defined(_APPLY_SCRIPT_ASYNC_UPDATE)
1168 struct apply_data {
1169         struct inst_info *inst;
1170         Eina_List *block_list;
1171         int is_pd;
1172 };
1173
1174 static Eina_Bool apply_changes_cb(void *_data)
1175 {
1176         struct apply_data *data = _data;
1177         struct block *block;
1178
1179         block = eina_list_nth(data->block_list, 0);
1180         data->block_list = eina_list_remove(data->block_list, block);
1181         consuming_parsed_block(data->inst, data->is_pd, block);
1182
1183         if (!data->block_list) {
1184                 free(data);
1185                 return ECORE_CALLBACK_CANCEL;
1186         }
1187
1188         return ECORE_CALLBACK_RENEW;
1189 }
1190 #endif
1191
1192 HAPI int script_handler_parse_desc(struct inst_info *inst, const char *filename, int is_pd)
1193 {
1194         PERF_INIT();
1195         PERF_BEGIN();
1196         int type_idx = 0;
1197         int type_len = 0;
1198         int field_idx = 0;
1199         int field_len = 0;
1200         char *filebuf;
1201         char *fileptr;
1202         char *ptr = NULL;
1203         struct block *block = NULL;
1204         Eina_List *block_list = NULL;
1205         enum state {
1206                 BEGIN,
1207                 FIELD,
1208                 DATA,
1209                 END,
1210                 DONE,
1211                 ERROR,
1212         } state;
1213
1214         filebuf = load_file(filename);
1215         if (!filebuf) {
1216                 return DBOX_STATUS_ERROR_IO_ERROR;
1217         }
1218
1219         fileptr = filebuf;
1220
1221         state = BEGIN;
1222         while (*fileptr && state != ERROR) {
1223                 switch (state) {
1224                 case BEGIN:
1225                         if (*fileptr == '{') {
1226                                 block = calloc(1, sizeof(*block));
1227                                 if (!block) {
1228                                         ErrPrint("calloc: %s\n", strerror(errno));
1229                                         state = ERROR;
1230                                         continue;
1231                                 }
1232                                 state = FIELD;
1233                                 ptr = NULL;
1234                         }
1235                         break;
1236                 case FIELD:
1237                         if (isspace(*fileptr)) {
1238                                 if (ptr != NULL) {
1239                                         *fileptr = '\0';
1240                                 }
1241                         } else if (*fileptr == '=') {
1242                                 *fileptr = '\0';
1243                                 ptr = NULL;
1244                                 state = DATA;
1245                         } else if (ptr == NULL) {
1246                                 ptr = fileptr;
1247                                 field_idx = 0;
1248                                 field_len = 0;
1249
1250                                 while (field_list[field_idx]) {
1251                                         if (field_list[field_idx][field_len] == *fileptr) {
1252                                                 break;
1253                                         }
1254                                         field_idx++;
1255                                 }
1256
1257                                 if (!field_list[field_idx]) {
1258                                         ErrPrint("Invalid field\n");
1259                                         state = ERROR;
1260                                         continue;
1261                                 }
1262
1263                                 field_len++;
1264                         } else {
1265                                 if (field_list[field_idx][field_len] != *fileptr) {
1266                                         field_idx++;
1267                                         while (field_list[field_idx]) {
1268                                                 if (!strncmp(field_list[field_idx], fileptr - field_len, field_len)) {
1269                                                         break;
1270                                                 } else {
1271                                                         field_idx++;
1272                                                 }
1273                                         }
1274
1275                                         if (!field_list[field_idx]) {
1276                                                 state = ERROR;
1277                                                 ErrPrint("field is not valid\n");
1278                                                 continue;
1279                                         }
1280                                 }
1281
1282                                 field_len++;
1283                         }
1284                         break;
1285                 case DATA:
1286                         switch (field_idx) {
1287                         case FIELD_TYPE:
1288                                 if (ptr == NULL) {
1289                                         if (isspace(*fileptr)) {
1290                                                 break;
1291                                         }
1292
1293                                         if (*fileptr == '\0') {
1294                                                 state = ERROR;
1295                                                 ErrPrint("Type is not valid\n");
1296                                                 continue;
1297                                         }
1298
1299                                         ptr = fileptr;
1300                                         type_idx = 0;
1301                                         type_len = 0;
1302                                 }
1303
1304                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1305                                         *fileptr = '\0';
1306                                 }
1307
1308                                 if (type_list[type_idx][type_len] != *fileptr) {
1309                                         type_idx++;
1310                                         while (type_list[type_idx]) {
1311                                                 if (!strncmp(type_list[type_idx], fileptr - type_len, type_len)) {
1312                                                         break;
1313                                                 } else {
1314                                                         type_idx++;
1315                                                 }
1316                                         }
1317
1318                                         if (!type_list[type_idx]) {
1319                                                 state = ERROR;
1320                                                 ErrPrint("type is not valid (%s)\n", fileptr - type_len);
1321                                                 continue;
1322                                         }
1323                                 }
1324
1325                                 if (!*fileptr) {
1326                                         block->type = type_idx;
1327                                         state = DONE;
1328                                         ptr = NULL;
1329                                 }
1330
1331                                 type_len++;
1332                                 break;
1333                         case FIELD_PART:
1334                                 if (ptr == NULL) {
1335                                         ptr = fileptr;
1336                                 }
1337
1338                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1339                                         *fileptr = '\0';
1340                                 }
1341
1342                                 if (!*fileptr) {
1343                                         block->part = ptr;
1344                                         state = DONE;
1345                                         ptr = NULL;
1346                                 }
1347                                 break;
1348                         case FIELD_DATA:
1349                                 if (ptr == NULL) {
1350                                         ptr = fileptr;
1351                                 }
1352
1353                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1354                                         *fileptr = '\0';
1355                                 }
1356
1357                                 if (!*fileptr) {
1358                                         block->data = ptr;
1359                                         state = DONE;
1360                                         ptr = NULL;
1361                                 }
1362                                 break;
1363                         case FIELD_OPTION:
1364                                 if (ptr == NULL) {
1365                                         ptr = fileptr;
1366                                 }
1367
1368                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1369                                         *fileptr = '\0';
1370                                 }
1371
1372                                 if (!*fileptr) {
1373                                         block->option = ptr;
1374                                         state = DONE;
1375                                         ptr = NULL;
1376                                 }
1377                                 break;
1378                         case FIELD_ID:
1379                                 if (ptr == NULL) {
1380                                         ptr = fileptr;
1381                                 }
1382
1383                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1384                                         *fileptr = '\0';
1385                                 }
1386
1387                                 if (!*fileptr) {
1388                                         block->id = ptr;
1389                                         state = DONE;
1390                                         ptr = NULL;
1391                                 }
1392                                 break;
1393                         case FIELD_TARGET:
1394                                 if (ptr == NULL) {
1395                                         ptr = fileptr;
1396                                 }
1397
1398                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1399                                         *fileptr = '\0';
1400                                 }
1401
1402                                 if (!*fileptr) {
1403                                         block->target = ptr;
1404                                         state = DONE;
1405                                         ptr = NULL;
1406                                 }
1407                                 break;
1408                         case FIELD_FILE:
1409                                 if (ptr == NULL) {
1410                                         ptr = fileptr;
1411                                 }
1412
1413                                 if (*fileptr && (*fileptr == '\n' || *fileptr == '\r' || *fileptr == '\f')) {
1414                                         *fileptr = '\0';
1415                                 }
1416
1417                                 if (!*fileptr) {
1418                                         block->target = ptr;
1419                                         state = DONE;
1420                                         ptr = NULL;
1421                                 }
1422                         default:
1423                                 break;
1424                         }
1425
1426                         break;
1427                 case DONE:
1428                         if (isspace(*fileptr)) {
1429                         } else if (*fileptr == '}') {
1430                                 state = BEGIN;
1431                                 block->filename = filename;
1432                                 block_list = eina_list_append(block_list, block);
1433                                 block = NULL;
1434                         } else {
1435                                 state = FIELD;
1436                                 continue;
1437                         }
1438                         break;
1439                 case END:
1440                 default:
1441                         break;
1442                 }
1443
1444                 fileptr++;
1445         }
1446
1447         if (state != BEGIN) {
1448                 ErrPrint("State %d\n", state);
1449
1450                 free(filebuf);
1451                 free(block);
1452
1453                 EINA_LIST_FREE(block_list, block) {
1454                         free(block);
1455                 }
1456
1457                 PERF_MARK("parser");
1458                 return DBOX_STATUS_ERROR_FAULT;
1459         }
1460
1461         block = eina_list_data_get(eina_list_last(block_list));
1462         if (block) {
1463                 block->filebuf = filebuf;
1464         } else {
1465                 ErrPrint("Last block is not exists (There is no parsed block)\n");
1466                 free(filebuf);
1467         }
1468
1469         PERF_MARK("parser");
1470
1471 #if defined(_APPLY_SCRIPT_ASYNC_UPDATE)
1472         struct apply_data *data;
1473
1474         data = malloc(sizeof(*data));
1475         if (data) {
1476                 data->inst = inst;
1477                 data->is_pd = is_pd;
1478                 data->block_list = block_list;
1479                 if (!ecore_timer_add(0.001f, apply_changes_cb, data)) {
1480                         ErrPrint("Failed to add timer\n");
1481                         free(data);
1482                         EINA_LIST_FREE(block_list, block) {
1483                                 consuming_parsed_block(inst, is_pd, block);
1484                         }
1485                 }
1486         } else {
1487                 ErrPrint("Heap: %s\n", strerror(errno));
1488                 EINA_LIST_FREE(block_list, block) {
1489                         consuming_parsed_block(inst, is_pd, block);
1490                 }
1491         }
1492 #else
1493         ErrPrint("Begin: Set content for EDJE object\n");
1494         EINA_LIST_FREE(block_list, block) {
1495                 consuming_parsed_block(inst, is_pd, block);
1496         }
1497         ErrPrint("End: Set content for EDJE object\n");
1498
1499         /*!
1500          * Doesn't need to force to render the contents.
1501          struct script_info *info;
1502          info = is_pd ? instance_gbar_script(inst) : instance_dbox_script(inst);
1503          if (info && info->ee) {
1504          ecore_evas_manual_render(info->ee);
1505          }
1506          */
1507 #endif
1508
1509         return DBOX_STATUS_ERROR_NONE;
1510 }
1511
1512 /* End of a file */