#include "edje_private.h" typedef struct _Edje_Table_Items Edje_Table_Items; struct _Edje_Table_Items { Evas_Object *child; const char *part; unsigned short col; unsigned short row; unsigned short colspan; unsigned short rowspan; }; typedef struct _Edje_Drag_Items Edje_Drag_Items; struct _Edje_Drag_Items { const char *part; FLOAT_T x, y, w, h; struct { FLOAT_T x, y; } step; struct { FLOAT_T x, y; } page; }; void _edje_file_add(Edje *ed, const Eina_File *f); /* START - Nested part support */ #define _edje_smart_nested_type "Evas_Smart_Nested" typedef struct _Edje_Nested_Support Edje_Nested_Support; struct _Edje_Nested_Support /* We builed nested-parts list using this struct */ { Evas_Object *o; /* Smart object containing nested children */ unsigned char nested_children_count; /* Number of nested children */ }; Evas_Smart * _edje_smart_nested_smart_class_new(void) { static Evas_Smart_Class _sc = EVAS_SMART_CLASS_INIT_NAME_VERSION("EdjeNested"); static const Evas_Smart_Class *class = NULL; static Evas_Smart *smart; if (smart) return smart; class = &_sc; smart = evas_smart_class_new(class); return smart; } void _edje_extract_mo_files(Edje *ed) { Eina_Strbuf *mo_id_str; const void *data; const char *cache_path; const char *filename; unsigned int crc; time_t t; size_t sz; unsigned int i; int len; cache_path = efreet_cache_home_get(); t = eina_file_mtime_get(ed->file->f); sz = eina_file_size_get(ed->file->f); filename = eina_file_filename_get(ed->file->f); crc = eina_crc(filename, strlen(filename), 0xffffffff, EINA_TRUE); snprintf(ed->file->fid, sizeof(ed->file->fid), "%lld-%lld-%x", (long long int)t, (long long int)sz, crc); mo_id_str = eina_strbuf_new(); for (i = 0; i < ed->file->mo_dir->mo_entries_count; i++) { Edje_Mo *mo_entry; char out[PATH_MAX + PATH_MAX + 128]; char outdir[PATH_MAX]; char *sub_str; char *mo_src; mo_entry = &ed->file->mo_dir->mo_entries[i]; eina_strbuf_append_printf(mo_id_str, "edje/mo/%i/%s/LC_MESSAGES", mo_entry->id, mo_entry->locale); data = eet_read_direct(ed->file->ef, eina_strbuf_string_get(mo_id_str), &len); if (data) { snprintf(outdir, sizeof(outdir), "%s/edje/%s/LC_MESSAGES", cache_path, mo_entry->locale); ecore_file_mkpath(outdir); mo_src = strdup(mo_entry->mo_src); sub_str = strstr(mo_src, ".po"); if (sub_str) sub_str[1] = 'm'; snprintf(out, sizeof(out), "%s/%s-%s", outdir, ed->file->fid, mo_src); if (ecore_file_exists(out)) { if (ed->file->mtime > ecore_file_mod_time(out)) ecore_file_remove(out); } if (!ecore_file_exists(out)) { FILE *f; f = fopen(out, "wb"); if (f) { if (fwrite(data, len, 1, f) != 1) ERR("Could not write mo: %s: %s", out, strerror(errno)); fclose(f); } else ERR("Could not open for writing mo: %s: %s", out, strerror(errno)); } free(mo_src); } eina_strbuf_reset(mo_id_str); } eina_strbuf_free(mo_id_str); } Evas_Object * edje_smart_nested_add(Evas *evas) { return evas_object_smart_add(evas, _edje_smart_nested_smart_class_new()); } /* END - Nested part support */ #ifdef EDJE_PROGRAM_CACHE static Eina_Bool _edje_collection_free_prog_cache_matches_free_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata); #endif static void _edje_object_pack_item_hints_set(Evas_Object *obj, Edje_Pack_Element *it); static void _cb_signal_repeat(void *data, Evas_Object *obj, const char *signal, const char *source); static Eina_Hash *_edje_object_collect(Edje *ed); static int _sort_defined_boxes(const void *a, const void *b); /************************** API Routines **************************/ EOLIAN const char * _efl_canvas_layout_efl_file_file_get(Eo *obj EINA_UNUSED, Edje *ed) { return ed->path; } EOLIAN const char * _efl_canvas_layout_efl_file_group_get(Eo *obj EINA_UNUSED, Edje *ed) { return ed->group; } EOLIAN Eina_Error _efl_canvas_layout_layout_load_error_get(const Eo *obj EINA_UNUSED, Edje *ed) { switch (ed->load_error) { case EDJE_LOAD_ERROR_NONE: return EFL_GFX_IMAGE_LOAD_ERROR_NONE; case EDJE_LOAD_ERROR_GENERIC: return EFL_GFX_IMAGE_LOAD_ERROR_GENERIC; case EDJE_LOAD_ERROR_DOES_NOT_EXIST: return EFL_GFX_IMAGE_LOAD_ERROR_DOES_NOT_EXIST; case EDJE_LOAD_ERROR_PERMISSION_DENIED: return EFL_GFX_IMAGE_LOAD_ERROR_PERMISSION_DENIED; case EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED: return EFL_GFX_IMAGE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; case EDJE_LOAD_ERROR_CORRUPT_FILE: return EFL_GFX_IMAGE_LOAD_ERROR_CORRUPT_FILE; case EDJE_LOAD_ERROR_UNKNOWN_FORMAT: return EFL_GFX_IMAGE_LOAD_ERROR_UNKNOWN_FORMAT; case EDJE_LOAD_ERROR_INCOMPATIBLE_FILE: return EFL_GFX_IMAGE_LOAD_ERROR_INCOMPATIBLE_FILE; case EDJE_LOAD_ERROR_UNKNOWN_COLLECTION: return EFL_GFX_IMAGE_LOAD_ERROR_UNKNOWN_COLLECTION; case EDJE_LOAD_ERROR_RECURSIVE_REFERENCE: return EFL_GFX_IMAGE_LOAD_ERROR_RECURSIVE_REFERENCE; default: break; } return EFL_GFX_IMAGE_LOAD_ERROR_GENERIC; } EAPI const char * edje_load_error_str(Edje_Load_Error error) { switch (error) { case EDJE_LOAD_ERROR_NONE: return "No Error"; case EDJE_LOAD_ERROR_GENERIC: return "Generic Error"; case EDJE_LOAD_ERROR_DOES_NOT_EXIST: return "File Does Not Exist"; case EDJE_LOAD_ERROR_PERMISSION_DENIED: return "Permission Denied"; case EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED: return "Resource Allocation Failed"; case EDJE_LOAD_ERROR_CORRUPT_FILE: return "Corrupt File"; case EDJE_LOAD_ERROR_UNKNOWN_FORMAT: return "Unknown Format"; case EDJE_LOAD_ERROR_INCOMPATIBLE_FILE: return "Incompatible File"; case EDJE_LOAD_ERROR_UNKNOWN_COLLECTION: return "Unknown Collection"; case EDJE_LOAD_ERROR_RECURSIVE_REFERENCE: return "Recursive Reference"; default: return "Unknown Error"; } } EAPI Eina_List * edje_mmap_collection_list(Eina_File *f) { Eina_List *lst = NULL; Edje_File *edf; int error_ret = 0; if (!f) return NULL; edf = _edje_cache_file_coll_open(f, NULL, &error_ret, NULL, NULL); if (edf) { Eina_Iterator *i; const char *key; i = eina_hash_iterator_key_new(edf->collection); EINA_ITERATOR_FOREACH(i, key) lst = eina_list_append(lst, eina_stringshare_add(key)); eina_iterator_free(i); _edje_cache_file_unref(edf); } return lst; } EAPI Eina_List * edje_file_collection_list(const char *file) { Eina_File *f; Eina_List *lst; char *tmp; if ((!file) || (!*file)) return NULL; tmp = eina_vpath_resolve(file); f = eina_file_open(tmp, EINA_FALSE); lst = edje_mmap_collection_list(f); eina_file_close(f); free(tmp); return lst; } EAPI void edje_file_collection_list_free(Eina_List *lst) { while (lst) { if (eina_list_data_get(lst)) eina_stringshare_del(eina_list_data_get(lst)); lst = eina_list_remove(lst, eina_list_data_get(lst)); } } EAPI void edje_mmap_collection_list_free(Eina_List *lst) { edje_file_collection_list_free(lst); } EAPI Eina_Bool edje_mmap_group_exists(Eina_File *f, const char *glob) { Edje_File *edf; int error_ret = 0; Eina_Bool succeed = EINA_FALSE; Eina_Bool is_glob = EINA_FALSE; const char *p; if ((!f) || (!glob)) return EINA_FALSE; edf = _edje_cache_file_coll_open(f, NULL, &error_ret, NULL, NULL); if (!edf) return EINA_FALSE; for (p = glob; *p; p++) { if ((*p == '*') || (*p == '?') || (*p == '[')) { is_glob = EINA_TRUE; break; } } if (is_glob) { if (!edf->collection_patterns) { Edje_Part_Collection_Directory_Entry *ce; Eina_Iterator *i; Eina_List *l = NULL; i = eina_hash_iterator_data_new(edf->collection); EINA_ITERATOR_FOREACH(i, ce) l = eina_list_append(l, ce); eina_iterator_free(i); edf->collection_patterns = edje_match_collection_dir_init(l); eina_list_free(l); } succeed = edje_match_collection_dir_exec(edf->collection_patterns, glob); if (edf->collection_patterns) { edje_match_patterns_free(edf->collection_patterns); edf->collection_patterns = NULL; } } else { if (eina_hash_find(edf->collection, glob)) succeed = EINA_TRUE; } _edje_cache_file_unref(edf); DBG("edje_file_group_exists: '%s', '%s': %i.", eina_file_filename_get(f), glob, succeed); return succeed; } EAPI Eina_Bool edje_mmap_3d_has(Eina_File *f, const char *group) { Edje_Part_Collection *edc = NULL; Edje_File *edf; int err_ret = 0; Eina_Bool r = EINA_FALSE; edf = _edje_cache_file_coll_open(f, group, &err_ret, &edc, NULL); if (!edf || !edc) return EINA_FALSE; if (edc->scene_size.width >0 && edc->scene_size.height > 0) r = EINA_TRUE; _edje_cache_coll_unref(edf, edc); _edje_cache_file_unref(edf); return r; } typedef struct _Edje_File_Iterator Edje_File_Iterator; struct _Edje_File_Iterator { Eina_Iterator iterator; Eina_Iterator *it; }; static Eina_Bool _edje_file_iterator_next(Eina_Iterator *it, void **data) { Edje_File_Iterator *et = (void *)it; Edje_File *edf = NULL; if (!eina_iterator_next(et->it, (void **)&edf)) return EINA_FALSE; *data = edf->f; return EINA_TRUE; } static void * _edje_file_iterator_container(Eina_Iterator *it EINA_UNUSED) { return NULL; } static void _edje_file_iterator_free(Eina_Iterator *it) { Edje_File_Iterator *et = (void *)it; EINA_MAGIC_SET(&et->iterator, 0); eina_iterator_free(et->it); free(et); } EAPI Eina_Iterator * edje_file_iterator_new(void) { Edje_File_Iterator *it; it = calloc(1, sizeof (Edje_File_Iterator)); if (!it) return NULL; EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); it->it = eina_hash_iterator_data_new(_edje_file_hash); it->iterator.version = EINA_ITERATOR_VERSION; it->iterator.next = _edje_file_iterator_next; it->iterator.get_container = _edje_file_iterator_container; it->iterator.free = _edje_file_iterator_free; return &it->iterator; } EAPI Eina_Bool edje_file_group_exists(const char *file, const char *glob) { Eina_File *f; Eina_Bool result; if ((!file) || (!*file) || (!glob)) return EINA_FALSE; f = eina_file_open(file, EINA_FALSE); if (!f) return EINA_FALSE; result = edje_mmap_group_exists(f, glob); eina_file_close(f); return result; } EAPI char * edje_mmap_data_get(const Eina_File *f, const char *key) { Edje_File *edf; char *str = NULL; int error_ret = 0; if (!key) return NULL; edf = _edje_cache_file_coll_open(f, NULL, &error_ret, NULL, NULL); if (edf) { str = (char *)edje_string_get(eina_hash_find(edf->data, key)); if (str) str = strdup(str); _edje_cache_file_unref(edf); } return str; } EAPI char * edje_file_data_get(const char *file, const char *key) { Eina_File *f; char *str; if (!key) return NULL; f = eina_file_open(file, EINA_FALSE); if (!f) { ERR("File [%s] can not be opened.", file); return NULL; } str = edje_mmap_data_get(f, key); eina_file_close(f); return str; } void _edje_programs_patterns_clean(Edje_Part_Collection *edc) { _edje_signals_sources_patterns_clean(&edc->patterns.programs); eina_rbtree_delete(edc->patterns.programs.exact_match, EINA_RBTREE_FREE_CB(edje_match_signal_source_free), NULL); edc->patterns.programs.exact_match = NULL; free(edc->patterns.programs.u.programs.globing); edc->patterns.programs.u.programs.globing = NULL; } void _evas_object_viewport_del(void *data, Evas *_evas EINA_UNUSED, Evas_Object *eo EINA_UNUSED, void *event_info EINA_UNUSED) { Eo* viewport = (Eo*) data; evas_object_del(viewport); } #ifdef HAVE_EPHYSICS static void _edje_physics_world_update_cb(void *data, EPhysics_World *world EINA_UNUSED, void *event_info EINA_UNUSED) { Edje *edje = data; if (EPH_LOAD()) _edje_recalc_do(edje); } #endif Eina_Bool _edje_part_allowed_seat_find(Edje_Real_Part *rp, const char *seat_name) { const char *name; unsigned int i; for (i = 0; i < rp->part->allowed_seats_count; i++) { name = rp->part->allowed_seats[i]->name; if (!strcmp(seat_name, name)) return EINA_TRUE; } return EINA_FALSE; } /* It goes throught the list of registered seats and * set event filters for each of these seats. */ static void _edje_part_seat_filter_apply(Edje *ed, Edje_Real_Part *rp) { Edje_Seat *seat; Eina_List *l; Eina_Bool found; EINA_LIST_FOREACH(ed->seats, l, seat) { found = _edje_part_allowed_seat_find(rp, seat->name); efl_input_seat_event_filter_set(rp->object, seat->device, found); } } /* It goes throught the list of all edje parts and * set event filters for each of these parts. Should be called when * a new seat is added. */ static void _edje_seat_event_filter_apply(Edje *ed, Edje_Seat *seat) { Edje_Real_Part *rp; unsigned short i; Eina_Bool found; for (i = 0; i < ed->table_parts_size; i++) { rp = ed->table_parts[i]; if (!rp->part->allowed_seats) continue; found = _edje_part_allowed_seat_find(rp, seat->name); efl_input_seat_event_filter_set(rp->object, seat->device, found); } } static void _edje_device_add(Edje *ed, Efl_Input_Device *dev) { Edje_Seat *s, *seat = NULL; Eina_Stringshare *name; char sig[256]; Eina_List *l; if (ed->collection && ed->collection->use_custom_seat_names) name = eina_stringshare_add(efl_name_get(dev)); else { ed->seats_count++; name = eina_stringshare_printf("seat%i", ed->seats_count); } EINA_SAFETY_ON_NULL_RETURN(name); EINA_LIST_FOREACH(ed->seats, l, s) { if (s->name != name) continue; seat = s; break; } if (!seat) { seat = calloc(1, sizeof(Edje_Seat)); EINA_SAFETY_ON_NULL_GOTO(seat, seat_err); ed->seats = eina_list_append(ed->seats, seat); seat->name = eina_stringshare_ref(name); } seat->device = dev; snprintf(sig, sizeof(sig), "seat,added,%s,%s", seat->name, efl_name_get(dev)); _edje_emit(ed, sig, ""); _edje_seat_event_filter_apply(ed, seat); seat_err: eina_stringshare_del(name); } static void _edje_device_added_cb(void *data, const Efl_Event *event) { Efl_Input_Device *dev = event->info; Edje *ed = data; if (efl_input_device_type_get(dev) != EFL_INPUT_DEVICE_TYPE_SEAT) return; _edje_device_add(ed, dev); } static void _edje_device_removed_cb(void *data, const Efl_Event *event) { Efl_Input_Device *dev = event->info; Edje_Seat *s, *seat = NULL; Edje *ed = data; char sig[256]; Eina_List *l; if (efl_input_device_type_get(dev) != EFL_INPUT_DEVICE_TYPE_SEAT) return; EINA_LIST_FOREACH(ed->seats, l, s) { if (s->device != dev) continue; seat = s; break; } /* It shouldn't happen. New seats are always registered. */ EINA_SAFETY_ON_NULL_RETURN(seat); seat->device = NULL; snprintf(sig, sizeof(sig), "seat,removed,%s", seat->name); _edje_emit(ed, sig, ""); } static void _edje_device_changed_cb(void *data, const Efl_Event *event) { Efl_Input_Device *dev = event->info; Edje_Seat *s, *seat = NULL; Eina_Stringshare *name; Edje *ed = data; char sig[256]; Eina_List *l; if (efl_input_device_type_get(dev) != EFL_INPUT_DEVICE_TYPE_SEAT) return; EINA_LIST_FOREACH(ed->seats, l, s) { if (s->device != dev) continue; seat = s; break; } /* not registered seat */ if (!seat) return; name = efl_name_get(dev); if (!name) return; /* no name changes */ if (eina_streq(seat->name, name)) return; /* check if device name was changed to match name used on EDC */ EINA_LIST_FOREACH(ed->seats, l, s) { if (eina_streq(s->name, name)) { if (s->device == dev) continue; if (s->device) { WRN("Two seats were detected with the same name: %s.\n" "Fix it or focus will misbehave", name); break; } /* merge seats */ s->device = dev; if (seat->focused_part) s->focused_part = seat->focused_part; ed->seats = eina_list_remove(ed->seats, seat); eina_stringshare_del(seat->name); free(seat); _edje_seat_event_filter_apply(ed, s); return; } } snprintf(sig, sizeof(sig), "seat,renamed,%s,%s", seat->name, name); eina_stringshare_replace(&seat->name, name); _edje_emit(ed, sig, ""); _edje_seat_event_filter_apply(ed, seat); } static void _edje_device_canvas_del(void *data, const Efl_Event *event) { Edje *ed = data; efl_event_callback_del(event->object, EFL_CANVAS_SCENE_EVENT_DEVICE_ADDED, _edje_device_added_cb, ed); efl_event_callback_del(event->object, EFL_CANVAS_SCENE_EVENT_DEVICE_REMOVED, _edje_device_removed_cb, ed); if (ed->collection && ed->collection->use_custom_seat_names) efl_event_callback_del(event->object, EFL_CANVAS_SCENE_EVENT_DEVICE_CHANGED, _edje_device_changed_cb, ed); } static void _edje_devices_add(Edje *ed, Evas *tev) { const Eina_List *devices, *l; Efl_Input_Device *dev; devices = evas_device_list(tev, NULL); EINA_LIST_FOREACH(devices, l, dev) { if (efl_input_device_type_get(dev) == EFL_INPUT_DEVICE_TYPE_SEAT) _edje_device_add(ed, dev); } efl_event_callback_add(tev, EFL_EVENT_DEL, _edje_device_canvas_del, ed); efl_event_callback_add(tev, EFL_CANVAS_SCENE_EVENT_DEVICE_ADDED, _edje_device_added_cb, ed); efl_event_callback_add(tev, EFL_CANVAS_SCENE_EVENT_DEVICE_REMOVED, _edje_device_removed_cb, ed); if (ed->collection && ed->collection->use_custom_seat_names) efl_event_callback_add(tev, EFL_CANVAS_SCENE_EVENT_DEVICE_CHANGED, _edje_device_changed_cb, ed); } Eina_Error _edje_object_file_set_internal(Evas_Object *obj, const Eina_File *file, const char *group, const char *parent, Eina_List *group_path, Eina_Array *nested) { Edje *ed; Evas *tev; Edje_Real_Part *rp; Eina_List *textblocks = NULL; Eina_List *sources = NULL; Eina_List *externals = NULL; Eina_Hash *collect = NULL; unsigned int n; Eina_Array parts; int group_path_started = 0; Evas_Object *nested_smart = NULL; char lang[PATH_MAX]; Eina_Hash *part_match = NULL; /* Get data pointer of top-of-stack */ int idx = eina_array_count(nested) - 1; Edje_Nested_Support *st_nested = (idx >= 0) ? eina_array_data_get(nested, idx) : NULL; ed = _edje_fetch(obj); if (!ed) return EFL_GFX_IMAGE_LOAD_ERROR_GENERIC; if (!group) group = ""; if ((ed->file) && (ed->file->f == file) && (ed->group) && (!strcmp(group, ed->group))) { return 0; } tev = evas_object_evas_get(obj); evas_event_freeze(tev); collect = _edje_object_collect(ed); if (collect) part_match = eina_hash_string_superfast_new(NULL); if (_edje_lua_script_only(ed)) _edje_lua_script_only_shutdown(ed); #ifdef HAVE_EPHYSICS /* clear physics world / shutdown ephysics */ if ((ed->collection) && (ed->collection->physics_enabled) && (ed->world)) { if (EPH_LOAD()) { EPH_CALL(ephysics_world_del)(ed->world); EPH_CALL(ephysics_shutdown)(); } } #endif _edje_file_del(ed); eina_stringshare_replace(&ed->path, file ? eina_file_filename_get(file) : NULL); eina_stringshare_replace(&ed->group, group); ed->parent = eina_stringshare_add(parent); ed->load_error = EDJE_LOAD_ERROR_NONE; _edje_file_add(ed, file); ed->block_break = EINA_FALSE; if (ed->file && ed->file->external_dir) { unsigned int i; for (i = 0; i < ed->file->external_dir->entries_count; ++i) edje_module_load(ed->file->external_dir->entries[i].entry); } _edje_textblock_style_all_update(ed); ed->has_entries = EINA_FALSE; if (ed->file && ed->file->mo_dir) _edje_extract_mo_files(ed); if (ed->collection) { if (ed->collection->parts_count > 0xffff) { ed->load_error = EDJE_LOAD_ERROR_CORRUPT_FILE; _edje_file_del(ed); return EFL_GFX_IMAGE_LOAD_ERROR_CORRUPT_FILE; } eina_array_step_set(&parts, sizeof (Eina_Array), 8); if (ed->collection->prop.orientation != EDJE_ORIENTATION_AUTO) ed->is_rtl = (ed->collection->prop.orientation == EDJE_ORIENTATION_RTL); ed->groups = eina_list_append(ed->groups, ed); if (ed->collection->lua_script_only) { ed->load_error = EDJE_LOAD_ERROR_NONE; _edje_lua_script_only_init(ed); } else { unsigned int i; if (ed->collection->physics_enabled) #ifdef HAVE_EPHYSICS { if (EPH_LOAD()) { EPH_CALL(ephysics_init)(); ed->world = EPH_CALL(ephysics_world_new)(); EPH_CALL(ephysics_world_event_callback_add) (ed->world, EPHYSICS_CALLBACK_WORLD_UPDATE, _edje_physics_world_update_cb, ed); EPH_CALL(ephysics_world_rate_set) (ed->world, ed->collection->physics.world.rate); EPH_CALL(ephysics_world_gravity_set) (ed->world, ed->collection->physics.world.gravity.x, ed->collection->physics.world.gravity.y, ed->collection->physics.world.gravity.z); } } #else ERR("Edje compiled without support to physics."); #endif /* handle multiseat stuff */ _edje_devices_add(ed, tev); /* colorclass stuff */ for (i = 0; i < ed->collection->parts_count; ++i) { Edje_Part *ep; unsigned int k; ep = ed->collection->parts[i]; /* Register any color classes in this parts descriptions. */ if ((ep->default_desc) && (ep->default_desc->color_class)) efl_observable_observer_add(_edje_color_class_member, ep->default_desc->color_class, obj); for (k = 0; k < ep->other.desc_count; k++) { Edje_Part_Description_Common *desc; desc = ep->other.desc[k]; if (desc->color_class) efl_observable_observer_add(_edje_color_class_member, desc->color_class, obj); } } /* sizeclass stuff */ for (i = 0; i < ed->collection->parts_count; ++i) { Edje_Part *ep; unsigned int k; ep = ed->collection->parts[i]; /* Register any size classes in this parts descriptions. */ if ((ep->default_desc) && (ep->default_desc->size_class)) efl_observable_observer_add(_edje_size_class_member, ep->default_desc->size_class, obj); for (k = 0; k < ep->other.desc_count; k++) { Edje_Part_Description_Common *desc; desc = ep->other.desc[k]; if (desc->size_class) efl_observable_observer_add(_edje_size_class_member, desc->size_class, obj); } } /* build real parts */ for (n = 0; n < ed->collection->parts_count; n++) { Edje_Part *ep; Eina_Bool memerr = EINA_FALSE; ep = ed->collection->parts[n]; if (part_match) eina_hash_add(part_match, ep->name, (void*)1); if (ep->nested_children_count) /* Add object to nested parts list */ { st_nested = malloc(sizeof(*st_nested)); nested_smart = st_nested->o = edje_smart_nested_add(tev); /* We add 1 to children_count because the parent object is added to smart obj children as well */ st_nested->nested_children_count = ep->nested_children_count + 1; evas_object_show(st_nested->o); eina_array_push(nested, st_nested); } rp = eina_mempool_malloc(_edje_real_part_mp, sizeof(Edje_Real_Part)); if (!rp) { /* FIXME: destroy all allocated ressource, need to have a common exit point */ ed->load_error = EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; goto on_error; } memset(rp, 0, sizeof (Edje_Real_Part)); if ((ep->dragable.x != 0) || (ep->dragable.y != 0)) { rp->drag = calloc(1, sizeof (Edje_Real_Part_Drag)); if (!rp->drag) { ed->load_error = EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; goto on_error; } rp->drag->step.x = FROM_INT(ep->dragable.step_x); rp->drag->step.y = FROM_INT(ep->dragable.step_y); } // allow part type specific data - this keeps real_part smaller switch (ep->type) { case EDJE_PART_TYPE_TEXT: case EDJE_PART_TYPE_TEXTBLOCK: rp->type = EDJE_RP_TYPE_TEXT; rp->typedata.text = calloc(1, sizeof(Edje_Real_Part_Text)); if (!rp->typedata.text) memerr = EINA_TRUE; break; case EDJE_PART_TYPE_GROUP: case EDJE_PART_TYPE_SWALLOW: case EDJE_PART_TYPE_EXTERNAL: rp->type = EDJE_RP_TYPE_SWALLOW; rp->typedata.swallow = calloc(1, sizeof(Edje_Real_Part_Swallow)); if (!rp->typedata.swallow) memerr = EINA_TRUE; break; case EDJE_PART_TYPE_BOX: case EDJE_PART_TYPE_TABLE: rp->type = EDJE_RP_TYPE_CONTAINER; rp->typedata.container = calloc(1, sizeof(Edje_Real_Part_Container)); if (!rp->typedata.container) memerr = EINA_TRUE; break; default: break; } if (memerr) { if (rp->drag) free(rp->drag); ed->load_error = EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; eina_mempool_free(_edje_real_part_mp, rp); evas_event_thaw(tev); evas_event_thaw_eval(tev); return EFL_GFX_IMAGE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; } _edje_ref(ed); rp->part = ep; eina_array_push(&parts, rp); rp->param1.description = _edje_part_description_find(ed, rp, "default", 0.0, EINA_TRUE); rp->chosen_description = rp->param1.description; if (!rp->param1.description) ERR("no default part description for '%s'!", rp->part->name); switch (ep->type) { case EDJE_PART_TYPE_RECTANGLE: rp->object = evas_object_rectangle_add(ed->base.evas); break; case EDJE_PART_TYPE_VECTOR: rp->object = evas_object_vg_add(ed->base.evas); break; case EDJE_PART_TYPE_PROXY: case EDJE_PART_TYPE_IMAGE: rp->object = evas_object_image_add(ed->base.evas); break; case EDJE_PART_TYPE_SNAPSHOT: rp->object = evas_object_image_filled_add(ed->base.evas); evas_object_image_snapshot_set(rp->object, EINA_TRUE); break; case EDJE_PART_TYPE_TEXT: _edje_text_part_on_add(ed, rp); rp->object = evas_object_text_add(ed->base.evas); evas_object_text_font_source_set(rp->object, ed->path); break; case EDJE_PART_TYPE_GROUP: sources = eina_list_append(sources, rp); EINA_FALLTHROUGH; // fallthrough intentional case EDJE_PART_TYPE_SWALLOW: EINA_FALLTHROUGH; case EDJE_PART_TYPE_EXTERNAL: if (ep->type == EDJE_PART_TYPE_EXTERNAL) externals = eina_list_append(externals, rp); rp->object = evas_object_rectangle_add(ed->base.evas); evas_object_color_set(rp->object, 0, 0, 0, 0); evas_object_pass_events_set(rp->object, 1); evas_object_pointer_mode_set(rp->object, EVAS_OBJECT_POINTER_MODE_NOGRAB); _edje_callbacks_focus_add(rp->object, ed, rp); break; case EDJE_PART_TYPE_TEXTBLOCK: _edje_textblock_styles_add(ed, rp); textblocks = eina_list_append(textblocks, rp); rp->object = evas_object_textblock_add(ed->base.evas); break; case EDJE_PART_TYPE_BOX: sources = eina_list_append(sources, rp); rp->object = evas_object_box_add(ed->base.evas); rp->typedata.container->anim = _edje_box_layout_anim_new(rp->object); break; case EDJE_PART_TYPE_TABLE: sources = eina_list_append(sources, rp); rp->object = evas_object_table_add(ed->base.evas); break; case EDJE_PART_TYPE_GRADIENT: ERR("YOU ARE USING GRADIENT IN PART %s FROM GROUP %s INSIDE FILE %s !! THEY ARE NOW REMOVED !", ep->name, group, eina_file_filename_get(file)); break; case EDJE_PART_TYPE_SPACER: rp->object = NULL; break; case EDJE_PART_TYPE_MESH_NODE: { Evas_Canvas3D_Mesh *mesh = NULL; Evas_Canvas3D_Material *material = NULL; Edje_Part_Description_Mesh_Node *pd_mesh_node; rp->node = efl_add(EVAS_CANVAS3D_NODE_CLASS, ed->base.evas, evas_canvas3d_node_type_set(efl_added, EVAS_CANVAS3D_NODE_TYPE_MESH)); mesh = efl_add(EVAS_CANVAS3D_MESH_CLASS, ed->base.evas); evas_canvas3d_node_mesh_add(rp->node, mesh); pd_mesh_node = (Edje_Part_Description_Mesh_Node*) rp->chosen_description; if (pd_mesh_node->mesh_node.mesh.primitive == EVAS_CANVAS3D_MESH_PRIMITIVE_NONE) { efl_file_simple_load(mesh, ed->file->model_dir->entries[pd_mesh_node->mesh_node.mesh.id].entry, NULL); } else { evas_canvas3d_mesh_frame_add(mesh, 0); } material = efl_add(EVAS_CANVAS3D_MATERIAL_CLASS, ed->base.evas); evas_canvas3d_mesh_frame_material_set(mesh, 0, material); if (pd_mesh_node->mesh_node.texture.need_texture && pd_mesh_node->mesh_node.texture.textured) { Evas_Canvas3D_Texture *texture = NULL; texture = efl_add(EVAS_CANVAS3D_TEXTURE_CLASS, ed->base.evas); evas_canvas3d_material_texture_set(material, EVAS_CANVAS3D_MATERIAL_ATTRIB_DIFFUSE, texture); } rp->object = NULL; } break; case EDJE_PART_TYPE_LIGHT: { Evas_Canvas3D_Light *light = NULL; rp->node = efl_add(EVAS_CANVAS3D_NODE_CLASS, ed->base.evas, evas_canvas3d_node_type_set(efl_added, EVAS_CANVAS3D_NODE_TYPE_LIGHT)); light = efl_add(EVAS_CANVAS3D_LIGHT_CLASS, ed->base.evas); evas_canvas3d_node_light_set(rp->node, light); rp->object = NULL; break; } case EDJE_PART_TYPE_CAMERA: { Evas_Canvas3D_Camera *camera = NULL; rp->node = efl_add(EVAS_CANVAS3D_NODE_CLASS, ed->base.evas, evas_canvas3d_node_type_set(efl_added, EVAS_CANVAS3D_NODE_TYPE_CAMERA)); camera = efl_add(EVAS_CANVAS3D_CAMERA_CLASS, ed->base.evas); evas_canvas3d_node_camera_set(rp->node, camera); rp->object = evas_object_image_filled_add(ed->base.evas); Eo* viewport = efl_add(EFL_CANVAS_SCENE3D_CLASS, ed->base.evas); evas_object_image_source_set(rp->object, viewport); evas_object_show(viewport); evas_object_event_callback_add(rp->object, EVAS_CALLBACK_DEL, _evas_object_viewport_del, viewport); break; } default: ERR("wrong part type %i!", ep->type); break; } if (rp->object) { if (nested_smart) /* Update this pointer to father object only this will make smart object size == father sz */ { rp->nested_smart = nested_smart; nested_smart = NULL; } if (ep->allowed_seats) _edje_part_seat_filter_apply(ed, rp); if (ep->no_render) efl_canvas_object_no_render_set(rp->object, 1); if (st_nested && st_nested->nested_children_count) /* Add this to list of children */ { evas_object_smart_member_add(rp->object, st_nested->o); st_nested->nested_children_count--; /* No more nested children for this obj */ while (st_nested && (st_nested->nested_children_count == 0)) { /* Loop to add smart counter as child */ Evas_Object *p_obj = st_nested->o; st_nested = eina_array_pop(nested); free(st_nested); /* Check for parent in stack */ idx = eina_array_count(nested) - 1; st_nested = (idx >= 0) ? eina_array_data_get(nested, idx) : NULL; if (st_nested) { st_nested->nested_children_count--; evas_object_smart_member_add(p_obj, st_nested->o); } else { evas_object_smart_member_add(p_obj, ed->obj); } } } else evas_object_smart_member_add(rp->object, ed->obj); // evas_object_layer_set(rp->object, evas_object_layer_get(ed->obj)); rp->mouse_events = ep->mouse_events; rp->repeat_events = ep->repeat_events; if (ep->type != EDJE_PART_TYPE_SWALLOW && ep->type != EDJE_PART_TYPE_GROUP && ep->type != EDJE_PART_TYPE_EXTERNAL) { if (rp->mouse_events) { _edje_callbacks_add(rp->object, ed, rp); if (rp->repeat_events) evas_object_repeat_events_set(rp->object, rp->repeat_events); if (ep->pointer_mode != EVAS_OBJECT_POINTER_MODE_AUTOGRAB) evas_object_pointer_mode_set(rp->object, ep->pointer_mode); } else { evas_object_pass_events_set(rp->object, 1); evas_object_pointer_mode_set(rp->object, EVAS_OBJECT_POINTER_MODE_NOGRAB); } efl_canvas_object_anti_alias_set(rp->object, ep->anti_alias); efl_canvas_object_precise_is_inside_set(rp->object, ep->precise_is_inside); } if (rp->part->clip_to_id < 0) evas_object_clip_set(rp->object, ed->base.clipper); } } if (n > 0) { ed->table_parts = malloc(sizeof(Edje_Real_Part *) * n); ed->table_parts_size = n; /* FIXME: check malloc return */ n = eina_array_count(&parts) - 1; while ((rp = eina_array_pop(&parts))) { ed->table_parts[n] = rp; n--; } for (i = 0; i < ed->table_parts_size; i++) { Edje_Real_Part *clip_to = NULL; rp = ed->table_parts[i]; if (rp->param1.description) /* FIXME: prevent rel to gone radient part to go wrong. You may be able to remove this when all theme are correctly rewritten. */ { if (rp->param1.description->rel1.id_x >= 0) rp->param1.description->rel1.id_x %= ed->table_parts_size; if (rp->param1.description->rel1.id_y >= 0) rp->param1.description->rel1.id_y %= ed->table_parts_size; if (rp->param1.description->rel2.id_x >= 0) rp->param1.description->rel2.id_x %= ed->table_parts_size; if (rp->param1.description->rel2.id_y >= 0) rp->param1.description->rel2.id_y %= ed->table_parts_size; } if (rp->param1.description && (rp->param1.description->clip_to_id >= 0)) { clip_to = ed->table_parts[rp->param1.description->clip_to_id % ed->table_parts_size]; ed->has_state_clip = EINA_TRUE; } else if (rp->part->clip_to_id >= 0) clip_to = ed->table_parts[rp->part->clip_to_id % ed->table_parts_size]; if (clip_to && clip_to->object && rp->object) { evas_object_pass_events_set(clip_to->object, 1); evas_object_pointer_mode_set(clip_to->object, EVAS_OBJECT_POINTER_MODE_NOGRAB); evas_object_clip_set(rp->object, clip_to->object); } if (rp->drag) { if (rp->part->dragable.confine_id >= 0) rp->drag->confine_to = ed->table_parts[rp->part->dragable.confine_id % ed->table_parts_size]; if (rp->part->dragable.threshold_id >= 0) rp->drag->threshold = ed->table_parts[rp->part->dragable.threshold_id % ed->table_parts_size]; } if ((rp->type == EDJE_RP_TYPE_SWALLOW) && (rp->typedata.swallow)) { rp->typedata.swallow->swallow_params.min.w = 0; rp->typedata.swallow->swallow_params.min.h = 0; rp->typedata.swallow->swallow_params.max.w = -1; rp->typedata.swallow->swallow_params.max.h = -1; } if (rp->part->type == EDJE_PART_TYPE_TEXT || rp->part->type == EDJE_PART_TYPE_TEXTBLOCK) { Edje_Part_Description_Text *text; text = (Edje_Part_Description_Text *)rp->param1.description; if (text) { if (ed->file->feature_ver < 1) { text->text.id_source = -1; text->text.id_text_source = -1; } if ((rp->type == EDJE_RP_TYPE_TEXT) && (rp->typedata.text)) { if (text->text.id_source >= 0) { rp->typedata.text->source = ed->table_parts[text->text.id_source % ed->table_parts_size]; } if (text->text.id_text_source >= 0) { rp->typedata.text->text_source = ed->table_parts[text->text.id_text_source % ed->table_parts_size]; } } } if ((rp->part->type == EDJE_PART_TYPE_TEXTBLOCK) && rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE) { _edje_entry_real_part_init(ed, rp); if (!ed->has_entries) ed->has_entries = EINA_TRUE; } } } } _edje_ref(ed); _edje_block(ed); _edje_util_freeze(ed); _edje_var_init(ed); for (i = 0; i < ed->table_parts_size; i++) { rp = ed->table_parts[i]; evas_object_show(rp->object); if (_edje_block_break(ed)) break; if (rp->drag) { if (rp->part->dragable.x < 0) rp->drag->val.x = FROM_DOUBLE(1.0); if (rp->part->dragable.y < 0) rp->drag->val.x = FROM_DOUBLE(1.0); _edje_dragable_pos_set(ed, rp, rp->drag->val.x, rp->drag->val.y); } } ed->recalc_call = EINA_TRUE; ed->dirty = EINA_TRUE; #ifdef EDJE_CALC_CACHE ed->all_part_change = EINA_TRUE; #endif if ((evas_object_clipees_has(ed->base.clipper)) && (evas_object_visible_get(obj))) evas_object_show(ed->base.clipper); /* instantiate 'internal swallows' */ EINA_LIST_FREE(externals, rp) { Edje_Part_Description_External *external; Evas_Object *child_obj; external = (Edje_Part_Description_External *)rp->part->default_desc; child_obj = _edje_external_type_add(rp->part->source, evas_object_evas_get(ed->obj), ed->obj, external->external_params, rp->part->name); if (child_obj) { _edje_real_part_swallow(ed, rp, child_obj, EINA_TRUE); rp->param1.external_params = _edje_external_params_parse(child_obj, external->external_params); _edje_external_recalc_apply(ed, rp, NULL, rp->chosen_description); } } EINA_LIST_FREE(sources, rp) { /* XXX: curr_item and pack_it don't require to be NULL since * XXX: they are just used when source != NULL and type == BOX, * XXX: and they're always set in this case, but GCC fails to * XXX: notice that, so let's shut it up */ Edje_Pack_Element **curr_item = NULL; unsigned int item_count = 0; Edje_Pack_Element *pack_it = NULL; const char *source = NULL; switch (rp->part->type) { case EDJE_PART_TYPE_GROUP: source = rp->part->source; break; case EDJE_PART_TYPE_BOX: case EDJE_PART_TYPE_TABLE: if (rp->part->items) { curr_item = rp->part->items; item_count = rp->part->items_count; if (item_count > 0) { pack_it = *curr_item; source = pack_it->source; item_count--; curr_item++; } } break; default: /* This list should only be filled by group, box or table, nothing else. */ abort(); continue; } while (source) { Eina_List *l; Evas_Object *child_obj; Edje_Pack_Element pack_it_copy; const char *group_path_entry = eina_stringshare_add(source); const char *data; if (!group_path) { group_path = eina_list_append(NULL, eina_stringshare_add(group)); group_path_started = 1; } /* make sure that this group isn't already in the tree of parents */ EINA_LIST_FOREACH(group_path, l, data) { if (data == group_path_entry) { ERR("recursive loop group '%s' already included inside part '%s' of group '%s' from file '%s'", group_path_entry, rp->part->name, group, eina_file_filename_get(file)); ed->load_error = EDJE_LOAD_ERROR_RECURSIVE_REFERENCE; eina_stringshare_del(group_path_entry); goto on_error; } } if (pack_it) { pack_it_copy = *pack_it; } else { memset(&pack_it_copy, 0, sizeof (pack_it_copy)); } do { Eina_Error load_error; child_obj = edje_object_add(ed->base.evas); edje_object_mirrored_set(child_obj, edje_object_mirrored_get(ed->obj)); group_path = eina_list_append(group_path, group_path_entry); if (rp->part->type == EDJE_PART_TYPE_GROUP) { _edje_real_part_swallow(ed, rp, child_obj, EINA_FALSE); } load_error = _edje_object_file_set_internal(child_obj, file, source, rp->part->name, group_path, nested); if (load_error) { ERR("impossible to set part '%s' of group '%s' from file '%s' to '%s'", rp->part->name, group_path_entry, eina_file_filename_get(file), source); ed->load_error = edje_object_load_error_get(child_obj); evas_object_del(child_obj); eina_stringshare_del(group_path_entry); goto on_error; } group_path = eina_list_remove(group_path, group_path_entry); edje_object_propagate_callback_add(child_obj, _cb_signal_repeat, obj); if (rp->part->type == EDJE_PART_TYPE_GROUP) { Edje *edg = _edje_fetch(child_obj); ed->groups = eina_list_append(ed->groups, edg); evas_object_data_set(child_obj, "\377 edje.part_obj", rp); _edje_real_part_swallow(ed, rp, child_obj, EINA_FALSE); _edje_subobj_register(ed, child_obj); source = NULL; } else { if ((rp->type == EDJE_RP_TYPE_CONTAINER) && (rp->typedata.container)) { Eina_Strbuf *buf = NULL; const char *name = pack_it_copy.name; pack_it->parent = rp; _edje_object_pack_item_hints_set(child_obj, &pack_it_copy); if (pack_it->spread.h > 1 && pack_it->spread.w >= 1) { buf = eina_strbuf_new(); if (name) eina_strbuf_append_printf(buf, "%s{%i,%i}", name, pack_it_copy.col, pack_it_copy.row); else eina_strbuf_append_printf(buf, "%i,%i", pack_it_copy.col, pack_it_copy.row); name = eina_strbuf_string_get(buf); } if (name) evas_object_name_set(child_obj, name); if (buf) eina_strbuf_free(buf); if (rp->part->type == EDJE_PART_TYPE_BOX) { _edje_real_part_box_append(ed, rp, child_obj); evas_object_data_set(child_obj, "\377 edje.box_item", pack_it); } else if (rp->part->type == EDJE_PART_TYPE_TABLE) { _edje_real_part_table_pack(ed, rp, child_obj, pack_it_copy.col, pack_it_copy.row, pack_it_copy.colspan, pack_it_copy.rowspan); evas_object_data_set(child_obj, "\377 edje.table_item", pack_it); } _edje_subobj_register(ed, child_obj); evas_object_show(child_obj); rp->typedata.container->items = eina_list_append(rp->typedata.container->items, child_obj); } } pack_it_copy.spread.w--; pack_it_copy.col++; if (pack_it_copy.spread.w < 1 && pack_it) { pack_it_copy.col = pack_it->col; pack_it_copy.row++; pack_it_copy.spread.h--; pack_it_copy.spread.w = pack_it->spread.w; } } while (pack_it_copy.spread.h > 0); eina_stringshare_del(group_path_entry); if ((rp->type == EDJE_RP_TYPE_CONTAINER) && (rp->typedata.container)) { if (item_count > 0) { pack_it = *curr_item; source = pack_it->source; curr_item++; item_count--; } else { source = NULL; curr_item = NULL; pack_it = NULL; } } } } if (group_path_started) { const char *str; EINA_LIST_FREE(group_path, str) eina_stringshare_del(str); } /* reswallow any swallows that existed before setting the file */ if (collect) { Edje_User_Defined *eud; Eina_List *boxes = NULL; Eina_Iterator *it; Eina_List *l, *ll; it = eina_hash_iterator_data_new(collect); /* the eud structs get manually freed below */ eina_hash_free_cb_set(collect, (void*)eina_list_free); EINA_ITERATOR_FOREACH(it, l) { EINA_LIST_FOREACH(l, ll, eud) { Evas_Object *child = NULL; if (!eina_hash_find(part_match, eud->part)) { /* part no longer exists */ switch (eud->type) { case EDJE_USER_SWALLOW: child = eud->u.swallow.child; break; case EDJE_USER_BOX_PACK: child = eud->u.box.child; break; case EDJE_USER_TABLE_PACK: child = eud->u.table.child; break; case EDJE_USER_STRING: case EDJE_USER_DRAG_STEP: case EDJE_USER_DRAG_PAGE: case EDJE_USER_DRAG_VALUE: case EDJE_USER_DRAG_SIZE: case EDJE_USER_TEXT_STYLE: case EDJE_USER_TEXT_EXPAND: default: break; } if (child) { WRN("Container part '%s' no longer exists, hiding previously-contained child object", eud->part); evas_object_hide(child); } } else { switch (eud->type) { case EDJE_USER_SWALLOW: edje_object_part_swallow(obj, eud->part, eud->u.swallow.child); child = eud->u.swallow.child; break; case EDJE_USER_BOX_PACK: boxes = eina_list_append(boxes, eud); eud = NULL; break; case EDJE_USER_TABLE_PACK: edje_object_part_table_pack(obj, eud->part, eud->u.table.child, eud->u.table.col, eud->u.table.row, eud->u.table.colspan, eud->u.table.rowspan); child = eud->u.table.child; break; case EDJE_USER_DRAG_STEP: edje_object_part_drag_step_set(obj, eud->part, eud->u.drag_position.x, eud->u.drag_position.y); break; case EDJE_USER_DRAG_PAGE: edje_object_part_drag_page_set(obj, eud->part, eud->u.drag_position.x, eud->u.drag_position.y); break; case EDJE_USER_DRAG_VALUE: edje_object_part_drag_value_set(obj, eud->part, eud->u.drag_position.x, eud->u.drag_position.y); break; case EDJE_USER_DRAG_SIZE: edje_object_part_drag_size_set(obj, eud->part, eud->u.drag_size.w, eud->u.drag_size.h); break; case EDJE_USER_STRING: switch (eud->u.string.type) { case EDJE_TEXT_TYPE_NORMAL: edje_object_part_text_set(obj, eud->part, eud->u.string.text); break; case EDJE_TEXT_TYPE_ESCAPED: edje_object_part_text_escaped_set(obj, eud->part, eud->u.string.text); break; case EDJE_TEXT_TYPE_UNESCAPED: edje_object_part_text_unescaped_set(obj, eud->part, eud->u.string.text); break; } eina_stringshare_del(eud->u.string.text); break; case EDJE_USER_TEXT_STYLE: { Edje_Part_Text_Prop *prop; EINA_LIST_FREE(eud->u.text_style.props, prop) { _canvas_layout_user_text_apply(eud, obj, prop); free(prop); } } break; case EDJE_USER_TEXT_EXPAND: { efl_canvas_layout_part_text_expand_set( efl_part(obj, eud->part), eud->u.text_expand.expand); } break; } } } } eina_iterator_free(it); boxes = eina_list_sort(boxes, -1, _sort_defined_boxes); EINA_LIST_FREE(boxes, eud) edje_object_part_box_append(obj, eud->part, eud->u.box.child); eina_hash_free(part_match); eina_hash_free(collect); } if (_edje_language) snprintf(lang, sizeof(lang), "edje,language,%s", _edje_language); else snprintf(lang, sizeof(lang), "edje,language,%s", "none"); edje_object_signal_emit(obj, lang, "edje"); if (edje_object_mirrored_get(obj)) edje_object_signal_emit(obj, "edje,state,rtl", "edje"); else edje_object_signal_emit(obj, "edje,state,ltr", "edje"); _edje_recalc(ed); _edje_util_thaw(ed); _edje_unblock(ed); _edje_unref(ed); ed->load_error = EDJE_LOAD_ERROR_NONE; _edje_emit(ed, "load", NULL); /* instantiate 'internal textblock style' */ EINA_LIST_FREE(textblocks, rp) if (rp->part->default_desc) { Edje_Part_Description_Text *text; Edje_Style *stl = NULL; const char *style; text = (Edje_Part_Description_Text *)rp->part->default_desc; style = edje_string_get(&text->text.style); if (style) { Eina_List *l; EINA_LIST_FOREACH(ed->file->styles, l, stl) { if ((stl->name) && (!strcmp(stl->name, style))) break; stl = NULL; } } if (stl) { if (evas_object_textblock_style_get(rp->object) != stl->style) evas_object_textblock_style_set(rp->object, stl->style); } } } _edje_entry_init(ed); eina_array_flush(&parts); evas_event_thaw(tev); evas_event_thaw_eval(tev); return 0; } evas_event_thaw(tev); evas_event_thaw_eval(tev); return EFL_GFX_IMAGE_LOAD_ERROR_GENERIC; on_error: eina_list_free(textblocks); eina_list_free(externals); eina_list_free(sources); eina_array_flush(&parts); _edje_util_thaw(ed); _edje_unblock(ed); _edje_unref(ed); _edje_file_del(ed); if (group_path_started) { const char *path; EINA_LIST_FREE(group_path, path) eina_stringshare_del(path); } evas_event_thaw(tev); evas_event_thaw_eval(tev); return EFL_GFX_IMAGE_LOAD_ERROR_GENERIC; } void _edje_file_add(Edje *ed, const Eina_File *f) { if (!_edje_edd_edje_file) return; if (!f) { ed->load_error = EDJE_LOAD_ERROR_DOES_NOT_EXIST; } else { int err = 0; ed->file = _edje_cache_file_coll_open(f, ed->group, &(err), &(ed->collection), ed); ed->load_error = (unsigned short)err; } if (!ed->collection) { if (ed->file) { _edje_cache_file_unref(ed->file); ed->file = NULL; } } } static int _sort_defined_boxes(const void *a, const void *b) { const Edje_User_Defined *euda = a; const Edje_User_Defined *eudb = b; if (euda->part - eudb->part != 0) return euda->part - eudb->part; return euda->u.box.index - eudb->u.box.index; } static Eina_Hash * _edje_object_collect(Edje *ed) { Edje_User_Defined *eud; Eina_Hash *collect; Eina_List *l, *ll; Eina_Iterator *it; collect = ed->user_defined; ed->user_defined = NULL; it = eina_hash_iterator_data_new(collect); EINA_ITERATOR_FOREACH(it, l) { EINA_LIST_FOREACH(l, ll, eud) { switch (eud->type) { case EDJE_USER_STRING: eud->u.string.text = eina_stringshare_ref(eud->u.string.text); break; case EDJE_USER_BOX_PACK: if (eud->u.box.index == -1) { Edje_User_Defined *search; Edje_Real_Part *rp; Eina_List *children; Eina_List *ls; Evas_Object *child; int idx = 0; rp = _edje_real_part_recursive_get(&ed, eud->part); if (rp) { if (rp->part->type != EDJE_PART_TYPE_BOX) continue; children = evas_object_box_children_get(rp->object); EINA_LIST_FREE(children, child) if (!evas_object_data_get(child, "\377 edje.box_item")) { EINA_LIST_FOREACH(l, ls, search) { if (search->type == EDJE_USER_BOX_PACK && search->u.box.child == child && search->part == eud->part /* beauty of stringshare ! */) { search->u.box.index = idx++; break; } } _edje_real_part_box_remove(eud->ed, rp, child); } } } break; case EDJE_USER_TABLE_PACK: { Edje_Real_Part *rp; rp = _edje_real_part_recursive_get(&ed, eud->part); if (rp) { if (rp->part->type != EDJE_PART_TYPE_TABLE) continue; _edje_real_part_table_unpack(eud->ed, rp, eud->u.table.child); } break; } case EDJE_USER_SWALLOW: edje_object_part_unswallow(NULL, eud->u.swallow.child); break; case EDJE_USER_TEXT_STYLE: _canvas_layout_user_text_collect(ed, eud); break; case EDJE_USER_DRAG_STEP: case EDJE_USER_DRAG_PAGE: case EDJE_USER_DRAG_VALUE: case EDJE_USER_DRAG_SIZE: case EDJE_USER_TEXT_EXPAND: break; } } } eina_iterator_free(it); return collect; } void _edje_file_callbacks_del(Edje *ed, Evas *e) { Evas *tev = e; if (!tev) tev = evas_object_evas_get(ed->obj); efl_event_callback_del(tev, EFL_EVENT_DEL, _edje_device_canvas_del, ed); efl_event_callback_del(tev, EFL_CANVAS_SCENE_EVENT_DEVICE_ADDED, _edje_device_added_cb, ed); efl_event_callback_del(tev, EFL_CANVAS_SCENE_EVENT_DEVICE_REMOVED, _edje_device_removed_cb, ed); if (ed->collection && ed->collection->use_custom_seat_names) efl_event_callback_del(tev, EFL_CANVAS_SCENE_EVENT_DEVICE_CHANGED, _edje_device_changed_cb, ed); } void _edje_file_del(Edje *ed) { Evas *tev = NULL; if (ed->obj && (!efl_invalidated_get(ed->obj))) tev = evas_object_evas_get(ed->obj); ed->groups = eina_list_free(ed->groups); if (tev) { _edje_file_callbacks_del(ed, tev); evas_event_freeze(tev); } if (ed->freeze_calc) { _edje_util_freeze_calc_list = eina_list_remove(_edje_util_freeze_calc_list, ed); ed->freeze_calc = EINA_FALSE; _edje_util_freeze_calc_count--; } _edje_entry_shutdown(ed); _edje_message_del(ed); _edje_block_violate(ed); _edje_var_shutdown(ed); if (!((ed->file) && (ed->collection))) { if (tev) { evas_event_thaw(tev); evas_event_thaw_eval(tev); } return; } eina_hash_free(ed->user_defined); ed->user_defined = NULL; if (ed->table_parts) { unsigned int i; for (i = 0; i < ed->table_parts_size; i++) { Edje_Real_Part *rp; #ifdef HAVE_EPHYSICS Evas_Object *face_obj; #endif rp = ed->table_parts[i]; if (!rp) continue; #ifdef HAVE_EPHYSICS EINA_LIST_FREE(rp->body_faces, face_obj) evas_object_del(face_obj); #endif if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE) _edje_entry_real_part_shutdown(ed, rp); if (rp->object) { _edje_callbacks_focus_del(rp->object, ed); _edje_callbacks_del(rp->object, ed); evas_object_del(rp->object); rp->object = NULL; } if (rp->custom) { // xxx: lua2 _edje_collection_free_part_description_clean(rp->part->type, rp->custom->description, ed->file->free_strings); free(rp->custom->description); rp->custom->description = NULL; } if ((rp->type == EDJE_RP_TYPE_CONTAINER) && (rp->typedata.container)) { if (rp->typedata.container->items) { /* evas_box/table handles deletion of objects */ rp->typedata.container->items = eina_list_free(rp->typedata.container->items); } if (rp->typedata.container->anim) { _edje_box_layout_free_data(rp->typedata.container->anim); rp->typedata.container->anim = NULL; } free(rp->typedata.container); rp->typedata.container = NULL; } else if ((rp->type == EDJE_RP_TYPE_TEXT) && (rp->typedata.text)) { eina_stringshare_del(rp->typedata.text->text); eina_stringshare_del(rp->typedata.text->font); eina_stringshare_del(rp->typedata.text->cache.in_str); eina_stringshare_del(rp->typedata.text->cache.out_str); free(rp->typedata.text); rp->typedata.text = NULL; } else if ((rp->type == EDJE_RP_TYPE_SWALLOW) && (rp->typedata.swallow)) { if (rp->typedata.swallow->swallowed_object) { /* Objects swallowed by the app do not get deleted, but those internally swallowed (GROUP type) do. */ switch (rp->part->type) { case EDJE_PART_TYPE_EXTERNAL: _edje_external_parsed_params_free(rp->typedata.swallow->swallowed_object, rp->param1.external_params); if (rp->param2) _edje_external_parsed_params_free(rp->typedata.swallow->swallowed_object, rp->param2->external_params); EINA_FALLTHROUGH; // fallthrough intentional case EDJE_PART_TYPE_GROUP: evas_object_del(rp->typedata.swallow->swallowed_object); rp->typedata.swallow->swallowed_object = NULL; default: break; } _edje_real_part_swallow_clear(ed, rp); } free(rp->typedata.swallow); rp->typedata.swallow = NULL; } /* Cleanup optional part. */ free(rp->drag); rp->drag = NULL; free(rp->param1.set); rp->param1.set = NULL; if (rp->param2) { free(rp->param2->set); rp->param2->set = NULL; #ifdef EDJE_CALC_CACHE _edje_calc_params_clear(&(rp->param2->p)); #endif } eina_mempool_free(_edje_real_part_state_mp, rp->param2); if (rp->custom) { free(rp->custom->set); rp->custom->set = NULL; #ifdef EDJE_CALC_CACHE _edje_calc_params_clear(&(rp->custom->p)); #endif } eina_mempool_free(_edje_real_part_state_mp, rp->custom); if (rp->current) { #ifdef EDJE_CALC_CACHE _edje_calc_params_clear(rp->current); #endif free(rp->current); rp->current = NULL; } _edje_unref(ed); #ifdef EDJE_CALC_CACHE _edje_calc_params_clear(&(rp->param1.p)); #endif eina_mempool_free(_edje_real_part_mp, rp); ed->table_parts[i] = NULL; } } if ((ed->file) && (ed->collection)) { Edje_Part *ep; unsigned int i; for (i = 0; i < ed->collection->parts_count; ++i) { ep = ed->collection->parts[i]; _edje_textblock_styles_del(ed, ep); _edje_text_part_on_del(ed, ep); _edje_color_class_on_del(ed, ep); } _edje_cache_coll_unref(ed->file, ed->collection); ed->collection = NULL; } if (ed->file) { _edje_cache_file_unref(ed->file); ed->file = NULL; } // Cleanup all animator if (ed->actions) { Edje_Running_Program *runp; EINA_LIST_FREE(ed->actions, runp) free(runp); } efl_event_callback_del(ed->obj, EFL_CANVAS_OBJECT_EVENT_ANIMATOR_TICK, _edje_timer_cb, ed); ecore_animator_del(ed->animator); ed->animator = NULL; if (ed->pending_actions) { Edje_Pending_Program *pp; EINA_LIST_FREE(ed->pending_actions, pp) { ecore_timer_del(pp->timer); pp->timer = NULL; free(pp); } } if (ed->seats) { Edje_Seat *seat; EINA_LIST_FREE(ed->seats, seat) { eina_stringshare_del(seat->name); free(seat); } ed->seats_count = 0; } if (ed->L) _edje_lua2_script_shutdown(ed); while (ed->subobjs) _edje_subobj_unregister(ed, ed->subobjs->data); if (ed->table_parts) free(ed->table_parts); ed->table_parts = NULL; ed->table_parts_size = 0; if (tev) { evas_event_thaw(tev); evas_event_thaw_eval(tev); } } void _edje_file_free(Edje_File *edf) { Edje_Color_Tree_Node *ectn; Edje_Color_Class *ecc; Edje_Text_Class *etc; Edje_Size_Class *esc; #define HASH_FREE(Hash) \ if (Hash) eina_hash_free(Hash); \ Hash = NULL; /* Clean cache before cleaning memory pool */ if (edf->collection_cache) _edje_cache_coll_flush(edf); HASH_FREE(edf->fonts); HASH_FREE(edf->collection); HASH_FREE(edf->data); HASH_FREE(edf->image_id_hash); if (edf->requires_count) { unsigned int i; for (i = 0; i < edf->requires_count; i++) eina_stringshare_del(edf->requires[i]); free(edf->requires); } if (edf->image_dir) { unsigned int i; if (edf->free_strings) { for (i = 0; i < edf->image_dir->entries_count; ++i) eina_stringshare_del(edf->image_dir->entries[i].entry); } /* Sets have been added after edje received eet dictionary support */ for (i = 0; i < edf->image_dir->sets_count; ++i) { Edje_Image_Directory_Set_Entry *se; EINA_LIST_FREE(edf->image_dir->sets[i].entries, se) free(se); } free(edf->image_dir->entries); free(edf->image_dir->sets); free(edf->image_dir); } if (edf->sound_dir) { unsigned int i; if (edf->free_strings) { for (i = 0; i < edf->sound_dir->samples_count; ++i) { eina_stringshare_del(edf->sound_dir->samples[i].name); eina_stringshare_del(edf->sound_dir->samples[i].snd_src); } for (i = 0; i < edf->sound_dir->tones_count; ++i) eina_stringshare_del(edf->sound_dir->tones[i].name); } free(edf->sound_dir->samples); free(edf->sound_dir->tones); free(edf->sound_dir); } if (edf->vibration_dir) { unsigned int i; if (edf->free_strings) { for (i = 0; i < edf->vibration_dir->samples_count; ++i) { eina_stringshare_del(edf->vibration_dir->samples[i].name); eina_stringshare_del(edf->vibration_dir->samples[i].src); } } free(edf->vibration_dir->samples); free(edf->vibration_dir); } if (edf->mo_dir) { unsigned int i; if (edf->free_strings) { for (i = 0; i < edf->mo_dir->mo_entries_count; ++i) { eina_stringshare_del(edf->mo_dir->mo_entries[i].locale); eina_stringshare_del(edf->mo_dir->mo_entries[i].mo_src); } } free(edf->mo_dir->mo_entries); free(edf->mo_dir); } if (edf->external_dir) { if (edf->external_dir->entries) free(edf->external_dir->entries); free(edf->external_dir); } eina_hash_free(edf->color_tree_hash); EINA_LIST_FREE(edf->color_tree, ectn) { if (edf->free_strings && ectn->name) eina_stringshare_del(ectn->name); eina_list_free(ectn->color_classes); free(ectn); } eina_hash_free(edf->color_hash); EINA_LIST_FREE(edf->color_classes, ecc) { if (edf->free_strings && ecc->name) eina_stringshare_del(ecc->name); if (edf->free_strings) eina_stringshare_del(ecc->desc); free(ecc); } eina_hash_free(edf->text_hash); EINA_LIST_FREE(edf->text_classes, etc) { if (edf->free_strings) { if (etc->name) eina_stringshare_del(etc->name); if (etc->font) eina_stringshare_del(etc->font); } free(etc); } eina_hash_free(edf->size_hash); EINA_LIST_FREE(edf->size_classes, esc) { if (edf->free_strings && esc->name) eina_stringshare_del(esc->name); free(esc); } if (edf->collection_patterns) edje_match_patterns_free(edf->collection_patterns); if (edf->path) eina_stringshare_del(edf->path); if (edf->free_strings && edf->compiler) eina_stringshare_del(edf->compiler); if (edf->free_strings) eina_stringshare_del(edf->id); _edje_textblock_style_cleanup(edf); if (edf->ef) eet_close(edf->ef); if (edf->f) eina_file_close(edf->f); free(edf); } static void _edje_program_free(Edje_Program *pr, Eina_Bool free_strings) { Edje_Program_Target *prt; Edje_Program_After *pa; if (free_strings) { if (pr->name) eina_stringshare_del(pr->name); if (pr->signal) eina_stringshare_del(pr->signal); if (pr->source) eina_stringshare_del(pr->source); if (pr->filter.part) eina_stringshare_del(pr->filter.part); if (pr->filter.state) eina_stringshare_del(pr->filter.state); if (pr->state) eina_stringshare_del(pr->state); if (pr->state2) eina_stringshare_del(pr->state2); if (pr->sample_name) eina_stringshare_del(pr->sample_name); if (pr->tone_name) eina_stringshare_del(pr->tone_name); if (pr->seat) eina_stringshare_del(pr->seat); } EINA_LIST_FREE(pr->targets, prt) free(prt); EINA_LIST_FREE(pr->after, pa) free(pa); free(pr); } void _edje_collection_free(Edje_File *edf, Edje_Part_Collection *ec, Edje_Part_Collection_Directory_Entry *ce) { unsigned int i; _edje_embryo_script_shutdown(ec); #define EDJE_LOAD_PROGRAM_FREE(Array, Ec, It, FreeStrings) \ for (It = 0; It < Ec->programs.Array##_count; ++It) \ _edje_program_free(Ec->programs.Array[It], FreeStrings); \ free(Ec->programs.Array); EDJE_LOAD_PROGRAM_FREE(fnmatch, ec, i, edf->free_strings); EDJE_LOAD_PROGRAM_FREE(strcmp, ec, i, edf->free_strings); EDJE_LOAD_PROGRAM_FREE(strncmp, ec, i, edf->free_strings); EDJE_LOAD_PROGRAM_FREE(strrncmp, ec, i, edf->free_strings); EDJE_LOAD_PROGRAM_FREE(nocmp, ec, i, edf->free_strings); for (i = 0; i < ec->parts_count; ++i) { Edje_Part *ep; unsigned int j; ep = ec->parts[i]; if (edf->free_strings && ep->name) eina_stringshare_del(ep->name); if (ep->default_desc) { _edje_collection_free_part_description_clean(ep->type, ep->default_desc, edf->free_strings); ep->default_desc = NULL; } for (j = 0; j < ep->other.desc_count; ++j) _edje_collection_free_part_description_clean(ep->type, ep->other.desc[j], edf->free_strings); free(ep->other.desc); /* Alloc for RTL objects in edje_calc.c:_edje_part_description_find() */ if (ep->other.desc_rtl) free(ep->other.desc_rtl); for (j = 0; j < ep->items_count; ++j) free(ep->items[j]); free(ep->items); for (j = 0; j < ep->allowed_seats_count; ++j) { if (edf->free_strings) eina_stringshare_del(ep->allowed_seats[j]->name); free(ep->allowed_seats[j]); } free(ep->allowed_seats); // technically need this - but we ASSUME we use "one_big" so everything gets // freed in one go lower down when we del the mempool... but what if pool goes // "over"? eina_mempool_free(ce->mp->mp.part, ep); } free(ec->parts); ec->parts = NULL; if (ec->data) { Eina_Iterator *it; Edje_String *es; it = eina_hash_iterator_data_new(ec->data); EINA_ITERATOR_FOREACH(it, es) free(es); eina_iterator_free(it); eina_hash_free(ec->data); } #ifdef EDJE_PROGRAM_CACHE if (ec->prog_cache.no_matches) eina_hash_free(ec->prog_cache.no_matches); if (ec->prog_cache.matches) { eina_hash_foreach(ec->prog_cache.matches, _edje_collection_free_prog_cache_matches_free_cb, NULL); eina_hash_free(ec->prog_cache.matches); } #endif _edje_programs_patterns_clean(ec); if (ec->patterns.table_programs) free(ec->patterns.table_programs); ec->patterns.table_programs = NULL; ec->patterns.table_programs_size = 0; if (ec->script) embryo_program_free(ec->script); _edje_lua2_script_unload(ec); eina_hash_free(ec->alias); eina_hash_free(ec->aliased); /* Destroy all part and description. */ edje_cache_emp_free(ce); free(ec); } void _edje_collection_free_part_description_clean(int type, Edje_Part_Description_Common *desc, Eina_Bool free_strings) { unsigned int i; if (free_strings && desc->color_class) eina_stringshare_del(desc->color_class); //clean the map colors if (desc->map.colors) { for (i = 0; i < desc->map.colors_count; i++) free(desc->map.colors[i]); free(desc->map.colors); } switch (type) { case EDJE_PART_TYPE_IMAGE: { Edje_Part_Description_Image *img; img = (Edje_Part_Description_Image *)desc; for (i = 0; i < img->image.tweens_count; ++i) free(img->image.tweens[i]); free(img->image.tweens); break; } case EDJE_PART_TYPE_EXTERNAL: { Edje_Part_Description_External *external; external = (Edje_Part_Description_External *)desc; if (external->external_params) _edje_external_params_free(external->external_params, free_strings); break; } case EDJE_PART_TYPE_TEXT: case EDJE_PART_TYPE_TEXTBLOCK: if (free_strings) { Edje_Part_Description_Text *text; text = (Edje_Part_Description_Text *)desc; eina_stringshare_del(text->text.text.str); eina_stringshare_del(text->text.domain); eina_stringshare_del(text->text.text_class); eina_stringshare_del(text->text.style.str); eina_stringshare_del(text->text.font.str); } break; } } void _edje_collection_free_part_description_free(int type, Edje_Part_Description_Common *desc, Edje_Part_Collection_Directory_Entry *ce, Eina_Bool free_strings) { #define FREE_POOL(Type, Ce, Desc) \ case EDJE_PART_TYPE_##Type: eina_mempool_free(ce->mp->mp.Type, Desc); \ ce->count.Type--; \ break; _edje_collection_free_part_description_clean(type, desc, free_strings); switch (type) { FREE_POOL(RECTANGLE, ce, desc); FREE_POOL(TEXT, ce, desc); FREE_POOL(IMAGE, ce, desc); FREE_POOL(PROXY, ce, desc); FREE_POOL(SWALLOW, ce, desc); FREE_POOL(TEXTBLOCK, ce, desc); FREE_POOL(GROUP, ce, desc); FREE_POOL(BOX, ce, desc); FREE_POOL(TABLE, ce, desc); FREE_POOL(EXTERNAL, ce, desc); FREE_POOL(SNAPSHOT, ce, desc); FREE_POOL(SPACER, ce, desc); } } #ifdef EDJE_PROGRAM_CACHE static Eina_Bool _edje_collection_free_prog_cache_matches_free_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata EINA_UNUSED) { eina_list_free((Eina_List *)data); return EINA_TRUE; key = NULL; hash = NULL; fdata = NULL; } #endif static void _edje_object_pack_item_hints_set(Evas_Object *obj, Edje_Pack_Element *it) { Evas_Coord w = 0, h = 0, minw, minh; Evas_Aspect_Control mode = EVAS_ASPECT_CONTROL_NONE; minw = it->min.w; minh = it->min.h; if ((minw <= 0) && (minh <= 0)) { edje_object_size_min_get(obj, &w, &h); if ((w <= 0) && (h <= 0)) edje_object_size_min_calc(obj, &w, &h); } else { w = minw; h = minh; } if (((minw <= 0) && (minh <= 0)) && ((w > 0) || (h > 0))) evas_object_size_hint_min_set(obj, w, h); else evas_object_size_hint_min_set(obj, minw, minh); evas_object_size_hint_request_set(obj, it->prefer.w, it->prefer.h); evas_object_size_hint_max_set(obj, it->max.w, it->max.h); evas_object_size_hint_padding_set(obj, it->padding.l, it->padding.r, it->padding.t, it->padding.b); evas_object_size_hint_align_set(obj, TO_DOUBLE(it->align.x), TO_DOUBLE(it->align.y)); evas_object_size_hint_weight_set(obj, TO_DOUBLE(it->weight.x), TO_DOUBLE(it->weight.y)); switch (it->aspect.mode) { case EDJE_ASPECT_CONTROL_NONE: mode = EVAS_ASPECT_CONTROL_NONE; break; case EDJE_ASPECT_CONTROL_NEITHER: mode = EVAS_ASPECT_CONTROL_NEITHER; break; case EDJE_ASPECT_CONTROL_HORIZONTAL: mode = EVAS_ASPECT_CONTROL_HORIZONTAL; break; case EDJE_ASPECT_CONTROL_VERTICAL: mode = EVAS_ASPECT_CONTROL_VERTICAL; break; case EDJE_ASPECT_CONTROL_BOTH: mode = EVAS_ASPECT_CONTROL_BOTH; break; } evas_object_size_hint_aspect_set(obj, mode, it->aspect.w, it->aspect.h); evas_object_resize(obj, w, h); } const char * _edje_find_alias(Eina_Hash *aliased, char *src, int *length) { const char *alias; char *search; *length = strlen(src); if (*length == 0) return NULL; alias = eina_hash_find(aliased, src); if (alias) return alias; search = strrchr(src, EDJE_PART_PATH_SEPARATOR); if (search == NULL) return NULL; *search = '\0'; alias = _edje_find_alias(aliased, src, length); *search = EDJE_PART_PATH_SEPARATOR; return alias; } static void _cb_signal_repeat(void *data, Evas_Object *obj, const char *sig, const char *source) { Edje_Pack_Element *pack_it; Evas_Object *parent; Edje *ed; Edje *ed_parent; char new_src[4096]; /* XXX is this max reasonable? */ size_t length_parent = 0; size_t length_index = 0; size_t length_source; int i = 0; const char *alias = NULL; const char *name = NULL; Edje_Message_Signal emsg; parent = data; ed = _edje_fetch(obj); if (!ed) return; pack_it = evas_object_data_get(obj, "\377 edje.box_item"); if (!pack_it) pack_it = evas_object_data_get(obj, "\377 edje.table_item"); name = evas_object_name_get(obj); if (pack_it) { if (!name) name = pack_it->name; if (!name) { Eina_Iterator *it = NULL; Evas_Object *o; if (pack_it->parent->part->type == EDJE_PART_TYPE_BOX) { it = evas_object_box_iterator_new(pack_it->parent->object); } else if (pack_it->parent->part->type == EDJE_PART_TYPE_TABLE) { it = evas_object_table_iterator_new(pack_it->parent->object); } EINA_ITERATOR_FOREACH(it, o) { if (o == obj) break; i++; } eina_iterator_free(it); length_index = 12; } else { length_index = strlen(name) + 2; } } /* Replace snprint("%s%c%s") == memcpy + *new_src + memcat */ if (ed->parent) length_parent = strlen(ed->parent); length_source = strlen(source); if (length_source + length_parent + 2 + length_index > sizeof(new_src)) return; if (ed->parent) memcpy(new_src, ed->parent, length_parent); if (ed->parent && length_index) { new_src[length_parent++] = EDJE_PART_PATH_SEPARATOR_INDEXL; if ((pack_it->parent->part->type == EDJE_PART_TYPE_BOX) || (!name && (pack_it->parent->part->type == EDJE_PART_TYPE_TABLE))) length_parent += eina_convert_itoa(i, new_src + length_parent); else if (name) { memcpy(new_src + length_parent, name, length_index - 2); length_parent += length_index - 2; } new_src[length_parent++] = EDJE_PART_PATH_SEPARATOR_INDEXR; } new_src[length_parent] = EDJE_PART_PATH_SEPARATOR; memcpy(new_src + length_parent + 1, source, length_source + 1); /* Handle alias renaming */ ed_parent = _edje_fetch(parent); if (ed_parent && ed_parent->collection && ed_parent->collection->aliased) { int length; alias = _edje_find_alias(ed_parent->collection->aliased, new_src, &length); if (alias) { int origin; /* Add back the end of the source */ origin = strlen(new_src); length++; /* Remove the trailing ':' from the count */ if (origin > length) { char *tmp; size_t alias_length; alias_length = strlen(alias); tmp = alloca(alias_length + origin - length + 2); memcpy(tmp, alias, alias_length); tmp[alias_length] = EDJE_PART_PATH_SEPARATOR; memcpy(tmp + alias_length + 1, new_src + length, origin - length + 1); alias = tmp; } } } emsg.sig = sig; emsg.src = alias ? alias : new_src; emsg.data = NULL; if (ed_parent) _edje_util_message_send(ed_parent, EDJE_QUEUE_SCRIPT, EDJE_MESSAGE_SIGNAL, 0, &emsg); } EAPI Eina_Bool edje_3d_object_add(Evas_Object *obj, Eo **root_node, Eo *scene) { /* Use default value for state. */ unsigned int i; Edje *ed; Edje_Real_Part *rp; ed = _edje_fetch(obj); if (!ed) { ERR("Cannot get edje from object"); return EINA_FALSE; } if (*root_node == NULL) *root_node = efl_add(EVAS_CANVAS3D_NODE_CLASS, ed->base.evas, evas_canvas3d_node_type_set(efl_added, EVAS_CANVAS3D_NODE_TYPE_NODE)); if (scene == NULL) scene = efl_add(EVAS_CANVAS3D_SCENE_CLASS, ed->base.evas); if ((*root_node == NULL) || (scene == NULL)) { ERR("Cannot create scene and root node"); return EINA_FALSE; } for (i = 0; i < ed->table_parts_size; i++) { rp = ed->table_parts[i]; if (rp->node) { evas_canvas3d_node_member_add(*root_node, rp->node); } if (rp->part->type == EDJE_PART_TYPE_CAMERA) { Evas_Object *viewport; evas_canvas3d_scene_camera_node_set(scene, rp->node); evas_canvas3d_scene_root_node_set(scene, *root_node); evas_canvas3d_scene_size_set(scene, ed->collection->scene_size.width, ed->collection->scene_size.height); evas_canvas3d_scene_background_color_set(scene, 0, 0 ,0 ,0); viewport = evas_object_image_source_get(rp->object); efl_canvas_scene3d_set(viewport, scene); } } return EINA_TRUE; }