[edje_load]: This code adds a safety check so that edje does not crash
[framework/uifw/edje.git] / src / lib / edje_load.c
1 #include "edje_private.h"
2
3 typedef struct _Edje_Table_Items Edje_Table_Items;
4 struct _Edje_Table_Items
5 {
6    Evas_Object *child;
7    const char *part;
8    unsigned short col;
9    unsigned short row;
10    unsigned short colspan;
11    unsigned short rowspan;
12 };
13
14 typedef struct _Edje_Drag_Items Edje_Drag_Items;
15 struct _Edje_Drag_Items
16 {
17    const char *part;
18    FLOAT_T x, y, w, h;
19    struct {
20       FLOAT_T x, y;
21    } step;
22    struct {
23       FLOAT_T x, y;
24    } page;
25 };
26
27 /* START - Nested part support */
28 #define _edje_smart_nested_type "Evas_Smart_Nested"
29 typedef struct _Edje_Nested_Support Edje_Nested_Support;
30 struct _Edje_Nested_Support
31 {  /* We builed nested-parts list using this struct */
32    Evas_Object *o;        /* Smart object containing nested children */
33    unsigned char nested_children_count; /* Number of nested children */
34 };
35
36 Evas_Smart *
37 _edje_smart_nested_smart_class_new(void)
38 {
39    static Evas_Smart_Class _sc = EVAS_SMART_CLASS_INIT_NAME_VERSION("EdjeNested");
40    static const Evas_Smart_Class *class = NULL;
41    static Evas_Smart *smart;
42
43    if (smart)
44      return smart;
45
46    class = &_sc;
47    smart = evas_smart_class_new(class);
48    return smart;
49 }
50
51
52 Evas_Object *
53 edje_smart_nested_add(Evas *evas)
54 {
55       return evas_object_smart_add(evas, _edje_smart_nested_smart_class_new());
56 }
57
58 /* END   - Nested part support */
59
60
61 #ifdef EDJE_PROGRAM_CACHE
62 static Eina_Bool  _edje_collection_free_prog_cache_matches_free_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata);
63 #endif
64 static void _edje_object_pack_item_hints_set(Evas_Object *obj, Edje_Pack_Element *it);
65 static void _cb_signal_repeat(void *data, Evas_Object *obj, const char *signal, const char *source);
66
67 static Eina_List *_edje_object_collect(Edje *ed);
68
69 static int _sort_defined_boxes(const void *a, const void *b);
70
71 /************************** API Routines **************************/
72
73 EAPI Eina_Bool
74 edje_object_file_set(Evas_Object *obj, const char *file, const char *group)
75 {
76    Eina_Bool ret;
77    Edje *ed;
78    Eina_Array *nested;
79
80    ed = _edje_fetch(obj);
81    if (!ed)
82      return EINA_FALSE;
83
84    nested = eina_array_new(8);
85    ret = ed->api->file_set(obj, file, group, nested);
86    eina_array_free(nested);
87    nested = NULL;
88
89    _edje_object_orientation_inform(obj);
90    return ret;
91 }
92
93 EAPI void
94 edje_object_file_get(const Evas_Object *obj, const char **file, const char **group)
95 {
96    Edje *ed;
97
98    ed = _edje_fetch(obj);
99    if (!ed)
100      {
101         if (file) *file = NULL;
102         if (group) *group = NULL;
103         return;
104      }
105    if (file) *file = ed->path;
106    if (group) *group = ed->group;
107 }
108
109 EAPI Edje_Load_Error
110 edje_object_load_error_get(const Evas_Object *obj)
111 {
112    Edje *ed;
113
114    ed = _edje_fetch(obj);
115    if (!ed) return EDJE_LOAD_ERROR_NONE;
116    return ed->load_error;
117 }
118
119 EAPI const char *
120 edje_load_error_str(Edje_Load_Error error)
121 {
122    switch (error)
123      {
124       case EDJE_LOAD_ERROR_NONE:
125          return "No Error";
126       case EDJE_LOAD_ERROR_GENERIC:
127          return "Generic Error";
128       case EDJE_LOAD_ERROR_DOES_NOT_EXIST:
129          return "File Does Not Exist";
130       case EDJE_LOAD_ERROR_PERMISSION_DENIED:
131          return "Permission Denied";
132       case EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED:
133          return "Resource Allocation Failed";
134       case EDJE_LOAD_ERROR_CORRUPT_FILE:
135          return "Corrupt File";
136       case EDJE_LOAD_ERROR_UNKNOWN_FORMAT:
137          return "Unknown Format";
138       case EDJE_LOAD_ERROR_INCOMPATIBLE_FILE:
139          return "Incompatible File";
140       case EDJE_LOAD_ERROR_UNKNOWN_COLLECTION:
141          return "Unknown Collection";
142       case EDJE_LOAD_ERROR_RECURSIVE_REFERENCE:
143          return "Recursive Reference";
144       default:
145          return "Unknown Error";
146      }
147 }
148
149
150 EAPI Eina_List *
151 edje_file_collection_list(const char *file)
152 {
153    Eina_List *lst = NULL;
154    Edje_File *edf;
155    int error_ret = 0;
156
157    if ((!file) || (!*file)) return NULL;
158    edf = _edje_cache_file_coll_open(file, NULL, &error_ret, NULL, NULL);
159    if (edf)
160      {
161         Eina_Iterator *i;
162         const char *key;
163
164         i = eina_hash_iterator_key_new(edf->collection);
165
166         EINA_ITERATOR_FOREACH(i, key)
167           lst = eina_list_append(lst, eina_stringshare_add(key));
168
169         eina_iterator_free(i);
170
171         _edje_cache_file_unref(edf);
172      }
173    return lst;
174 }
175
176 EAPI void
177 edje_file_collection_list_free(Eina_List *lst)
178 {
179    while (lst)
180      {
181         if (eina_list_data_get(lst)) eina_stringshare_del(eina_list_data_get(lst));
182         lst = eina_list_remove(lst, eina_list_data_get(lst));
183      }
184 }
185
186 EAPI Eina_Bool
187 edje_file_group_exists(const char *file, const char *glob)
188 {
189    Edje_File *edf;
190    int error_ret = 0;
191    Eina_Bool succeed = EINA_FALSE;
192    Eina_Bool is_glob = EINA_FALSE;
193    const char *p;
194
195    if ((!file) || (!*file) || (!glob))
196       return EINA_FALSE;
197
198    edf = _edje_cache_file_coll_open(file, NULL, &error_ret, NULL, NULL);
199    if (!edf)
200       return EINA_FALSE;
201
202    for (p = glob; *p; p++)
203      {
204        if ((*p == '*') || (*p == '?') || (*p == '['))
205          {
206            is_glob = EINA_TRUE;
207            break;
208          }
209      }
210
211    if (is_glob)
212      {
213        if (!edf->collection_patterns)
214          {
215            Edje_Part_Collection_Directory_Entry *ce;
216            Eina_Iterator *i;
217            Eina_List *l = NULL;
218
219            i = eina_hash_iterator_data_new(edf->collection);
220
221            EINA_ITERATOR_FOREACH(i, ce)
222              l = eina_list_append(l, ce);
223
224            eina_iterator_free(i);
225
226            edf->collection_patterns = edje_match_collection_dir_init(l);
227            eina_list_free(l);
228          }
229
230        succeed = edje_match_collection_dir_exec(edf->collection_patterns, glob);
231        if (edf->collection_patterns)
232          {
233            edje_match_patterns_free(edf->collection_patterns);
234            edf->collection_patterns = NULL;
235          }
236      }
237    else
238      {
239         if (eina_hash_find(edf->collection, glob)) succeed = EINA_TRUE;
240      }
241    _edje_cache_file_unref(edf);
242
243    INF("edje_file_group_exists: '%s', '%s': %i\n", file, glob, succeed);
244
245    return succeed;
246 }
247
248
249 EAPI char *
250 edje_file_data_get(const char *file, const char *key)
251 {
252    Edje_File *edf;
253    char *str = NULL;
254    int error_ret = 0;
255
256    if (key)
257      {
258         edf = _edje_cache_file_coll_open(file, NULL, &error_ret, NULL, NULL);
259         if (edf)
260           {
261              str = (char*) edje_string_get(eina_hash_find(edf->data, key));
262
263              if (str) str = strdup(str);
264
265              _edje_cache_file_unref(edf);
266           }
267      }
268    return str;
269 }
270
271 void
272 _edje_programs_patterns_clean(Edje *ed)
273 {
274    _edje_signals_sources_patterns_clean(&ed->patterns.programs);
275
276    eina_rbtree_delete(ed->patterns.programs.exact_match,
277                       EINA_RBTREE_FREE_CB(edje_match_signal_source_free),
278                       NULL);
279    ed->patterns.programs.exact_match = NULL;
280
281    free(ed->patterns.programs.u.programs.globing);
282    ed->patterns.programs.u.programs.globing = NULL;
283 }
284
285 void
286 _edje_programs_patterns_init(Edje *ed)
287 {
288    Edje_Signals_Sources_Patterns *ssp = &ed->patterns.programs;
289    Edje_Program **all;
290    unsigned int i, j;
291
292    if (ssp->signals_patterns)
293      return;
294
295    if (getenv("EDJE_DUMP_PROGRAMS"))
296      {
297        INF("Group '%s' programs:", ed->group);
298 #define EDJE_DUMP_PROGRAM(Section)                                      \
299        for (i = 0; i < ed->collection->programs.Section##_count; i++)   \
300          INF(#Section" for ('%s', '%s')", ed->collection->programs.Section[i]->signal, ed->collection->programs.Section[i]->source);
301
302        EDJE_DUMP_PROGRAM(strcmp);
303        EDJE_DUMP_PROGRAM(strncmp);
304        EDJE_DUMP_PROGRAM(strrncmp);
305        EDJE_DUMP_PROGRAM(fnmatch);
306        EDJE_DUMP_PROGRAM(nocmp);
307      }
308
309    edje_match_program_hash_build(ed->collection->programs.strcmp,
310                                  ed->collection->programs.strcmp_count,
311                                  &ssp->exact_match);
312
313    j = ed->collection->programs.strncmp_count
314      + ed->collection->programs.strrncmp_count
315      + ed->collection->programs.fnmatch_count
316      + ed->collection->programs.nocmp_count;
317    if (j == 0) return ;
318
319    all = malloc(sizeof (Edje_Program *) * j);
320    if (!all) return ;
321    j = 0;
322
323    /* FIXME: Build specialized data type for each case */
324 #define EDJE_LOAD_PROGRAMS_ADD(Array, Ed, It, Git, All)                 \
325    for (It = 0; It < Ed->collection->programs.Array##_count; ++It, ++Git) \
326      All[Git] = Ed->collection->programs.Array[It];
327
328    EDJE_LOAD_PROGRAMS_ADD(fnmatch, ed, i, j, all);
329    EDJE_LOAD_PROGRAMS_ADD(strncmp, ed, i, j, all);
330    EDJE_LOAD_PROGRAMS_ADD(strrncmp, ed, i, j, all);
331    /* FIXME: Do a special pass for that one */
332    EDJE_LOAD_PROGRAMS_ADD(nocmp, ed, i, j, all);
333
334    ssp->u.programs.globing = all;
335    ssp->u.programs.count = j;
336    ssp->signals_patterns = edje_match_programs_signal_init(all, j);
337    ssp->sources_patterns = edje_match_programs_source_init(all, j);
338 }
339
340 int
341 _edje_object_file_set_internal(Evas_Object *obj, const char *file, const char *group, const char *parent, Eina_List *group_path, Eina_Array *nested)
342 {
343    Edje *ed;
344    Evas *tev;
345    Edje_Real_Part *rp;
346    Eina_List *textblocks = NULL;
347    Eina_List *sources = NULL;
348    Eina_List *externals = NULL;
349    Eina_List *collect = NULL;
350    unsigned int n;
351    Eina_Array parts;
352    int group_path_started = 0;
353    Evas_Object *nested_smart = NULL;
354
355    /* Get data pointer of top-of-stack */
356    int idx = eina_array_count(nested) - 1;
357    Edje_Nested_Support *st_nested = (idx >= 0) ? eina_array_data_get(nested, idx) : NULL;
358
359    ed = _edje_fetch(obj);
360    if (!ed) return 0;
361    if (!file) file = "";
362    if (!group) group = "";
363    if (((ed->path) && (!strcmp(file, ed->path))) &&
364        (ed->group) && (!strcmp(group, ed->group)) &&
365        ed->file)
366      {
367         struct stat st;
368
369         if (stat(file, &st) != 0)
370           return 1;
371         if (st.st_mtime == ed->file->mtime)
372           return 1;
373      }
374
375    tev = evas_object_evas_get(obj);
376    evas_event_freeze(tev);
377
378    collect = _edje_object_collect(ed);
379
380    if (_edje_script_only(ed)) _edje_script_only_shutdown(ed);
381    if (_edje_lua_script_only(ed)) _edje_lua_script_only_shutdown(ed);
382
383    _edje_file_del(ed);
384
385    eina_stringshare_replace(&ed->path, file);
386    eina_stringshare_replace(&ed->group, group);
387
388    ed->parent = eina_stringshare_add(parent);
389
390    ed->load_error = EDJE_LOAD_ERROR_NONE;
391    _edje_file_add(ed);
392    ed->block_break = EINA_FALSE;
393
394    if (ed->file && ed->file->external_dir)
395      {
396         unsigned int i;
397
398         for (i = 0; i < ed->file->external_dir->entries_count; ++i)
399           edje_module_load(ed->file->external_dir->entries[i].entry);
400      }
401
402    _edje_textblock_styles_add(ed);
403    _edje_textblock_style_all_update(ed);
404
405    ed->has_entries = EINA_FALSE;
406
407    if (ed->collection)
408      {
409         eina_array_step_set(&parts, sizeof (Eina_Array), 8);
410
411         if (ed->collection->prop.orientation != EDJE_ORIENTATION_AUTO)
412           ed->is_rtl = (ed->collection->prop.orientation ==
413                         EDJE_ORIENTATION_RTL);
414
415         ed->groups = eina_list_append(ed->groups, ed);
416
417         if (ed->collection->script_only)
418           {
419              ed->load_error = EDJE_LOAD_ERROR_NONE;
420              _edje_script_only_init(ed);
421           }
422         else if (ed->collection->lua_script_only)
423           {
424              ed->load_error = EDJE_LOAD_ERROR_NONE;
425              _edje_lua_script_only_init(ed);
426           }
427         else
428           {
429              unsigned int i;
430
431              /* colorclass stuff */
432              for (i = 0; i < ed->collection->parts_count; ++i)
433                {
434                   Edje_Part *ep;
435                   unsigned int k;
436
437                   ep = ed->collection->parts[i];
438
439                   /* Register any color classes in this parts descriptions. */
440                   if ( ep && (ep->default_desc) && (ep->default_desc->color_class))
441                     _edje_color_class_member_add(ed, ep->default_desc->color_class);
442
443                   for (k = 0; k < ep->other.desc_count; k++)
444                     {
445                        Edje_Part_Description_Common *desc;
446
447                        desc = ep->other.desc[k];
448
449                        if (desc->color_class)
450                          _edje_color_class_member_add(ed, desc->color_class);
451                     }
452                }
453              /* build real parts */
454              for (n = 0; n < ed->collection->parts_count; n++)
455                {
456                   Edje_Part *ep;
457                   Eina_Bool memerr = EINA_FALSE;
458
459                   ep = ed->collection->parts[n];
460
461                   if (ep->nested_children_count)
462                     {  /* Add object to nested parts list */
463                        st_nested = malloc(sizeof(*st_nested));
464                        nested_smart = st_nested->o = edje_smart_nested_add(tev);
465
466                        /* We add 1 to children_count because the parent
467                           object is added to smart obj children as well */
468                        st_nested->nested_children_count =
469                           ep->nested_children_count + 1;
470
471                        evas_object_show(st_nested->o);
472
473                        eina_array_push(nested, st_nested);
474                     }
475
476                   rp = eina_mempool_malloc(_edje_real_part_mp, sizeof(Edje_Real_Part));
477                   if (!rp)
478                     {
479                        /* FIXME: destroy all allocated ressource, need to have a common exit point */
480                        ed->load_error = EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
481                        goto on_error;
482                     }
483
484                   memset(rp, 0, sizeof (Edje_Real_Part));
485
486                   if ((ep->dragable.x != 0) || (ep->dragable.y != 0))
487                     {
488                        rp->drag = calloc(1, sizeof (Edje_Real_Part_Drag));
489                        if (!rp->drag)
490                          {
491                             ed->load_error = EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
492                             goto on_error;
493                          }
494
495                        rp->drag->step.x = FROM_INT(ep->dragable.step_x);
496                        rp->drag->step.y = FROM_INT(ep->dragable.step_y);
497                     }
498                   // allow part type specific data - this keeps real_part smaller
499                   switch (ep->type)
500                     {
501                      case EDJE_PART_TYPE_TEXT:
502                      case EDJE_PART_TYPE_TEXTBLOCK:
503                        rp->type = EDJE_RP_TYPE_TEXT;
504                        rp->typedata.text = calloc(1, sizeof(Edje_Real_Part_Text));
505                        if (!rp->typedata.text) memerr = EINA_TRUE;
506                        break;
507                      case EDJE_PART_TYPE_GROUP:
508                      case EDJE_PART_TYPE_SWALLOW:
509                      case EDJE_PART_TYPE_EXTERNAL:
510                        rp->type = EDJE_RP_TYPE_SWALLOW;
511                        rp->typedata.swallow = calloc(1, sizeof(Edje_Real_Part_Swallow));
512                        if (!rp->typedata.swallow) memerr = EINA_TRUE;
513                        break;
514                      case EDJE_PART_TYPE_BOX:
515                      case EDJE_PART_TYPE_TABLE:
516                        rp->type = EDJE_RP_TYPE_CONTAINER;
517                        rp->typedata.container = calloc(1, sizeof(Edje_Real_Part_Container));
518                        if (!rp->typedata.container) memerr = EINA_TRUE;
519                        break;
520                      default:
521                        break;
522                     }
523                   
524                   if (memerr)
525                     {
526                        if (rp->drag) free(rp->drag);
527                        ed->load_error = EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
528                        eina_mempool_free(_edje_real_part_mp, rp);
529                        evas_event_thaw(tev);
530                        evas_event_thaw_eval(tev);
531                        return 0;
532                     }
533
534                   rp->edje = ed;
535                   _edje_ref(rp->edje);
536                   rp->part = ep;
537                   eina_array_push(&parts, rp);
538                   rp->param1.description = 
539                     _edje_part_description_find(ed, rp, "default", 0.0);
540                   rp->chosen_description = rp->param1.description;
541                   if (!rp->param1.description)
542                     ERR("no default part description for '%s'!",
543                         rp->part->name);
544
545                   switch (ep->type)
546                     {
547                      case EDJE_PART_TYPE_RECTANGLE:
548                         rp->object = evas_object_rectangle_add(ed->base.evas);
549                         break;
550                      case EDJE_PART_TYPE_PROXY:
551                      case EDJE_PART_TYPE_IMAGE:
552                         rp->object = evas_object_image_add(ed->base.evas);
553                         break;
554                      case EDJE_PART_TYPE_TEXT:
555                         _edje_text_part_on_add(ed, rp);
556                         rp->object = evas_object_text_add(ed->base.evas);
557                         evas_object_text_font_source_set(rp->object, ed->path);
558                         break;
559                      case EDJE_PART_TYPE_GROUP:
560                         sources = eina_list_append(sources, rp);
561                      case EDJE_PART_TYPE_SWALLOW:
562                      case EDJE_PART_TYPE_EXTERNAL:
563                         if (ep->type == EDJE_PART_TYPE_EXTERNAL)
564                           externals = eina_list_append(externals, rp);
565                         rp->object = evas_object_rectangle_add(ed->base.evas);
566                         evas_object_color_set(rp->object, 0, 0, 0, 0);
567                         evas_object_pass_events_set(rp->object, 1);
568                         evas_object_pointer_mode_set(rp->object, EVAS_OBJECT_POINTER_MODE_NOGRAB);
569                         _edje_callbacks_focus_add(rp->object, ed, rp);
570                         break;
571                      case EDJE_PART_TYPE_TEXTBLOCK:
572                         textblocks = eina_list_append(textblocks, rp);
573                         rp->object = evas_object_textblock_add(ed->base.evas);
574                         break;
575                      case EDJE_PART_TYPE_BOX:
576                         sources = eina_list_append(sources, rp);
577                         rp->object = evas_object_box_add(ed->base.evas);
578                         rp->typedata.container->anim = _edje_box_layout_anim_new(rp->object);
579                         break;
580                      case EDJE_PART_TYPE_TABLE:
581                         sources = eina_list_append(sources, rp);
582                         rp->object = evas_object_table_add(ed->base.evas);
583                         break;
584                      case EDJE_PART_TYPE_GRADIENT:
585                         ERR("SPANK ! SPANK ! SPANK ! YOU ARE USING GRADIENT IN PART %s FROM GROUP %s INSIDE FILE %s !! THEY ARE NOW REMOVED !",
586                             ep->name, group, file);
587                         break;
588                      case EDJE_PART_TYPE_SPACER:
589                         rp->object = NULL;
590                         break;
591                      default:
592                         ERR("wrong part type %i!", ep->type);
593                         break;
594                     }
595
596                   if (rp->object)
597                     {
598                        if (nested_smart)
599                          {  /* Update this pointer to father object only
600                                this will make smart object size == father sz */
601                             rp->nested_smart = nested_smart;
602                             nested_smart = NULL;
603                          }
604
605                        if (st_nested && st_nested->nested_children_count)
606                          {  /* Add this to list of children */
607                             evas_object_smart_member_add(rp->object,
608                                                          st_nested->o);
609
610                             st_nested->nested_children_count--;
611
612                             /* No more nested children for this obj */
613                             while (st_nested && (st_nested->nested_children_count == 0))
614                               {
615                                  /* Loop to add smart counter as child */
616                                  Evas_Object *p_obj = st_nested->o;
617
618                                  st_nested = eina_array_pop(nested);
619                                  free(st_nested);
620
621                                  /* Check for parent in stack */
622                                  idx = eina_array_count(nested) - 1;
623                                  st_nested = (idx >= 0) ? eina_array_data_get(nested,idx) : NULL;
624
625                                  if (st_nested)
626                                    {
627                                       st_nested->nested_children_count--;
628                                       evas_object_smart_member_add(p_obj, st_nested->o);
629                                    }
630                                  else
631                                    {
632                                       evas_object_smart_member_add(p_obj, ed->obj);
633                                    }
634                               }
635                          }
636                        else
637                          evas_object_smart_member_add(rp->object, ed->obj);
638
639 //                     evas_object_layer_set(rp->object, evas_object_layer_get(ed->obj));
640                        if (ep->type != EDJE_PART_TYPE_SWALLOW && ep->type != EDJE_PART_TYPE_GROUP && ep->type != EDJE_PART_TYPE_EXTERNAL)
641                          {
642                             if (ep->mouse_events)
643                               {
644                                  _edje_callbacks_add(rp->object, ed, rp);
645                                  if (ep->repeat_events)
646                                    evas_object_repeat_events_set(rp->object, 1);
647                                  
648                                  if (ep->pointer_mode != EVAS_OBJECT_POINTER_MODE_AUTOGRAB)
649                                    evas_object_pointer_mode_set(rp->object, ep->pointer_mode);
650                               }
651                             else
652                               {
653                                  evas_object_pass_events_set(rp->object, 1);
654                                  evas_object_pointer_mode_set(rp->object, EVAS_OBJECT_POINTER_MODE_NOGRAB);
655                               }
656                             if (ep->precise_is_inside)
657                               evas_object_precise_is_inside_set(rp->object, 1);
658                          }
659                        if (rp->part->clip_to_id < 0)
660                          evas_object_clip_set(rp->object, ed->base.clipper);
661                     }
662                }
663              if (n > 0)
664                {
665                   ed->table_parts = malloc(sizeof(Edje_Real_Part *) * n);
666                   ed->table_parts_size = n;
667                   /* FIXME: check malloc return */
668                   n = eina_array_count(&parts) - 1;
669                   while ((rp = eina_array_pop(&parts)))
670                     {
671                        ed->table_parts[n] = rp;
672                        n--;
673                     }
674                   for (i = 0; i < ed->table_parts_size; i++)
675                     {
676                        rp = ed->table_parts[i];
677                        if (rp->param1.description) /* FIXME: prevent rel to gone radient part to go wrong. You may
678                                                       be able to remove this when all theme are correctly rewritten. */
679                          {
680                             if (rp->param1.description->rel1.id_x >= 0)
681                               rp->param1.rel1_to_x = ed->table_parts[rp->param1.description->rel1.id_x % ed->table_parts_size];
682                             if (rp->param1.description->rel1.id_y >= 0)
683                               rp->param1.rel1_to_y = ed->table_parts[rp->param1.description->rel1.id_y % ed->table_parts_size];
684                             if (rp->param1.description->rel2.id_x >= 0)
685                               rp->param1.rel2_to_x = ed->table_parts[rp->param1.description->rel2.id_x % ed->table_parts_size];
686                             if (rp->param1.description->rel2.id_y >= 0)
687                               rp->param1.rel2_to_y = ed->table_parts[rp->param1.description->rel2.id_y % ed->table_parts_size];
688                          }
689                        if (rp->part->clip_to_id >= 0)
690                          {
691                             rp->clip_to = ed->table_parts[rp->part->clip_to_id % ed->table_parts_size];
692                             if (rp->clip_to &&
693                                 rp->clip_to->object &&
694                                 rp->object)
695                               {
696                                  evas_object_pass_events_set(rp->clip_to->object, 1);
697                                  evas_object_pointer_mode_set(rp->clip_to->object, EVAS_OBJECT_POINTER_MODE_NOGRAB);
698                                  evas_object_clip_set(rp->object, rp->clip_to->object);
699                               }
700                          }
701                        if (rp->drag)
702                          {
703                             if (rp->part->dragable.confine_id >= 0)
704                               rp->drag->confine_to = ed->table_parts[rp->part->dragable.confine_id % ed->table_parts_size];
705                          }
706
707                        /* replay events for dragable */
708                        if (rp->part->dragable.event_id >= 0)
709                          {
710                             rp->events_to =
711                               ed->table_parts[rp->part->dragable.event_id % ed->table_parts_size];
712                             /* events_to may be used only with dragable */
713                             if (!rp->events_to->part->dragable.x &&
714                                 !rp->events_to->part->dragable.y)
715                               rp->events_to = NULL;
716                          }
717
718                        if ((rp->type == EDJE_RP_TYPE_SWALLOW) &&
719                            (rp->typedata.swallow))
720                          {
721                             rp->typedata.swallow->swallow_params.min.w = 0;
722                             rp->typedata.swallow->swallow_params.min.h = 0;
723                             rp->typedata.swallow->swallow_params.max.w = -1;
724                             rp->typedata.swallow->swallow_params.max.h = -1;
725                          }
726
727                        if (rp->part->type == EDJE_PART_TYPE_TEXT
728                            || rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
729                          {
730                             Edje_Part_Description_Text *text;
731
732                             text = (Edje_Part_Description_Text *) rp->param1.description;
733
734                             if (ed->file->feature_ver < 1)
735                               {
736                                  text->text.id_source = -1;
737                                  text->text.id_text_source = -1;
738                               }
739
740                             if ((rp->type == EDJE_RP_TYPE_TEXT) &&
741                                 (rp->typedata.text))
742                               {
743                                  if (text->text.id_source >= 0)
744                                    rp->typedata.text->source = ed->table_parts[text->text.id_source % ed->table_parts_size];
745                                  if (text->text.id_text_source >= 0)
746                                    rp->typedata.text->text_source = ed->table_parts[text->text.id_text_source % ed->table_parts_size];
747                               }
748                             if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
749                               {
750                                  _edje_entry_real_part_init(rp);
751                                  if (!ed->has_entries)
752                                    ed->has_entries = EINA_TRUE;
753                               }
754                          }
755                     }
756                }
757              
758              _edje_programs_patterns_init(ed);
759
760              n = ed->collection->programs.fnmatch_count +
761                ed->collection->programs.strcmp_count +
762                ed->collection->programs.strncmp_count +
763                ed->collection->programs.strrncmp_count +
764                ed->collection->programs.nocmp_count;
765              if (n > 0)
766                {
767                   Edje_Program *pr;
768
769                   ed->table_programs = malloc(sizeof(Edje_Program *) * n);
770                   if (ed->table_programs)
771                     {
772                        ed->table_programs_size = n;
773
774 #define EDJE_LOAD_BUILD_TABLE(Array, Ed, It, Tmp)       \
775                        for (It = 0; It < Ed->collection->programs.Array##_count; ++It) \
776                          {                                              \
777                             Tmp = Ed->collection->programs.Array[It];   \
778                             Ed->table_programs[Tmp->id] = Tmp;          \
779                          }
780
781                        EDJE_LOAD_BUILD_TABLE(fnmatch, ed, i, pr);
782                        EDJE_LOAD_BUILD_TABLE(strcmp, ed, i, pr);
783                        EDJE_LOAD_BUILD_TABLE(strncmp, ed, i, pr);
784                        EDJE_LOAD_BUILD_TABLE(strrncmp, ed, i, pr);
785                        EDJE_LOAD_BUILD_TABLE(nocmp, ed, i, pr);
786                     }
787                }
788              _edje_ref(ed);
789              _edje_block(ed);
790              _edje_freeze(ed);
791 //           if (ed->collection->script) _edje_embryo_script_init(ed);
792              _edje_var_init(ed);
793              for (i = 0; i < ed->table_parts_size; i++)
794                {
795                   rp = ed->table_parts[i];
796                   if (rp->object) evas_object_show(rp->object);
797                   if (_edje_block_break(ed)) break;
798                   if (rp->drag)
799                     {
800                        if (rp->part->dragable.x < 0) rp->drag->val.x = FROM_DOUBLE(1.0);
801                        if (rp->part->dragable.y < 0) rp->drag->val.x = FROM_DOUBLE(1.0);
802                        _edje_dragable_pos_set(ed, rp, rp->drag->val.x, rp->drag->val.y);
803                     }
804                }
805              ed->recalc_call = EINA_TRUE;
806              ed->dirty = EINA_TRUE;
807 #ifdef EDJE_CALC_CACHE
808              ed->all_part_change = EINA_TRUE;
809 #endif
810              if ((evas_object_clipees_get(ed->base.clipper)) &&
811                  (evas_object_visible_get(obj)))
812                evas_object_show(ed->base.clipper);
813
814              /* instantiate 'internal swallows' */
815              EINA_LIST_FREE(externals, rp)
816                {
817                   Edje_Part_Description_External *external;
818                   Evas_Object *child_obj;
819
820                   external = (Edje_Part_Description_External *) rp->part->default_desc;
821                   child_obj = _edje_external_type_add(rp->part->source,
822                                                       evas_object_evas_get(ed->obj), ed->obj,
823                                                       external->external_params, rp->part->name);
824                   if (child_obj)
825                     {
826                        _edje_real_part_swallow(rp, child_obj, EINA_TRUE);
827                        rp->param1.external_params = _edje_external_params_parse(child_obj,
828                                                                                 external->external_params);
829                        _edje_external_recalc_apply(ed, rp, NULL, rp->chosen_description);
830                     }
831                }
832
833              EINA_LIST_FREE(sources, rp)
834                {
835                   /* XXX: curr_item and pack_it don't require to be NULL since
836                    * XXX: they are just used when source != NULL and type == BOX,
837                    * XXX: and they're always set in this case, but GCC fails to
838                    * XXX: notice that, so let's shut it up
839                    */
840                   Edje_Pack_Element **curr_item = NULL;
841                   unsigned int item_count = 0;
842                   Edje_Pack_Element *pack_it = NULL;
843                   const char *source = NULL;
844
845                   switch (rp->part->type)
846                     {
847                      case EDJE_PART_TYPE_GROUP:
848                         source = rp->part->source;
849                         break;
850                      case EDJE_PART_TYPE_BOX:
851                      case EDJE_PART_TYPE_TABLE:
852                         if (rp->part->items)
853                           {
854                              curr_item = rp->part->items;
855                              item_count = rp->part->items_count;
856                              if (item_count > 0)
857                                {
858                                   pack_it = *curr_item;
859                                   source = pack_it->source;
860                                   item_count--;
861                                   curr_item++;
862                                }
863                           }
864                         break;
865                      default:
866                         /* This list should only be filled by group, box or table, nothing else. */
867                         abort();
868                         continue;
869                     }
870
871                   while (source)
872                     {
873                        Eina_List *l;
874                        Evas_Object *child_obj;
875                        const char *group_path_entry = eina_stringshare_add(source);
876                        const char *data;
877
878                        if (!group_path)
879                          {
880                             group_path = eina_list_append(NULL, eina_stringshare_add(group));
881                             group_path_started = 1;
882                          }
883                        /* make sure that this group isn't already in the tree of parents */
884                        EINA_LIST_FOREACH(group_path, l, data)
885                          {
886                             if (data == group_path_entry)
887                               {
888                                  ERR("recursive loop group '%s' already included inside part '%s' of group '%s' from file '%s'",
889                                      group_path_entry, rp->part->name, group, file);
890                                  ed->load_error = EDJE_LOAD_ERROR_RECURSIVE_REFERENCE;
891                                  eina_stringshare_del(group_path_entry);
892                                  goto on_error;
893                               }
894                          }
895
896                        child_obj = edje_object_add(ed->base.evas);
897                        group_path = eina_list_append(group_path, group_path_entry);
898                        if (rp->part->type == EDJE_PART_TYPE_GROUP)
899                          {
900                             _edje_real_part_swallow(rp, child_obj, EINA_FALSE);
901                          }
902
903                        if (!_edje_object_file_set_internal(child_obj, file, source, rp->part->name, group_path, nested))
904                          {
905                             ERR("impossible to set part '%s' of group '%s' from file '%s' to '%s'",
906                                 rp->part->name, group_path_entry, file, source);
907                             ed->load_error = edje_object_load_error_get(child_obj);
908                             evas_object_del(child_obj);
909                             eina_stringshare_del(group_path_entry);
910                             goto on_error;
911                          }
912
913                        group_path = eina_list_remove(group_path, group_path_entry);
914                        eina_stringshare_del(group_path_entry);
915
916                        edje_object_propagate_callback_add(child_obj,
917                                                           _cb_signal_repeat,
918                                                           obj);
919                        if (rp->part->type == EDJE_PART_TYPE_GROUP)
920                          {
921                             ed->groups = eina_list_append(ed->groups, _edje_fetch(child_obj));
922                             _edje_real_part_swallow(rp, child_obj, EINA_TRUE);
923                             _edje_subobj_register(ed, child_obj);
924                             source = NULL;
925                          }
926                        else
927                          {
928                             if ((rp->type == EDJE_RP_TYPE_CONTAINER) &&
929                                 (rp->typedata.container))
930                               {
931                                  pack_it->parent = rp;
932                                  
933                                  _edje_object_pack_item_hints_set(child_obj, pack_it);
934                                  if (pack_it->name)
935                                    evas_object_name_set(child_obj, pack_it->name);
936                                  
937                                  if (rp->part->type == EDJE_PART_TYPE_BOX)
938                                    {
939                                       _edje_real_part_box_append(rp, child_obj);
940                                       evas_object_data_set(child_obj, "\377 edje.box_item", pack_it);
941                                    }
942                                  else if (rp->part->type == EDJE_PART_TYPE_TABLE)
943                                    {
944                                       _edje_real_part_table_pack(rp, child_obj, pack_it->col, pack_it->row, pack_it->colspan, pack_it->rowspan);
945                                       evas_object_data_set(child_obj, "\377 edje.table_item", pack_it);
946                                    }
947                                  _edje_subobj_register(ed, child_obj);
948                                  evas_object_show(child_obj);
949                                  rp->typedata.container->items = eina_list_append(rp->typedata.container->items, child_obj);
950                                  
951                                  if (item_count > 0)
952                                    {
953                                       pack_it = *curr_item;
954                                       source = pack_it->source;
955                                       curr_item++;
956                                       item_count--;
957                                    }
958                                  else
959                                    {
960                                       source = NULL;
961                                       curr_item = NULL;
962                                       pack_it = NULL;
963                                    }
964                               }
965                          }
966                     }
967                }
968
969              if (group_path_started)
970                {
971                   const char *str;
972
973                   EINA_LIST_FREE(group_path, str)
974                     eina_stringshare_del(str);
975                }
976
977              /* reswallow any swallows that existed before setting the file */
978              if (collect)
979                {
980                   Edje_User_Defined *eud;
981                   Eina_List *boxes = NULL;
982
983                   EINA_LIST_FREE(collect, eud)
984                     {
985                        Evas_Object *child = NULL;
986
987                        switch (eud->type)
988                          {
989                           case EDJE_USER_SWALLOW:
990                              edje_object_part_swallow(obj, eud->part, eud->u.swallow.child);
991                              child = eud->u.swallow.child;
992                              break;
993                           case EDJE_USER_BOX_PACK:
994                              boxes = eina_list_append(boxes, eud);
995                              eud = NULL;
996                              break;
997                           case EDJE_USER_TABLE_PACK:
998                              edje_object_part_table_pack(obj, eud->part, eud->u.table.child,
999                                                          eud->u.table.col, eud->u.table.row,
1000                                                          eud->u.table.colspan, eud->u.table.rowspan);
1001                              child = eud->u.table.child;
1002                              break;
1003                           case EDJE_USER_DRAG_STEP:
1004                              edje_object_part_drag_step_set(obj, eud->part,
1005                                                             eud->u.drag_position.x,
1006                                                             eud->u.drag_position.y);
1007                              break;
1008                           case EDJE_USER_DRAG_PAGE:
1009                              edje_object_part_drag_page_set(obj, eud->part,
1010                                                             eud->u.drag_position.x,
1011                                                             eud->u.drag_position.y);
1012                              break;
1013                           case EDJE_USER_DRAG_VALUE:
1014                              edje_object_part_drag_value_set(obj, eud->part,
1015                                                              eud->u.drag_position.x,
1016                                                              eud->u.drag_position.y);
1017                              break;
1018                           case EDJE_USER_DRAG_SIZE:
1019                              edje_object_part_drag_size_set(obj, eud->part,
1020                                                             eud->u.drag_size.w,
1021                                                             eud->u.drag_size.h);
1022                              break;
1023                           case EDJE_USER_STRING:
1024                              edje_object_part_text_set(obj, eud->part, eud->u.string.text);
1025                              eina_stringshare_del(eud->u.string.text);
1026                              break;
1027                          }
1028                        if (eud) _edje_user_definition_remove(eud, child);
1029                     }
1030
1031                   boxes = eina_list_sort(boxes, -1, _sort_defined_boxes);
1032                   EINA_LIST_FREE(boxes, eud)
1033                     {
1034                        edje_object_part_box_append(obj, eud->part, eud->u.box.child);
1035                        _edje_user_definition_remove(eud, eud->u.box.child);
1036                     }
1037                }
1038
1039              if (edje_object_mirrored_get(obj))
1040                edje_object_signal_emit(obj, "edje,state,rtl", "edje");
1041              else
1042                edje_object_signal_emit(obj, "edje,state,ltr", "edje");
1043
1044              _edje_recalc(ed);
1045              _edje_thaw(ed);
1046              _edje_unblock(ed);
1047              _edje_unref(ed);
1048              ed->load_error = EDJE_LOAD_ERROR_NONE;
1049              _edje_emit(ed, "load", NULL);
1050
1051              /* instantiate 'internal textblock style' */
1052              EINA_LIST_FREE(textblocks, rp)
1053                if (rp->part->default_desc)
1054                  {
1055                     Edje_Part_Description_Text *text;
1056                     Edje_Style *stl  = NULL;
1057                     const char *style;
1058
1059                     text = (Edje_Part_Description_Text *) rp->part->default_desc;
1060                     style = edje_string_get(&text->text.style);
1061                     if (style)
1062                       {
1063                          Eina_List *l;
1064
1065                          EINA_LIST_FOREACH(ed->file->styles, l, stl)
1066                            {
1067                               if ((stl->name) && (!strcmp(stl->name, style))) break;
1068                               stl = NULL;
1069                            }
1070                       }
1071                     if (stl)
1072                       {
1073                          if (evas_object_textblock_style_get(rp->object) != stl->style)
1074                            evas_object_textblock_style_set(rp->object, stl->style);
1075                       }
1076                  }
1077           }
1078         _edje_entry_init(ed);
1079         eina_array_flush(&parts);
1080         evas_event_thaw(tev);
1081         evas_event_thaw_eval(tev);
1082         return 1;
1083      }
1084    else
1085      {
1086         evas_event_thaw(tev);
1087         evas_event_thaw_eval(tev);
1088         return 0;
1089      }
1090    ed->load_error = EDJE_LOAD_ERROR_NONE;
1091    _edje_entry_init(ed);
1092    evas_event_thaw(tev);
1093    evas_event_thaw_eval(tev);
1094    return 1;
1095
1096  on_error:
1097    textblocks = eina_list_free(textblocks);
1098    externals = eina_list_free(externals);
1099    sources = eina_list_free(sources);
1100    eina_array_flush(&parts);
1101    _edje_thaw(ed);
1102    _edje_unblock(ed);
1103    _edje_unref(ed);
1104    _edje_file_del(ed);
1105    if (group_path_started)
1106      {
1107         const char *path;
1108
1109         EINA_LIST_FREE(group_path, path)
1110           eina_stringshare_del(path);
1111      }
1112    evas_event_thaw(tev);
1113    evas_event_thaw_eval(tev);
1114    return 0;
1115 }
1116
1117 void
1118 _edje_file_add(Edje *ed)
1119 {
1120    if (!_edje_edd_edje_file) return;
1121    ed->file = _edje_cache_file_coll_open(ed->path, ed->group,
1122                                          &(ed->load_error),
1123                                          &(ed->collection),
1124                                          ed);
1125
1126    if (!ed->collection)
1127      {
1128         if (ed->file)
1129           {
1130              _edje_cache_file_unref(ed->file);
1131              ed->file = NULL;
1132           }
1133      }
1134 }
1135
1136 static int
1137 _sort_defined_boxes(const void *a, const void *b)
1138 {
1139    const Edje_User_Defined *euda = a;
1140    const Edje_User_Defined *eudb = b;
1141
1142    if (euda->part - eudb->part != 0)
1143      return euda->part - eudb->part;
1144    return euda->u.box.index - eudb->u.box.index;
1145 }
1146
1147 static Eina_List *
1148 _edje_object_collect(Edje *ed)
1149 {
1150    Edje_User_Defined *eud;
1151    Eina_List *collect;
1152    Eina_List *l;
1153
1154    collect = ed->user_defined;
1155    ed->user_defined = NULL;
1156
1157    EINA_LIST_FOREACH(collect, l, eud)
1158      {
1159         switch (eud->type)
1160           {
1161            case EDJE_USER_STRING:
1162               eud->u.string.text = eina_stringshare_ref(eud->u.string.text);
1163               break;
1164            case EDJE_USER_BOX_PACK:
1165               if (eud->u.box.index == -1)
1166                 {
1167                    Edje_User_Defined *search;
1168                    Edje_Real_Part *rp;
1169                    Eina_List *children;
1170                    Eina_List *ls;
1171                    Evas_Object *child;
1172                    int idx = 0;
1173
1174                    rp = _edje_real_part_recursive_get(ed, eud->part);
1175                    if (rp->part->type != EDJE_PART_TYPE_BOX) continue ;
1176
1177                    children = evas_object_box_children_get(rp->object);
1178                    EINA_LIST_FREE(children, child)
1179                      if (!evas_object_data_get(child, "\377 edje.box_item"))
1180                        {
1181                           EINA_LIST_FOREACH(l, ls, search)
1182                             {
1183                                if (search->type == EDJE_USER_BOX_PACK &&
1184                                    search->u.box.child == child &&
1185                                    search->part == eud->part /* beauty of stringshare ! */)
1186                                  {
1187                                     search->u.box.index = idx++;
1188                                     break;
1189                                  }
1190                             }
1191                           _edje_real_part_box_remove(rp, child);
1192                        }
1193                 }
1194               break;
1195            case EDJE_USER_TABLE_PACK:
1196              {
1197                 Edje_Real_Part *rp;
1198
1199                 rp = _edje_real_part_recursive_get(ed, eud->part);
1200                 if (rp->part->type != EDJE_PART_TYPE_TABLE) continue ;
1201
1202                 _edje_real_part_table_unpack(rp, eud->u.table.child);
1203                 break;
1204              }
1205            case EDJE_USER_SWALLOW:
1206               edje_object_part_unswallow(NULL, eud->u.swallow.child);
1207               break;
1208            case EDJE_USER_DRAG_STEP:
1209            case EDJE_USER_DRAG_PAGE:
1210            case EDJE_USER_DRAG_VALUE:
1211            case EDJE_USER_DRAG_SIZE:
1212               break;
1213           }
1214      }
1215
1216    return collect;
1217 }
1218
1219 void
1220 _edje_file_del(Edje *ed)
1221 {
1222    Edje_User_Defined *eud;
1223    Evas *tev = NULL;
1224    
1225    if (ed->obj) tev = evas_object_evas_get(ed->obj);
1226
1227    ed->groups = eina_list_free(ed->groups);
1228
1229    if (tev) evas_event_freeze(tev);
1230    if (ed->freeze_calc)
1231      {
1232         _edje_freeze_calc_list = eina_list_remove(_edje_freeze_calc_list, ed);
1233         ed->freeze_calc = EINA_FALSE;
1234         _edje_freeze_calc_count--;
1235      }
1236    _edje_entry_shutdown(ed);
1237    _edje_message_del(ed);
1238    _edje_block_violate(ed);
1239    _edje_var_shutdown(ed);
1240    _edje_programs_patterns_clean(ed);
1241 //   if (ed->collection)
1242 //     {
1243 //        if (ed->collection->script) _edje_embryo_script_shutdown(ed);
1244 //     }
1245
1246    if (!((ed->file) && (ed->collection)))
1247      {
1248         if (tev)
1249           {
1250              evas_event_thaw(tev);
1251              evas_event_thaw_eval(tev);
1252           }
1253         return;
1254      }
1255
1256    while (ed->user_defined)
1257      {
1258         eud = eina_list_data_get(ed->user_defined);
1259         _edje_user_definition_free(eud);
1260      }
1261
1262    if (ed->table_parts)
1263      {
1264         unsigned int i;
1265         for (i = 0; i < ed->table_parts_size; i++)
1266           {
1267              Edje_Real_Part *rp;
1268
1269              rp = ed->table_parts[i];
1270              if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
1271                _edje_entry_real_part_shutdown(rp);
1272              if (rp->object)
1273                {
1274                   _edje_callbacks_del(rp->object, ed);
1275                   _edje_callbacks_focus_del(rp->object, ed);
1276                   evas_object_del(rp->object);
1277                }
1278              if ((rp->type == EDJE_RP_TYPE_CONTAINER) &&
1279                  (rp->typedata.container))
1280                {
1281                   if (rp->typedata.container->items)
1282                     {
1283                        /* evas_box/table handles deletion of objects */
1284                        rp->typedata.container->items = eina_list_free(rp->typedata.container->items);
1285                     }
1286                   if (rp->typedata.container->anim)
1287                     {
1288                        _edje_box_layout_free_data(rp->typedata.container->anim);
1289                        rp->typedata.container->anim = NULL;
1290                     }
1291                   free(rp->typedata.container);
1292                }
1293              else if ((rp->type == EDJE_RP_TYPE_TEXT) &&
1294                       (rp->typedata.text))
1295                {
1296                   if (rp->typedata.text->text) eina_stringshare_del(rp->typedata.text->text);
1297                   if (rp->typedata.text->font) eina_stringshare_del(rp->typedata.text->font);
1298                   if (rp->typedata.text->cache.in_str) eina_stringshare_del(rp->typedata.text->cache.in_str);
1299                   if (rp->typedata.text->cache.out_str) eina_stringshare_del(rp->typedata.text->cache.out_str);
1300                   free(rp->typedata.text);
1301                }
1302              else if ((rp->type == EDJE_RP_TYPE_SWALLOW) &&
1303                       (rp->typedata.swallow))
1304                {
1305                   if (rp->typedata.swallow->swallowed_object)
1306                     {
1307                        /* Objects swallowed by the app do not get deleted,
1308                         but those internally swallowed (GROUP type) do. */
1309                        switch (rp->part->type)
1310                          {
1311                           case EDJE_PART_TYPE_EXTERNAL:
1312                             _edje_external_parsed_params_free(rp->typedata.swallow->swallowed_object, rp->param1.external_params);
1313                             if (rp->param2)
1314                               _edje_external_parsed_params_free(rp->typedata.swallow->swallowed_object, rp->param2->external_params);
1315                           case EDJE_PART_TYPE_GROUP:
1316                             evas_object_del(rp->typedata.swallow->swallowed_object);
1317                           default:
1318                             break;
1319                          }
1320                        _edje_real_part_swallow_clear(rp);
1321                        rp->typedata.swallow->swallowed_object = NULL;
1322                     }
1323                   free(rp->typedata.swallow);
1324                }
1325
1326              if (rp->custom)
1327                {
1328                   // xxx: lua2
1329                   _edje_collection_free_part_description_clean(rp->part->type,
1330                                                                rp->custom->description,
1331                                                                ed->file->free_strings);
1332                   free(rp->custom->description);
1333                   rp->custom->description = NULL;
1334                }
1335
1336              /* Cleanup optional part. */
1337              free(rp->drag);
1338              free(rp->param1.set);
1339
1340              if (rp->param2)
1341                free(rp->param2->set);
1342              eina_mempool_free(_edje_real_part_state_mp, rp->param2);
1343
1344              if (rp->custom)
1345                free(rp->custom->set);
1346              eina_mempool_free(_edje_real_part_state_mp, rp->custom);
1347              
1348              _edje_unref(rp->edje);
1349              eina_mempool_free(_edje_real_part_mp, rp);
1350           }
1351      }
1352    if ((ed->file) && (ed->collection))
1353      {
1354         Edje_Part *ep;
1355         unsigned int i;
1356
1357         _edje_textblock_styles_del(ed);
1358         for (i = 0; i < ed->collection->parts_count; ++i)
1359           {
1360              ep = ed->collection->parts[i];
1361
1362              _edje_text_part_on_del(ed, ep);
1363              _edje_color_class_on_del(ed, ep);
1364           }
1365
1366         _edje_cache_coll_unref(ed->file, ed->collection);
1367         ed->collection = NULL;
1368      }
1369    if (ed->file)
1370      {
1371 #ifdef HAVE_EIO
1372         ed->file->edjes = eina_list_remove(ed->file->edjes, ed);
1373 #endif
1374         _edje_cache_file_unref(ed->file);
1375         ed->file = NULL;
1376      }
1377    if (ed->actions)
1378      {
1379         Edje_Running_Program *runp;
1380
1381         EINA_LIST_FREE(ed->actions, runp)
1382           {
1383              _edje_anim_count--;
1384              free(runp);
1385           }
1386      }
1387    _edje_animators = eina_list_remove(_edje_animators, ed);
1388    if (ed->pending_actions)
1389      {
1390         Edje_Pending_Program *pp;
1391
1392         EINA_LIST_FREE(ed->pending_actions, pp)
1393           {
1394              ecore_timer_del(pp->timer);
1395              free(pp);
1396           }
1397      }
1398
1399    if (ed->L) _edje_lua2_script_shutdown(ed);
1400    while (ed->subobjs) _edje_subobj_unregister(ed, ed->subobjs->data);
1401    if (ed->table_parts) free(ed->table_parts);
1402    ed->table_parts = NULL;
1403    ed->table_parts_size = 0;
1404    if (ed->table_programs) free(ed->table_programs);
1405    ed->table_programs = NULL;
1406    ed->table_programs_size = 0;
1407    ed->focused_part = NULL;
1408    if (tev)
1409      {
1410         evas_event_thaw(tev);
1411         evas_event_thaw_eval(tev);
1412      }
1413 }
1414
1415 void
1416 _edje_file_free(Edje_File *edf)
1417 {
1418    Edje_Color_Class *ecc;
1419 #ifdef HAVE_EIO
1420    Ecore_Event_Handler *event;
1421 #endif
1422
1423 #define HASH_FREE(Hash)                         \
1424    if (Hash) eina_hash_free(Hash);              \
1425    Hash = NULL;
1426
1427    /* Clean cache before cleaning memory pool */
1428    if (edf->collection_cache) _edje_cache_coll_flush(edf);
1429
1430    HASH_FREE(edf->fonts);
1431    HASH_FREE(edf->collection);
1432    HASH_FREE(edf->data);
1433
1434    if (edf->image_dir)
1435      {
1436         unsigned int i;
1437
1438         if (edf->free_strings)
1439           {
1440              for (i = 0; i < edf->image_dir->entries_count; ++i)
1441                eina_stringshare_del(edf->image_dir->entries[i].entry);
1442           }
1443
1444         /* Sets have been added after edje received eet dictionnary support */
1445         for (i = 0; i < edf->image_dir->sets_count; ++i)
1446           {
1447              Edje_Image_Directory_Set_Entry *se;
1448
1449              EINA_LIST_FREE(edf->image_dir->sets[i].entries, se)
1450                free(se);
1451
1452           }
1453
1454         free(edf->image_dir->entries);
1455         free(edf->image_dir->sets);
1456         free(edf->image_dir);
1457      }
1458    if (edf->sound_dir)
1459      {
1460         unsigned int i;
1461
1462         if (edf->free_strings)
1463           {
1464              for (i = 0; i < edf->sound_dir->samples_count; ++i)
1465                {
1466                   eina_stringshare_del(edf->sound_dir->samples[i].name);
1467                   eina_stringshare_del(edf->sound_dir->samples[i].snd_src);
1468                }
1469
1470              for (i = 0; i < edf->sound_dir->tones_count; ++i)
1471                eina_stringshare_del(edf->sound_dir->tones[i].name);
1472           }
1473         free(edf->sound_dir->samples);
1474         free(edf->sound_dir->tones);
1475         free(edf->sound_dir);
1476      }
1477
1478    if (edf->external_dir)
1479      {
1480         if (edf->external_dir->entries) free(edf->external_dir->entries);
1481         free(edf->external_dir);
1482      }
1483
1484    eina_hash_free(edf->color_hash);
1485    EINA_LIST_FREE(edf->color_classes, ecc)
1486      {
1487         if (edf->free_strings && ecc->name) eina_stringshare_del(ecc->name);
1488         free(ecc);
1489      }
1490
1491    if (edf->collection_patterns) edje_match_patterns_free(edf->collection_patterns);
1492 #ifdef HAVE_EIO
1493    if (edf->timeout) ecore_timer_del(edf->timeout);
1494    EINA_LIST_FREE(edf->handlers, event)
1495      ecore_event_handler_del(event);
1496    eio_monitor_del(edf->monitor);
1497 #endif
1498    if (edf->path) eina_stringshare_del(edf->path);
1499    if (edf->free_strings && edf->compiler) eina_stringshare_del(edf->compiler);
1500    _edje_textblock_style_cleanup(edf);
1501    if (edf->ef) eet_close(edf->ef);
1502    free(edf);
1503 }
1504
1505 static void
1506 _edje_program_free(Edje_Program *pr, Eina_Bool free_strings)
1507 {
1508    Edje_Program_Target *prt;
1509    Edje_Program_After *pa;
1510
1511    if (free_strings)
1512      {
1513         if (pr->name) eina_stringshare_del(pr->name);
1514         if (pr->signal) eina_stringshare_del(pr->signal);
1515         if (pr->source) eina_stringshare_del(pr->source);
1516         if (pr->filter.part) eina_stringshare_del(pr->filter.part);
1517         if (pr->filter.state) eina_stringshare_del(pr->filter.state);
1518         if (pr->state) eina_stringshare_del(pr->state);
1519         if (pr->state2) eina_stringshare_del(pr->state2);
1520    if (pr->sample_name) eina_stringshare_del(pr->sample_name);
1521    if (pr->tone_name) eina_stringshare_del(pr->tone_name);
1522      }
1523    EINA_LIST_FREE(pr->targets, prt)
1524      free(prt);
1525    EINA_LIST_FREE(pr->after, pa)
1526      free(pa);
1527    free(pr);
1528 }
1529
1530 void
1531 _edje_collection_free(Edje_File *edf, Edje_Part_Collection *ec, Edje_Part_Collection_Directory_Entry *ce)
1532 {
1533    unsigned int i;
1534
1535    _edje_embryo_script_shutdown(ec);
1536
1537 #define EDJE_LOAD_PROGRAM_FREE(Array, Ec, It, FreeStrings)      \
1538    for (It = 0; It < Ec->programs.Array##_count; ++It)          \
1539      _edje_program_free(Ec->programs.Array[It], FreeStrings);   \
1540    free(Ec->programs.Array);
1541
1542    EDJE_LOAD_PROGRAM_FREE(fnmatch, ec, i, edf->free_strings);
1543    EDJE_LOAD_PROGRAM_FREE(strcmp, ec, i, edf->free_strings);
1544    EDJE_LOAD_PROGRAM_FREE(strncmp, ec, i, edf->free_strings);
1545    EDJE_LOAD_PROGRAM_FREE(strrncmp, ec, i, edf->free_strings);
1546    EDJE_LOAD_PROGRAM_FREE(nocmp, ec, i, edf->free_strings);
1547
1548    for (i = 0; i < ec->parts_count; ++i)
1549      {
1550         Edje_Part *ep;
1551         unsigned int j;
1552
1553         ep = ec->parts[i];
1554
1555         if (edf->free_strings && ep->name) eina_stringshare_del(ep->name);
1556         if (ep->default_desc)
1557           {
1558              _edje_collection_free_part_description_clean(ep->type, ep->default_desc, edf->free_strings);
1559              ep->default_desc = NULL;
1560           }
1561         for (j = 0; j < ep->other.desc_count; ++j)
1562           _edje_collection_free_part_description_clean(ep->type, ep->other.desc[j], edf->free_strings);
1563
1564         free(ep->other.desc);
1565         /* Alloc for RTL objects in edje_calc.c:_edje_part_description_find() */
1566         if(ep->other.desc_rtl)
1567           free(ep->other.desc_rtl);
1568
1569         free(ep->items);
1570 // technically need this - but we ASSUME we use "one_big" so everything gets
1571 // freed in one go lower down when we del the mempool... but what if pool goes
1572 // "over"?
1573         eina_mempool_free(ce->mp.part, ep);
1574      }
1575    free(ec->parts);
1576    ec->parts = NULL;
1577
1578    if (ec->data)
1579      {
1580         Eina_Iterator *it;
1581         Edje_String *es;
1582
1583         it = eina_hash_iterator_data_new(ec->data);
1584         EINA_ITERATOR_FOREACH(it, es)
1585           free(es);
1586         eina_iterator_free(it);
1587
1588         eina_hash_free(ec->data);
1589      }
1590 #ifdef EDJE_PROGRAM_CACHE
1591    if (ec->prog_cache.no_matches) eina_hash_free(ec->prog_cache.no_matches);
1592    if (ec->prog_cache.matches)
1593      {
1594         eina_hash_foreach(ec->prog_cache.matches,
1595                           _edje_collection_free_prog_cache_matches_free_cb,
1596                           NULL);
1597         eina_hash_free(ec->prog_cache.matches);
1598      }
1599 #endif
1600    if (ec->script) embryo_program_free(ec->script);
1601    _edje_lua2_script_unload(ec);
1602
1603    eina_hash_free(ec->alias);
1604    eina_hash_free(ec->aliased);
1605
1606    /* Destroy all part and description. */
1607    eina_mempool_del(ce->mp.RECTANGLE);
1608    eina_mempool_del(ce->mp.TEXT);
1609    eina_mempool_del(ce->mp.IMAGE);
1610    eina_mempool_del(ce->mp.PROXY);
1611    eina_mempool_del(ce->mp.SWALLOW);
1612    eina_mempool_del(ce->mp.TEXTBLOCK);
1613    eina_mempool_del(ce->mp.GROUP);
1614    eina_mempool_del(ce->mp.BOX);
1615    eina_mempool_del(ce->mp.TABLE);
1616    eina_mempool_del(ce->mp.EXTERNAL);
1617    eina_mempool_del(ce->mp.SPACER);
1618    eina_mempool_del(ce->mp.part);
1619    memset(&ce->mp, 0, sizeof (ce->mp));
1620
1621    eina_mempool_del(ce->mp_rtl.RECTANGLE);
1622    eina_mempool_del(ce->mp_rtl.TEXT);
1623    eina_mempool_del(ce->mp_rtl.IMAGE);
1624    eina_mempool_del(ce->mp_rtl.PROXY);
1625    eina_mempool_del(ce->mp_rtl.SWALLOW);
1626    eina_mempool_del(ce->mp_rtl.TEXTBLOCK);
1627    eina_mempool_del(ce->mp_rtl.GROUP);
1628    eina_mempool_del(ce->mp_rtl.BOX);
1629    eina_mempool_del(ce->mp_rtl.TABLE);
1630    eina_mempool_del(ce->mp_rtl.EXTERNAL);
1631    eina_mempool_del(ce->mp_rtl.SPACER);
1632    memset(&ce->mp_rtl, 0, sizeof (ce->mp_rtl));
1633    free(ec);
1634    ce->ref = NULL;
1635 }
1636
1637 void
1638 _edje_collection_free_part_description_clean(int type, Edje_Part_Description_Common *desc, Eina_Bool free_strings)
1639 {
1640    if (free_strings && desc->color_class) eina_stringshare_del(desc->color_class);
1641
1642    switch (type)
1643      {
1644       case EDJE_PART_TYPE_IMAGE:
1645         {
1646            Edje_Part_Description_Image *img;
1647            unsigned int i;
1648
1649            img = (Edje_Part_Description_Image *) desc;
1650
1651            for (i = 0; i < img->image.tweens_count; ++i)
1652              free(img->image.tweens[i]);
1653            free(img->image.tweens);
1654            break;
1655         }
1656       case EDJE_PART_TYPE_EXTERNAL:
1657         {
1658            Edje_Part_Description_External *external;
1659
1660            external = (Edje_Part_Description_External *) desc;
1661
1662            if (external->external_params)
1663              _edje_external_params_free(external->external_params, free_strings);
1664            break;
1665         }
1666       case EDJE_PART_TYPE_TEXT:
1667       case EDJE_PART_TYPE_TEXTBLOCK:
1668          if (free_strings)
1669            {
1670               Edje_Part_Description_Text *text;
1671
1672               text = (Edje_Part_Description_Text *) desc;
1673
1674               if (text->text.text.str)      eina_stringshare_del(text->text.text.str);
1675               if (text->text.text_class)    eina_stringshare_del(text->text.text_class);
1676               if (text->text.style.str)     eina_stringshare_del(text->text.style.str);
1677               if (text->text.font.str)      eina_stringshare_del(text->text.font.str);
1678            }
1679          break;
1680      }
1681 }
1682
1683 void
1684 _edje_collection_free_part_description_free(int type,
1685                                             Edje_Part_Description_Common *desc,
1686                                             Edje_Part_Collection_Directory_Entry *ce,
1687                                             Eina_Bool free_strings)
1688 {
1689 #define FREE_POOL(Type, Ce, Desc)                                       \
1690    case EDJE_PART_TYPE_##Type: eina_mempool_free(Ce->mp.Type, Desc);    \
1691                                ce->count.Type--;                        \
1692                                break;
1693
1694    _edje_collection_free_part_description_clean(type, desc, free_strings);
1695
1696    switch (type)
1697      {
1698         FREE_POOL(RECTANGLE, ce, desc);
1699         FREE_POOL(TEXT, ce, desc);
1700         FREE_POOL(IMAGE, ce, desc);
1701         FREE_POOL(PROXY, ce, desc);
1702         FREE_POOL(SWALLOW, ce, desc);
1703         FREE_POOL(TEXTBLOCK, ce, desc);
1704         FREE_POOL(GROUP, ce, desc);
1705         FREE_POOL(BOX, ce, desc);
1706         FREE_POOL(TABLE, ce, desc);
1707         FREE_POOL(EXTERNAL, ce, desc);
1708      }
1709 }
1710
1711 #ifdef EDJE_PROGRAM_CACHE
1712 static Eina_Bool
1713 _edje_collection_free_prog_cache_matches_free_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
1714 {
1715    eina_list_free((Eina_List *)data);
1716    return EINA_TRUE;
1717    key = NULL;
1718    hash = NULL;
1719    fdata = NULL;
1720 }
1721 #endif
1722
1723 static void
1724 _edje_object_pack_item_hints_set(Evas_Object *obj, Edje_Pack_Element *it)
1725 {
1726    Evas_Coord w = 0, h = 0, minw, minh;
1727
1728    minw = it->min.w;
1729    minh = it->min.h;
1730
1731    if ((minw <= 0) && (minh <= 0))
1732      {
1733         edje_object_size_min_get(obj, &w, &h);
1734         if ((w <= 0) && (h <= 0))
1735           edje_object_size_min_calc(obj, &w, &h);
1736      }
1737    else
1738      {
1739         w = minw;
1740         h = minh;
1741      }
1742    if (((minw <= 0) && (minh <= 0)) && ((w > 0) || (h > 0)))
1743      evas_object_size_hint_min_set(obj, w, h);
1744    else
1745      evas_object_size_hint_min_set(obj, minw, minh);
1746
1747    evas_object_size_hint_request_set(obj, it->prefer.w, it->prefer.h);
1748    evas_object_size_hint_max_set(obj, it->max.w, it->max.h);
1749    evas_object_size_hint_padding_set(obj, it->padding.l, it->padding.r, it->padding.t, it->padding.b);
1750    evas_object_size_hint_align_set(obj, TO_DOUBLE(it->align.x), TO_DOUBLE(it->align.y));
1751    evas_object_size_hint_weight_set(obj, TO_DOUBLE(it->weight.x), TO_DOUBLE(it->weight.y));
1752    evas_object_size_hint_aspect_set(obj, it->aspect.mode, it->aspect.w, it->aspect.h);
1753
1754    evas_object_resize(obj, w, h);
1755 }
1756
1757 static const char *
1758 _edje_find_alias(Eina_Hash *aliased, char *src, int *length)
1759 {
1760    const char *alias;
1761    char *search;
1762
1763    *length = strlen(src);
1764    if (*length == 0) return NULL;
1765
1766    alias = eina_hash_find(aliased, src);
1767    if (alias) return alias;
1768
1769    search = strrchr(src, EDJE_PART_PATH_SEPARATOR);
1770    if (search == NULL) return NULL;
1771
1772    *search = '\0';
1773    alias = _edje_find_alias(aliased, src, length);
1774    *search = EDJE_PART_PATH_SEPARATOR;
1775
1776    return alias;
1777 }
1778
1779 static void
1780 _cb_signal_repeat(void *data, Evas_Object *obj, const char *sig, const char *source)
1781 {
1782    Edje_Pack_Element *pack_it;
1783    Evas_Object  *parent;
1784    Edje         *ed;
1785    Edje         *ed_parent;
1786    char          new_src[4096]; /* XXX is this max reasonable? */
1787    size_t        length_parent = 0;
1788    size_t        length_index = 0;
1789    size_t        length_source;
1790    int           i = 0;
1791    const char   *alias = NULL;
1792    Edje_Message_Signal emsg;
1793
1794    parent = data;
1795    ed = _edje_fetch(obj);
1796    if (!ed) return;
1797
1798    pack_it = evas_object_data_get(obj, "\377 edje.box_item");
1799    if (!pack_it) pack_it = evas_object_data_get(obj, "\377 edje.table_item");
1800    if (pack_it)
1801      {
1802         if (!pack_it->name)
1803           {
1804              Eina_List *child = NULL;
1805              Evas_Object *o;
1806
1807              if (pack_it->parent->part->type == EDJE_PART_TYPE_BOX)
1808                {
1809                   child = evas_object_box_children_get(pack_it->parent->object);
1810                }
1811              else if (pack_it->parent->part->type == EDJE_PART_TYPE_TABLE)
1812                {
1813                   child = evas_object_table_children_get(pack_it->parent->object);
1814                }
1815
1816              EINA_LIST_FREE(child, o)
1817                {
1818                   if (o == obj) break;
1819                   i++;
1820                }
1821
1822              eina_list_free(child);
1823
1824              length_index = 12;
1825           }
1826         else
1827           {
1828              length_index = strlen(pack_it->name) + 2;
1829           }
1830      }
1831
1832    /* Replace snprint("%s%c%s") == memcpy + *new_src + memcat */
1833    if (ed->parent)
1834      length_parent = strlen(ed->parent);
1835    length_source = strlen(source);
1836    if (length_source + length_parent + 2 + length_index > sizeof(new_src))
1837      return;
1838
1839    if (ed->parent)
1840      memcpy(new_src, ed->parent, length_parent);
1841    if (ed->parent && length_index)
1842      {
1843         new_src[length_parent++] = EDJE_PART_PATH_SEPARATOR_INDEXL;
1844         if (length_index == 12)
1845           length_parent += eina_convert_itoa(i, new_src + length_parent);
1846         else
1847           {
1848              memcpy(new_src + length_parent, pack_it->name, length_index);
1849              length_parent += length_index - 2;
1850           }
1851         new_src[length_parent++] = EDJE_PART_PATH_SEPARATOR_INDEXR;
1852      }
1853
1854    new_src[length_parent] = EDJE_PART_PATH_SEPARATOR;
1855    memcpy(new_src + length_parent + 1, source, length_source + 1);
1856
1857    /* Handle alias renaming */
1858    ed_parent = _edje_fetch(parent);
1859    if (ed_parent && ed_parent->collection && ed_parent->collection->aliased)
1860      {
1861         int length;
1862
1863         alias = _edje_find_alias(ed_parent->collection->aliased, new_src, &length);
1864
1865         if (alias)
1866           {
1867              int origin;
1868
1869              /* Add back the end of the source */
1870              origin = strlen(new_src);
1871              length ++; /* Remove the trailing ':' from the count */
1872              if (origin > length)
1873                {
1874                   char *tmp;
1875                   size_t alias_length;
1876
1877                   alias_length = strlen(alias);
1878                   tmp = alloca(alias_length + origin - length + 2);
1879                   memcpy(tmp, alias, alias_length);
1880                   tmp[alias_length] = EDJE_PART_PATH_SEPARATOR;
1881                   memcpy(tmp + alias_length + 1, new_src + length, origin - length + 1);
1882
1883                   alias = tmp;
1884                }
1885           }
1886      }
1887    
1888    emsg.sig = sig;
1889    emsg.src = alias ? alias : new_src;
1890    emsg.data = NULL;
1891    if (ed_parent)
1892      _edje_message_send(ed_parent, EDJE_QUEUE_SCRIPT, 
1893                         EDJE_MESSAGE_SIGNAL, 0, &emsg);
1894 }