#include "e.h" typedef struct _E_Thumb E_Thumb; struct _E_Thumb { int objid; int w, h; const char *file; const char *key; char *sort_id; struct { int x, y, x_count, y_count; } desk_pan; Eina_List *sigsrc; unsigned char queued E_BITFIELD; unsigned char busy E_BITFIELD; unsigned char done E_BITFIELD; }; /* local subsystem functions */ static void _e_thumb_gen_begin(int objid, const char *file, const char *key, int w, int h, int desk_x, int desk_y, int desk_x_count, int desk_y_count, Eina_List *sigsrc); static void _e_thumb_gen_end(int objid); static void _e_thumb_del_hook(void *data, Evas *e, Evas_Object *obj, void *event_info); static void _e_thumb_hash_add(int objid, Evas_Object *obj); static void _e_thumb_hash_del(int objid); static Evas_Object *_e_thumb_hash_find(int objid); static void _e_thumb_thumbnailers_kill(void); static void _e_thumb_thumbnailers_kill_cancel(void); static Eina_Bool _e_thumb_cb_kill(void *data); static Eina_Bool _e_thumb_cb_exe_event_del(void *data, int type, void *event); /* local subsystem globals */ static Eina_List *_thumbnailers = NULL; static Eina_List *_thumbnailers_exe = NULL; static Eina_List *_thumb_queue = NULL; static int _objid = 0; static Eina_Hash *_thumbs = NULL; static int _pending = 0; static int _num_thumbnailers = 1; static Ecore_Event_Handler *_exe_del_handler = NULL; static Ecore_Timer *_kill_timer = NULL; /* externally accessible functions */ EINTERN int e_thumb_init(void) { _exe_del_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _e_thumb_cb_exe_event_del, NULL); _thumbs = eina_hash_string_superfast_new(NULL); return 1; } EINTERN int e_thumb_shutdown(void) { _e_thumb_thumbnailers_kill_cancel(); _e_thumb_cb_kill(NULL); if (_exe_del_handler) ecore_event_handler_del(_exe_del_handler); _exe_del_handler = NULL; _thumbnailers = eina_list_free(_thumbnailers); E_FREE_LIST(_thumbnailers_exe, ecore_exe_free); _thumb_queue = eina_list_free(_thumb_queue); _objid = 0; eina_hash_free(_thumbs); _thumbs = NULL; _pending = 0; return 1; } static void _thumb_preloaded(void *data, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED) { evas_object_smart_callback_call(data, "e_thumb_gen", NULL); } E_API Evas_Object * e_thumb_icon_add(Evas *evas) { Evas_Object *obj; E_Thumb *eth; obj = e_icon_add(evas); evas_object_smart_callback_add(obj, "preloaded", _thumb_preloaded, obj); _objid++; eth = E_NEW(E_Thumb, 1); eth->objid = _objid; eth->w = 64; eth->h = 64; evas_object_data_set(obj, "e_thumbdata", eth); evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE, _e_thumb_del_hook, NULL); _e_thumb_hash_add(eth->objid, obj); return obj; } E_API void e_thumb_icon_file_set(Evas_Object *obj, const char *file, const char *key) { E_Thumb *eth; eth = evas_object_data_get(obj, "e_thumbdata"); if (!eth) return; eina_stringshare_replace(ð->file, file); eina_stringshare_replace(ð->key, key); E_FREE(eth->sort_id); } E_API void e_thumb_icon_size_set(Evas_Object *obj, int w, int h) { E_Thumb *eth; eth = evas_object_data_get(obj, "e_thumbdata"); if (!eth) return; if ((w < 1) || (h < 1)) return; eth->w = w; eth->h = h; } E_API void e_thumb_icon_begin(Evas_Object *obj) { E_Thumb *eth, *eth2; char buf[4096]; eth = evas_object_data_get(obj, "e_thumbdata"); if (!eth) return; if (eth->queued) return; if (eth->busy) return; if (eth->done) return; if (!eth->file) return; if (!_thumbnailers) { while ((int)eina_list_count(_thumbnailers_exe) < _num_thumbnailers) { Ecore_Exe *exe; snprintf(buf, sizeof(buf), "%s/enlightenment/utils/enlightenment_thumb --nice=%d", e_prefix_lib_get(), e_config->thumb_nice); exe = e_util_exe_safe_run(buf, NULL); _thumbnailers_exe = eina_list_append(_thumbnailers_exe, exe); } _thumb_queue = eina_list_append(_thumb_queue, eth); eth->queued = 1; return; } EINA_LIST_FREE(_thumb_queue, eth2) { eth2->queued = 0; eth2->busy = 1; _pending++; if (_pending == 1) _e_thumb_thumbnailers_kill_cancel(); _e_thumb_gen_begin(eth2->objid, eth2->file, eth2->key, eth2->w, eth2->h, eth2->desk_pan.x, eth2->desk_pan.y, eth2->desk_pan.x_count, eth2->desk_pan.y_count, eth2->sigsrc); } eth->busy = 1; _pending++; if (_pending == 1) _e_thumb_thumbnailers_kill_cancel(); _e_thumb_gen_begin(eth->objid, eth->file, eth->key, eth->w, eth->h, eth->desk_pan.x, eth->desk_pan.y, eth->desk_pan.x_count, eth->desk_pan.y_count, eth->sigsrc); } E_API void e_thumb_icon_end(Evas_Object *obj) { E_Thumb *eth; eth = evas_object_data_get(obj, "e_thumbdata"); if (!eth) return; if (eth->queued) { _thumb_queue = eina_list_remove(_thumb_queue, eth); eth->queued = 0; } if (eth->busy) { _e_thumb_gen_end(eth->objid); eth->busy = 0; _pending--; if (_pending == 0) _e_thumb_thumbnailers_kill(); } } E_API void e_thumb_icon_rethumb(Evas_Object *obj) { E_Thumb *eth; eth = evas_object_data_get(obj, "e_thumbdata"); if (!eth) return; if (eth->done) eth->done = 0; else e_thumb_icon_end(obj); e_thumb_icon_begin(obj); } E_API void e_thumb_desk_pan_set(Evas_Object *obj, int x, int y, int x_count, int y_count) { E_Thumb *eth; eth = evas_object_data_get(obj, "e_thumbdata"); if (!eth) return; eth->desk_pan.x = x; eth->desk_pan.y = y; eth->desk_pan.x_count = x_count; eth->desk_pan.y_count = y_count; } E_API void e_thumb_signal_add(Evas_Object *obj, const char *sig, const char *src) { E_Thumb *eth; eth = evas_object_data_get(obj, "e_thumbdata"); if (!eth) return; eth->sigsrc = eina_list_append(eth->sigsrc, eina_stringshare_add(sig)); eth->sigsrc = eina_list_append(eth->sigsrc, eina_stringshare_add(src)); } #define A(v) (((v) >> 24) & 0xff) #define R(v) (((v) >> 16) & 0xff) #define G(v) (((v) >> 8) & 0xff) #define B(v) (((v)) & 0xff) #define PIX(p, x, y) p[((y) << 2) + (x)] #define PIX2(p, x, y) p[((y) << 1) + (x)] static void _e_thumb_key_load(E_Thumb *eth, const char *icon) { Eet_File *ef; int size = 0; ef = eet_open(icon, EET_FILE_MODE_READ); if (!ef) return; eth->sort_id = eet_read(ef, "/thumbnail/sort_id", &size); if (eth->sort_id) { if (size > 0) eth->sort_id[size - 1] = 0; else { free(eth->sort_id); eth->sort_id = NULL; } } eet_close(ef); } E_API const char * e_thumb_sort_id_get(Evas_Object *obj) { E_Thumb *eth; eth = evas_object_data_get(obj, "e_thumbdata"); if (!eth) return ""; if (!eth->sort_id) return ""; return eth->sort_id; } E_API void e_thumb_client_data(Ecore_Ipc_Event_Client_Data *e) { int objid; char *icon; E_Thumb *eth; Evas_Object *obj; if (!eina_list_data_find(_thumbnailers, e->client)) _thumbnailers = eina_list_prepend(_thumbnailers, e->client); if (e->minor == 2) { objid = e->ref; icon = e->data; if ((icon) && (e->size > 1) && (icon[e->size - 1] == 0)) { obj = _e_thumb_hash_find(objid); if (obj) { eth = evas_object_data_get(obj, "e_thumbdata"); if (eth) { eth->busy = 0; _pending--; eth->done = 1; if (_pending == 0) _e_thumb_thumbnailers_kill(); if (ecore_file_exists(icon)) { e_icon_file_key_set(obj, icon, "/thumbnail/data"); _e_thumb_key_load(eth, icon); e_icon_preload_set(obj, 1); } evas_object_smart_callback_call(obj, "e_thumb_gen", NULL); } } } } if (e->minor == 1) { /* hello message */ EINA_LIST_FREE(_thumb_queue, eth) { eth->queued = 0; eth->busy = 1; _pending++; if (_pending == 1) _e_thumb_thumbnailers_kill_cancel(); _e_thumb_gen_begin(eth->objid, eth->file, eth->key, eth->w, eth->h, eth->desk_pan.x, eth->desk_pan.y, eth->desk_pan.x_count, eth->desk_pan.y_count, eth->sigsrc); } } } E_API void e_thumb_client_del(Ecore_Ipc_Event_Client_Del *e) { if (!eina_list_data_find(_thumbnailers, e->client)) return; _thumbnailers = eina_list_remove(_thumbnailers, e->client); if ((!_thumbs) && (!_thumbnailers)) _objid = 0; } /* local subsystem functions */ static void _e_thumb_gen_begin(int objid, const char *file, const char *key, int w, int h, int desk_x, int desk_y, int desk_x_count, int desk_y_count, Eina_List *sigsrc) { char *buf, *p; int l1, l2, size, *desk; Ecore_Ipc_Client *cli; Eina_List *l; const char *s; /* send thumb req */ // figure out buffer size needed l1 = strlen(file); l2 = 0; if (key) l2 = strlen(key); size = (4 * sizeof(int)); // desk_x/y/count size += l1 + 1; // file size += l2 + 1; // key EINA_LIST_FOREACH(sigsrc, l, s) { size += strlen(s) + 1; } buf = alloca(size); p = buf; // fill in buffer data // data is: // [int]desk_x // [int]desk_y // [int]desk_x_count // [int]desk_y_count // [char[]]file // [char[]]key // optional: // [char[]]sig1 // [char[]]src1 // [char[]]sig2 // [char[]]src2 // ... desk = (int *)(void *)buf; desk[0] = desk_x; desk[1] = desk_y; desk[2] = desk_x_count; desk[3] = desk_y_count; p += (4 * sizeof(int)); strcpy(p, file); p += l1 + 1; if (key) { strcpy(p, key); p += l2 + 1; } else { p[0] = 0; p += 1; } EINA_LIST_FOREACH(sigsrc, l, s) { strcpy(p, s); p += strlen(s) + 1; } // actually send it off cli = eina_list_data_get(_thumbnailers); if (!cli) return; _thumbnailers = eina_list_remove_list(_thumbnailers, _thumbnailers); _thumbnailers = eina_list_append(_thumbnailers, cli); ecore_ipc_client_send(cli, E_IPC_DOMAIN_THUMB, 1, objid, w, h, buf, size); } static void _e_thumb_gen_end(int objid) { Eina_List *l; Ecore_Ipc_Client *cli; /* send thumb cancel */ EINA_LIST_FOREACH(_thumbnailers, l, cli) { ecore_ipc_client_send(cli, E_IPC_DOMAIN_THUMB, 2, objid, 0, 0, NULL, 0); } } static void _e_thumb_del_hook(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED) { E_Thumb *eth; const char *s; eth = evas_object_data_get(obj, "e_thumbdata"); if (!eth) return; evas_object_data_del(obj, "e_thumbdata"); _e_thumb_hash_del(eth->objid); if (eth->busy) { _e_thumb_gen_end(eth->objid); eth->busy = 0; _pending--; if (_pending == 0) _e_thumb_thumbnailers_kill(); } if (eth->queued) _thumb_queue = eina_list_remove(_thumb_queue, eth); if (eth->file) eina_stringshare_del(eth->file); if (eth->key) eina_stringshare_del(eth->key); free(eth->sort_id); EINA_LIST_FREE(eth->sigsrc, s) eina_stringshare_del(s); free(eth); } static void _e_thumb_hash_add(int objid, Evas_Object *obj) { char buf[32]; snprintf(buf, sizeof(buf), "%i", objid); eina_hash_add(_thumbs, buf, obj); } static void _e_thumb_hash_del(int objid) { char buf[32]; snprintf(buf, sizeof(buf), "%i", objid); if (_thumbs) eina_hash_del(_thumbs, buf, NULL); if ((!_thumbs) && (!_thumbnailers)) _objid = 0; } static Evas_Object * _e_thumb_hash_find(int objid) { char buf[32]; snprintf(buf, sizeof(buf), "%i", objid); return eina_hash_find(_thumbs, buf); } static void _e_thumb_thumbnailers_kill(void) { if (_kill_timer) ecore_timer_del(_kill_timer); _kill_timer = ecore_timer_loop_add(1.0, _e_thumb_cb_kill, NULL); } static void _e_thumb_thumbnailers_kill_cancel(void) { if (_kill_timer) ecore_timer_del(_kill_timer); _kill_timer = NULL; } static Eina_Bool _e_thumb_cb_kill(void *data EINA_UNUSED) { Eina_List *l; Ecore_Exe *exe; EINA_LIST_FOREACH(_thumbnailers_exe, l, exe) ecore_exe_terminate(exe); _kill_timer = NULL; return ECORE_CALLBACK_DONE; } static Eina_Bool _e_thumb_cb_exe_event_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) { Ecore_Exe_Event_Del *ev; Ecore_Exe *exe; Eina_List *l; ev = event; EINA_LIST_FOREACH(_thumbnailers_exe, l, exe) { if (exe == ev->exe) { _thumbnailers_exe = eina_list_remove_list(_thumbnailers_exe, l); break; } } if ((!_thumbnailers_exe) && (_thumb_queue)) { while ((int)eina_list_count(_thumbnailers_exe) < _num_thumbnailers) { Ecore_Exe *exe_thumb; char buf[4096]; snprintf(buf, sizeof(buf), "%s/enlightenment/utils/enlightenment_thumb --nice=%d", e_prefix_lib_get(), e_config->thumb_nice); exe_thumb = e_util_exe_safe_run(buf, NULL); _thumbnailers_exe = eina_list_append(_thumbnailers_exe, exe_thumb); } } return ECORE_CALLBACK_PASS_ON; }