update for beta release
[framework/uifw/e17.git] / src / bin / e_icon.c
1 #include "e.h"
2
3 //#define USE_ICON_CACHE
4
5 typedef struct _E_Smart_Data E_Smart_Data;
6 typedef struct _Cache_Item Cache_Item;
7 typedef struct _Cache Cache;
8
9 struct _E_Smart_Data
10 {
11    Evas_Coord x, y, w, h;
12    Evas_Object *obj;
13    Evas_Object *eventarea;
14    Ecore_Timer *timer;
15    int size;
16    int frame, frame_count;
17    const char *fdo;
18    unsigned char fill_inside : 1;
19    unsigned char scale_up : 1;
20    unsigned char preload : 1;
21    unsigned char loading : 1;
22 #ifdef USE_ICON_CACHE
23    const char *file;
24    Cache_Item *ci;
25 #endif
26 };
27
28 struct _Cache_Item
29 {
30   unsigned int timestamp;
31
32   Evas_Object *icon, *obj;
33   const char *id;
34   Eina_List *objs;
35 };
36
37 struct _Cache
38 {
39   Eina_Hash *hash;
40
41   char *file;
42   Eet_File *ef;
43   Ecore_Timer *timer;
44   Eina_List *load_queue;
45 };
46
47 /* local subsystem functions */
48 static void _e_icon_smart_reconfigure(E_Smart_Data *sd);
49 static void _e_icon_smart_init(void);
50 static void _e_icon_smart_add(Evas_Object *obj);
51 static void _e_icon_smart_del(Evas_Object *obj);
52 static void _e_icon_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
53 static void _e_icon_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h);
54 static void _e_icon_smart_show(Evas_Object *obj);
55 static void _e_icon_smart_hide(Evas_Object *obj);
56 static void _e_icon_smart_color_set(Evas_Object *obj, int r, int g, int b, int a);
57 static void _e_icon_smart_clip_set(Evas_Object *obj, Evas_Object * clip);
58 static void _e_icon_smart_clip_unset(Evas_Object *obj);
59 static void _e_icon_obj_prepare(Evas_Object *obj, E_Smart_Data *sd);
60 static void _e_icon_preloaded(void *data, Evas *e, Evas_Object *obj, void *event_info);
61
62 #ifdef USE_ICON_CACHE
63 static Eina_Bool _e_icon_cache_find(Evas_Object *o, const char *file);
64 static void _e_icon_cache_icon_loaded(Cache_Item *ci);
65 static void _e_icon_cache_icon_try_next(Cache_Item *ci);
66 static void _e_icon_cache_item_free(void *data);
67 static void _e_icon_obj_del(void *data, Evas *e, Evas_Object *obj, void *event_info);
68 #endif
69
70 /* local subsystem globals */
71 static Evas_Smart *_e_smart = NULL;
72
73 #ifdef USE_ICON_CACHE
74 static Cache *_cache = NULL;
75 static E_Config_DD *cache_edd = NULL;
76 static E_Config_DD *cache_item_edd = NULL;
77 #define DBG(...)
78 #endif
79
80 EINTERN int
81 e_icon_init(void)
82 {
83 #ifdef USE_ICON_CACHE
84
85    Eet_File *ef;
86    char buf[PATH_MAX];
87
88 #undef T
89 #undef D
90 #define T Cache_Item
91 #define D cache_item_edd
92    D = E_CONFIG_DD_NEW("Cache_Item", T);
93    E_CONFIG_VAL(D, T, timestamp, UINT);
94 #undef T
95 #undef D
96 #define T Cache
97 #define D cache_edd
98    D = E_CONFIG_DD_NEW("Cache", T);
99    E_CONFIG_HASH(D, T, hash, cache_item_edd);
100 #undef T
101 #undef D
102
103    e_user_dir_concat_static(buf, "icon_cache.eet");
104
105    ef = eet_open(buf, EET_FILE_MODE_READ_WRITE);
106    if (!ef) return 1; /* not critical */
107
108    _cache = eet_data_read(ef, cache_edd, "idx");
109    if (!_cache)
110      _cache = E_NEW(Cache, 1);
111
112    if (!_cache->hash)
113      _cache->hash = eina_hash_string_superfast_new(_e_icon_cache_item_free);
114
115    eet_close(ef);
116
117    _cache->file = strdup(buf);
118
119    _cache->ef = NULL;
120 #endif
121    return 1;
122 }
123
124 EINTERN int
125 e_icon_shutdown(void)
126 {
127 #ifdef USE_ICON_CACHE
128    if (_cache)
129      {
130         E_FREE(_cache->file);
131
132         if (_cache->ef)
133           eet_close(_cache->ef);
134
135         if (_cache->load_queue)
136           eina_list_free(_cache->load_queue);
137
138         eina_hash_free(_cache->hash);
139         E_FREE(_cache);
140      }
141
142    E_CONFIG_DD_FREE(cache_item_edd);
143    E_CONFIG_DD_FREE(cache_edd);
144 #endif
145
146    return 1;
147 }
148
149 /* externally accessible functions */
150 EAPI Evas_Object *
151 e_icon_add(Evas *evas)
152 {
153    _e_icon_smart_init();
154    return evas_object_smart_add(evas, _e_smart);
155 }
156
157 static void
158 _e_icon_obj_prepare(Evas_Object *obj, E_Smart_Data *sd)
159 {
160    if (!sd->obj) return;
161
162    if (!strcmp(evas_object_type_get(sd->obj), "edje"))
163      {
164         Evas_Object *pclip;
165
166         pclip = evas_object_clip_get(sd->obj);
167         evas_object_del(sd->obj);
168 #ifdef USE_ICON_CACHE
169         sd->ci = NULL;
170         eina_stringshare_replace(&sd->file, NULL);
171 #endif
172         sd->obj = evas_object_image_add(evas_object_evas_get(obj));
173         evas_object_image_scale_hint_set(sd->obj, EVAS_IMAGE_SCALE_HINT_STATIC);
174         evas_object_smart_member_add(sd->obj, obj);
175         evas_object_event_callback_add(sd->obj, EVAS_CALLBACK_IMAGE_PRELOADED,
176                                        _e_icon_preloaded, obj);
177         evas_object_clip_set(sd->obj, pclip);
178      }
179 }
180
181 static Eina_Bool
182 _frame_anim(void *data)
183 {
184    E_Smart_Data *sd = data;
185    double t;
186    int fr;
187
188    sd->frame++;
189    fr = (sd->frame % (sd->frame_count)) + 1;
190    evas_object_image_animated_frame_set(sd->obj, fr);
191    t = evas_object_image_animated_frame_duration_get(sd->obj, fr, 0);
192    sd->timer = ecore_timer_add(t, _frame_anim, sd);
193    return EINA_FALSE;
194 }
195
196 static int
197 _handle_anim(E_Smart_Data *sd)
198 {
199    double t;
200
201    if (sd->timer) ecore_timer_del(sd->timer);
202    sd->timer = NULL;
203    sd->frame = 0;
204    sd->frame_count = 0;
205    if (!evas_object_image_animated_get(sd->obj)) return 0;
206    // FIXME: hack around jiyouns BUG!!!!!!!!
207      {
208         const char *file;
209         char buf[256];
210         snprintf(buf, sizeof(buf), "%ld", (long)sd);
211         evas_object_image_file_get(sd->obj, &file, NULL);
212         evas_object_image_file_set(sd->obj, file, buf);
213      }
214    sd->frame_count = evas_object_image_animated_frame_count_get(sd->obj);
215    if (sd->frame_count < 2) return 0;
216    evas_object_show(sd->obj);
217    t = evas_object_image_animated_frame_duration_get(sd->obj, sd->frame, 0);
218    sd->timer = ecore_timer_add(t, _frame_anim, sd);
219    return 1;
220 }
221
222 EAPI Eina_Bool
223 e_icon_file_set(Evas_Object *obj, const char *file)
224 {
225    E_Smart_Data *sd;
226    int len;
227
228    if (!file) return EINA_FALSE;
229    if (!(sd = evas_object_smart_data_get(obj)))
230      return EINA_FALSE;
231
232    len = strlen(file);
233    if ((len > 4) && (!strcasecmp(file + len - 4, ".edj")))
234       return e_icon_file_edje_set(obj, file, "icon");
235
236    /* smart code here */
237    _e_icon_obj_prepare(obj, sd);
238    /* FIXME: 64x64 - unhappy about this. use icon size */
239    sd->loading = 0;
240    if (sd->fdo)
241      {
242         eina_stringshare_del(sd->fdo);
243         sd->fdo = NULL;
244      }
245
246    if (sd->timer) ecore_timer_del(sd->timer);
247    sd->timer = NULL;
248    sd->frame = 0;
249    sd->frame_count = 0;
250
251    if (sd->size != 0)
252      evas_object_image_load_size_set(sd->obj, sd->size, sd->size);
253    if (sd->preload) evas_object_hide(sd->obj);
254
255 #ifdef USE_ICON_CACHE
256    if (_e_icon_cache_find(obj, file))
257      {
258         _e_icon_smart_reconfigure(sd);
259         return EINA_TRUE;
260      }
261 #endif
262
263    evas_object_image_file_set(sd->obj, file, NULL);
264    if (evas_object_image_load_error_get(sd->obj) != EVAS_LOAD_ERROR_NONE)
265      return EINA_FALSE;
266
267    if (!_handle_anim(sd))
268      {
269         if (sd->preload)
270           {
271              sd->loading = 1;
272              evas_object_image_preload(sd->obj, EINA_FALSE);
273           }
274         else if (evas_object_visible_get(obj))
275           {
276              evas_object_show(sd->obj);
277 #ifdef USE_ICON_CACHE
278              _e_icon_cache_icon_loaded(sd->ci);
279 #endif
280           }
281      }
282 #ifdef USE_ICON_CACHE
283    else
284      {
285         evas_object_event_callback_del_full(sd->obj, EVAS_CALLBACK_DEL,
286                                             _e_icon_obj_del, obj);
287         _cache->load_queue = eina_list_remove(_cache->load_queue, sd->ci);
288         eina_stringshare_del(sd->ci->id);
289         E_FREE(sd->ci);
290         sd->ci = NULL;
291      }
292 #endif
293
294    _e_icon_smart_reconfigure(sd);
295    return EINA_TRUE;
296 }
297
298 EAPI Eina_Bool
299 e_icon_file_key_set(Evas_Object *obj, const char *file, const char *key)
300 {
301    E_Smart_Data *sd;
302
303    if (!(sd = evas_object_smart_data_get(obj)))
304      return EINA_FALSE;
305
306    /* smart code here */
307    sd->loading = 0;
308    if (sd->fdo)
309      {
310         eina_stringshare_del(sd->fdo);
311         sd->fdo = NULL;
312      }
313
314    if (sd->timer) ecore_timer_del(sd->timer);
315    sd->timer = NULL;
316    sd->frame = 0;
317    sd->frame_count = 0;
318
319    _e_icon_obj_prepare(obj, sd);
320    if (sd->size != 0)
321      evas_object_image_load_size_set(sd->obj, sd->size, sd->size);
322    if (sd->preload) evas_object_hide(sd->obj);
323    evas_object_image_file_set(sd->obj, file, key);
324    if (evas_object_image_load_error_get(sd->obj) != EVAS_LOAD_ERROR_NONE)
325      return EINA_FALSE;
326    if (!_handle_anim(sd))
327      {
328         if (sd->preload)
329           {
330              sd->loading = 1;
331              evas_object_image_preload(sd->obj, 0);
332           }
333         else if (evas_object_visible_get(obj))
334            evas_object_show(sd->obj);
335      }
336    _e_icon_smart_reconfigure(sd);
337    return EINA_TRUE;
338 }
339
340 EAPI Eina_Bool
341 e_icon_file_edje_set(Evas_Object *obj, const char *file, const char *part)
342 {
343    E_Smart_Data *sd;
344
345    if (!(sd = evas_object_smart_data_get(obj)))
346      return EINA_FALSE;
347
348    /* smart code here */
349    if (sd->obj) evas_object_del(sd->obj);
350    sd->loading = 0;
351    if (sd->fdo)
352      {
353         eina_stringshare_del(sd->fdo);
354         sd->fdo = NULL;
355      }
356
357    if (sd->timer) ecore_timer_del(sd->timer);
358    sd->timer = NULL;
359    sd->frame = 0;
360    sd->frame_count = 0;
361
362    sd->obj = edje_object_add(evas_object_evas_get(obj));
363    edje_object_file_set(sd->obj, file, part);
364    if (evas_object_image_load_error_get(sd->obj) != EVAS_LOAD_ERROR_NONE)
365      return EINA_FALSE;
366    if (evas_object_visible_get(obj)) evas_object_show(sd->obj);
367    evas_object_smart_member_add(sd->obj, obj);
368    _e_icon_smart_reconfigure(sd);
369    return EINA_TRUE;
370 }
371
372 EAPI Eina_Bool
373 e_icon_fdo_icon_set(Evas_Object *obj, const char *icon)
374 {
375    E_Smart_Data *sd;
376    const char *path;
377    int len;
378
379    if (!icon) return EINA_TRUE;
380    if (icon[0] == '/') return e_icon_file_set(obj, icon);
381
382    if (!(sd = evas_object_smart_data_get(obj)))
383      return EINA_FALSE;
384
385    if (sd->timer) ecore_timer_del(sd->timer);
386    sd->timer = NULL;
387    sd->frame = 0;
388    sd->frame_count = 0;
389
390    eina_stringshare_replace(&sd->fdo, icon);
391    if (!sd->fdo) return EINA_FALSE;
392
393    path = efreet_icon_path_find(e_config->icon_theme, sd->fdo, sd->size);
394    if (!path) return EINA_TRUE;
395
396    len = strlen(icon);
397    if ((len > 4) && (!strcasecmp(icon + len - 4, ".edj")))
398       return e_icon_file_edje_set(obj, path, "icon");
399
400    /* smart code here */
401    _e_icon_obj_prepare(obj, sd);
402    sd->loading = 0;
403    if (sd->size != 0)
404      evas_object_image_load_size_set(sd->obj, sd->size, sd->size);
405    if (sd->preload) evas_object_hide(sd->obj);
406    evas_object_image_file_set(sd->obj, path, NULL);
407    if (evas_object_image_load_error_get(sd->obj) != EVAS_LOAD_ERROR_NONE)
408      return EINA_FALSE;
409    if (sd->preload)
410      {
411         sd->loading = 1;
412         evas_object_image_preload(sd->obj, 0);
413      }
414    else if (evas_object_visible_get(obj))
415      evas_object_show(sd->obj);
416    _e_icon_smart_reconfigure(sd);
417    return EINA_TRUE;
418 }
419
420 EAPI void
421 e_icon_object_set(Evas_Object *obj, Evas_Object *o)
422 {
423    E_Smart_Data *sd;
424
425    if (!(sd = evas_object_smart_data_get(obj))) return;
426
427    if (sd->timer) ecore_timer_del(sd->timer);
428    sd->timer = NULL;
429    sd->frame = 0;
430    sd->frame_count = 0;
431
432    /* smart code here */
433    if (sd->obj) evas_object_del(sd->obj);
434    sd->loading = 0;
435    sd->obj = o;
436    evas_object_smart_member_add(sd->obj, obj);
437    if (evas_object_visible_get(obj)) evas_object_show(sd->obj);
438    _e_icon_smart_reconfigure(sd);
439 }
440
441 EAPI const char *
442 e_icon_file_get(const Evas_Object *obj)
443 {
444    E_Smart_Data *sd;
445    const char *file;
446
447    if (!(sd = evas_object_smart_data_get(obj))) return NULL;
448 #ifdef USE_ICON_CACHE
449    if (sd->file) return sd->file;
450 #endif
451    if (!strcmp(evas_object_type_get(sd->obj), "edje"))
452      {
453         edje_object_file_get(sd->obj, &file, NULL);
454         return file;
455      }
456    evas_object_image_file_get(sd->obj, &file, NULL);
457    return file;
458 }
459
460 EAPI void
461 e_icon_smooth_scale_set(Evas_Object *obj, Eina_Bool smooth)
462 {
463    E_Smart_Data *sd;
464
465    if (!(sd = evas_object_smart_data_get(obj))) return;
466    if (!strcmp(evas_object_type_get(sd->obj), "edje")) return;
467    evas_object_image_smooth_scale_set(sd->obj, smooth);
468 }
469
470 EAPI Eina_Bool
471 e_icon_smooth_scale_get(const Evas_Object *obj)
472 {
473    E_Smart_Data *sd;
474
475    if (!(sd = evas_object_smart_data_get(obj))) return EINA_FALSE;
476    if (!strcmp(evas_object_type_get(sd->obj), "edje"))
477      return EINA_FALSE;
478    return evas_object_image_smooth_scale_get(sd->obj);
479 }
480
481 EAPI void
482 e_icon_alpha_set(Evas_Object *obj, Eina_Bool alpha)
483 {
484    E_Smart_Data *sd;
485
486    if (!(sd = evas_object_smart_data_get(obj))) return;
487    if (!strcmp(evas_object_type_get(sd->obj), "edje")) return;
488    evas_object_image_alpha_set(sd->obj, alpha);
489 }
490
491 EAPI Eina_Bool
492 e_icon_alpha_get(const Evas_Object *obj)
493 {
494    E_Smart_Data *sd;
495
496    if (!(sd = evas_object_smart_data_get(obj))) return EINA_FALSE;
497    if (!strcmp(evas_object_type_get(sd->obj), "edje")) return EINA_FALSE;
498    return evas_object_image_alpha_get(sd->obj);
499 }
500
501 EAPI void
502 e_icon_preload_set(Evas_Object *obj, Eina_Bool preload)
503 {
504    E_Smart_Data *sd;
505
506    if (!(sd = evas_object_smart_data_get(obj))) return;
507    sd->preload = preload;
508 }
509
510 EAPI Eina_Bool
511 e_icon_preload_get(const Evas_Object *obj)
512 {
513    E_Smart_Data *sd;
514
515    if (!(sd = evas_object_smart_data_get(obj))) return EINA_FALSE;
516    return sd->preload;
517 }
518
519 EAPI void
520 e_icon_size_get(const Evas_Object *obj, int *w, int *h)
521 {
522    E_Smart_Data *sd;
523
524    if (!(sd = evas_object_smart_data_get(obj)))
525      {
526         if (w) *w = 0;
527         if (h) *h = 0;
528         return;
529      }
530    evas_object_image_size_get(sd->obj, w, h);
531 }
532
533 EAPI Eina_Bool
534 e_icon_fill_inside_get(const Evas_Object *obj)
535 {
536    E_Smart_Data *sd;
537
538    if (!(sd = evas_object_smart_data_get(obj))) return EINA_FALSE;
539    return sd->fill_inside;
540 }
541
542 EAPI void
543 e_icon_fill_inside_set(Evas_Object *obj, Eina_Bool fill_inside)
544 {
545    E_Smart_Data *sd;
546
547    if (!(sd = evas_object_smart_data_get(obj))) return;
548    fill_inside = !!fill_inside;
549    if (sd->fill_inside == fill_inside) return;
550    sd->fill_inside = fill_inside;
551    _e_icon_smart_reconfigure(sd);
552 }
553
554 EAPI Eina_Bool
555 e_icon_scale_up_get(const Evas_Object *obj)
556 {
557    E_Smart_Data *sd;
558
559    if (!(sd = evas_object_smart_data_get(obj))) return EINA_FALSE;
560    return sd->scale_up;
561 }
562
563 EAPI void
564 e_icon_scale_up_set(Evas_Object *obj, Eina_Bool scale_up)
565 {
566    E_Smart_Data *sd;
567
568    if (!(sd = evas_object_smart_data_get(obj))) return;
569    scale_up = !!scale_up;
570    if (sd->scale_up == scale_up) return;
571    sd->scale_up = scale_up;
572    _e_icon_smart_reconfigure(sd);
573 }
574
575 EAPI void
576 e_icon_data_set(Evas_Object *obj, void *data, int w, int h)
577 {
578    E_Smart_Data *sd;
579
580    if (!(sd = evas_object_smart_data_get(obj))) return;
581    if (!strcmp(evas_object_type_get(sd->obj), "edje")) return;
582    evas_object_image_size_set(sd->obj, w, h);
583    evas_object_image_data_copy_set(sd->obj, data);
584 }
585
586 EAPI void *
587 e_icon_data_get(const Evas_Object *obj, int *w, int *h)
588 {
589    E_Smart_Data *sd;
590
591    if (!(sd = evas_object_smart_data_get(obj))) return NULL;
592    if (!strcmp(evas_object_type_get(sd->obj), "edje")) return NULL;
593    evas_object_image_size_get(sd->obj, w, h);
594    return evas_object_image_data_get(sd->obj, 0);
595 }
596
597 EAPI void
598 e_icon_scale_size_set(Evas_Object *obj, int size)
599 {
600    E_Smart_Data *sd;
601
602    if (!(sd = evas_object_smart_data_get(obj))) return;
603    sd->size = size;
604    if (!strcmp(evas_object_type_get(sd->obj), "edje"))
605      return;
606    evas_object_image_load_size_set(sd->obj, sd->size, sd->size);
607 }
608
609 EAPI int
610 e_icon_scale_size_get(const Evas_Object *obj)
611 {
612    E_Smart_Data *sd;
613
614    if (!(sd = evas_object_smart_data_get(obj))) return 0;
615    return sd->size;
616 }
617
618 EAPI void
619 e_icon_selected_set(const Evas_Object *obj, Eina_Bool selected)
620 {
621    E_Smart_Data *sd;
622
623    if (!(sd = evas_object_smart_data_get(obj))) return;
624    if (strcmp(evas_object_type_get(sd->obj), "edje")) return;
625    if (selected)
626      edje_object_signal_emit(sd->obj, "e,state,selected", "e");
627    else
628      edje_object_signal_emit(sd->obj, "e,state,unselected", "e");
629 }
630
631 /* local subsystem globals */
632 static void
633 _e_icon_smart_reconfigure(E_Smart_Data *sd)
634 {
635    int iw, ih;
636    Evas_Coord x, y, w, h;
637
638    if (!sd->obj) return;
639    if (!strcmp(evas_object_type_get(sd->obj), "edje"))
640      {
641         w = sd->w;
642         h = sd->h;
643         x = sd->x;
644         y = sd->y;
645         evas_object_move(sd->obj, x, y);
646         evas_object_resize(sd->obj, w, h);
647         evas_object_move(sd->eventarea, x, y);
648         evas_object_resize(sd->eventarea, w, h);
649      }
650    else
651      {
652         ih = 0;
653         ih = 0;
654         evas_object_image_size_get(sd->obj, &iw, &ih);
655         if (iw < 1) iw = 1;
656         if (ih < 1) ih = 1;
657
658         if (sd->fill_inside)
659           {
660              w = sd->w;
661              h = ((double)ih * w) / (double)iw;
662              if (h > sd->h)
663                {
664                   h = sd->h;
665                   w = ((double)iw * h) / (double)ih;
666                }
667           }
668         else
669           {
670              w = sd->w;
671              h = ((double)ih * w) / (double)iw;
672              if (h < sd->h)
673                {
674                   h = sd->h;
675                   w = ((double)iw * h) / (double)ih;
676                }
677           }
678         if (!sd->scale_up)
679           {
680              if ((w > iw) || (h > ih))
681                {
682                   w = iw;
683                   h = ih;
684                }
685           }
686         x = sd->x + ((sd->w - w) / 2);
687         y = sd->y + ((sd->h - h) / 2);
688         evas_object_move(sd->obj, x, y);
689         evas_object_image_fill_set(sd->obj, 0, 0, w, h);
690         evas_object_resize(sd->obj, w, h);
691         evas_object_move(sd->eventarea, x, y);
692         evas_object_resize(sd->eventarea, w, h);
693      }
694 }
695
696 static void
697 _e_icon_smart_init(void)
698 {
699    if (_e_smart) return;
700      {
701         static Evas_Smart_Class sc = EVAS_SMART_CLASS_INIT_NAME_VERSION("e_icon");
702         if (!sc.add)
703           {
704              sc.add = _e_icon_smart_add;
705              sc.del = _e_icon_smart_del;
706              sc.move = _e_icon_smart_move;
707              sc.resize = _e_icon_smart_resize;
708              sc.show = _e_icon_smart_show;
709              sc.hide = _e_icon_smart_hide;
710              sc.color_set = _e_icon_smart_color_set;
711              sc.clip_set = _e_icon_smart_clip_set;
712              sc.clip_unset = _e_icon_smart_clip_unset;
713           }
714         _e_smart = evas_smart_class_new(&sc);
715      }
716 }
717
718 static void
719 _e_icon_preloaded(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
720 {
721    E_Smart_Data *sd;
722
723    if (!(sd = evas_object_smart_data_get(data))) return;
724
725    evas_object_smart_callback_call(data, "preloaded", NULL);
726    evas_object_show(sd->obj);
727    sd->loading = 0;
728
729 #ifdef USE_ICON_CACHE
730    _e_icon_cache_icon_loaded(sd->ci);
731 #endif
732 }
733
734 static void
735 _e_icon_smart_add(Evas_Object *obj)
736 {
737    E_Smart_Data *sd;
738
739    if (!(sd = calloc(1, sizeof(E_Smart_Data)))) return;
740    sd->eventarea = evas_object_rectangle_add(evas_object_evas_get(obj));
741    evas_object_color_set(sd->eventarea, 0, 0, 0, 0);
742    evas_object_smart_member_add(sd->eventarea, obj);
743
744    sd->obj = evas_object_image_add(evas_object_evas_get(obj));
745    evas_object_event_callback_add(sd->obj, EVAS_CALLBACK_IMAGE_PRELOADED,
746                                   _e_icon_preloaded, obj);
747    sd->x = 0;
748    sd->y = 0;
749    sd->w = 0;
750    sd->h = 0;
751    sd->fill_inside = 1;
752    sd->scale_up = 1;
753    sd->size = 64;
754    evas_object_smart_member_add(sd->obj, obj);
755    evas_object_smart_data_set(obj, sd);
756 }
757
758 static void
759 _e_icon_smart_del(Evas_Object *obj)
760 {
761    E_Smart_Data *sd;
762
763    if (!(sd = evas_object_smart_data_get(obj))) return;
764    evas_object_del(sd->obj);
765    evas_object_del(sd->eventarea);
766    if (sd->fdo) eina_stringshare_del(sd->fdo);
767 #ifdef USE_ICON_CACHE
768    if (sd->file) eina_stringshare_del(sd->file);
769 #endif
770    if (sd->timer) ecore_timer_del(sd->timer);
771    free(sd);
772 }
773
774 static void
775 _e_icon_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
776 {
777    E_Smart_Data *sd;
778
779    if (!(sd = evas_object_smart_data_get(obj))) return;
780    if ((sd->x == x) && (sd->y == y)) return;
781    sd->x = x;
782    sd->y = y;
783    _e_icon_smart_reconfigure(sd);
784 }
785
786 static void
787 _e_icon_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
788 {
789    E_Smart_Data *sd;
790
791    if (!(sd = evas_object_smart_data_get(obj))) return;
792    if ((sd->w == w) && (sd->h == h)) return;
793    sd->w = w;
794    sd->h = h;
795    if (sd->fdo)
796      {
797         const char *path;
798
799         sd->size = MAX(w, h);
800         path = efreet_icon_path_find(e_config->icon_theme, sd->fdo, sd->size);
801         if (!path) return;
802
803         /* smart code here */
804         evas_object_image_load_size_set(sd->obj, sd->size, sd->size);
805         evas_object_image_file_set(sd->obj, path, NULL);
806         if (sd->preload)
807           {
808              sd->loading = 1;
809              evas_object_image_preload(sd->obj, 0);
810           }
811      }
812
813    _e_icon_smart_reconfigure(sd);
814 }
815
816 static void
817 _e_icon_smart_show(Evas_Object *obj)
818 {
819    E_Smart_Data *sd;
820
821    if (!(sd = evas_object_smart_data_get(obj))) return;
822    if (!((sd->preload) && (sd->loading)))
823      {
824         evas_object_show(sd->obj);
825 #ifdef USE_ICON_CACHE
826         if (!sd->preload)
827           _e_icon_cache_icon_loaded(sd->ci);
828 #endif
829      }
830
831    evas_object_show(sd->eventarea);
832 }
833
834 static void
835 _e_icon_smart_hide(Evas_Object *obj)
836 {
837    E_Smart_Data *sd;
838
839    if (!(sd = evas_object_smart_data_get(obj))) return;
840    evas_object_hide(sd->obj);
841    evas_object_hide(sd->eventarea);
842 }
843
844 static void
845 _e_icon_smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
846 {
847    E_Smart_Data *sd;
848
849    if (!(sd = evas_object_smart_data_get(obj))) return;
850    evas_object_color_set(sd->obj, r, g, b, a);
851 }
852
853 static void
854 _e_icon_smart_clip_set(Evas_Object *obj, Evas_Object * clip)
855 {
856    E_Smart_Data *sd;
857
858    if (!(sd = evas_object_smart_data_get(obj))) return;
859    evas_object_clip_set(sd->obj, clip);
860    evas_object_clip_set(sd->eventarea, clip);
861 }
862
863 static void
864 _e_icon_smart_clip_unset(Evas_Object *obj)
865 {
866    E_Smart_Data *sd;
867
868    if (!(sd = evas_object_smart_data_get(obj))) return;
869    evas_object_clip_unset(sd->obj);
870    evas_object_clip_unset(sd->eventarea);
871 }
872
873 #ifdef USE_ICON_CACHE
874
875 static void
876 _e_icon_cache_item_free(void *data)
877 {
878    Cache_Item *ci = data;
879    eina_stringshare_del(ci->id);
880    E_FREE(ci);
881 }
882
883 static Eina_Bool
884 _e_icon_cache_save(void *data)
885 {
886    if (_cache->load_queue)
887      {
888         Cache_Item *ci;
889         Eina_List *l;
890
891         /* EINA_LIST_FOREACH(_cache->load_queue, l, ci)
892          *   printf("  : %s\n", ci->id); */
893
894         return ECORE_CALLBACK_RENEW;
895      }
896
897    eet_sync(_cache->ef);
898    eet_close(_cache->ef);
899
900    _cache->ef = NULL;
901    _cache->timer = NULL;
902
903    return ECORE_CALLBACK_CANCEL;
904 }
905
906 static Eina_Bool
907 _e_icon_cache_find(Evas_Object *obj, const char *file)
908 {
909    E_Smart_Data *sd;
910    Cache_Item *ci;
911    char buf[PATH_MAX];
912    const char *id;
913    Eina_List *l;
914
915    if (!_cache) return EINA_FALSE;
916
917    if (!(sd = evas_object_smart_data_get(obj)))
918      return EINA_FALSE;
919
920    snprintf(buf, PATH_MAX, "%d:%s", sd->size, file);
921
922    if ((ci = eina_hash_find(_cache->hash, buf)))
923      {
924         unsigned int w, h, alpha;
925         void *data;
926         int found = 0;
927
928         if (!_cache->ef)
929           _cache->ef = eet_open(_cache->file, EET_FILE_MODE_READ_WRITE);
930
931         if (_cache->ef && (data = eet_data_image_read(_cache->ef, buf,
932                                                       &w, &h, &alpha,
933                                                       NULL, NULL, NULL)))
934           {
935              evas_object_image_size_set(sd->obj, w, h);
936              evas_object_image_alpha_set(sd->obj, alpha);
937              evas_object_image_data_copy_set(sd->obj, data);
938              evas_object_smart_callback_call(obj, "preloaded", NULL);
939              evas_object_show(sd->obj);
940              free(data);
941              found = 1;
942           }
943         
944         if ((_cache->ef) && !(_cache->timer))
945           _cache->timer = ecore_timer_add(3.0, _e_icon_cache_save, NULL);
946
947         if (found)
948           return EINA_TRUE;
949
950         eina_hash_del_by_key(_cache->hash, ci->id);
951         ci = NULL;
952      }
953
954    id = eina_stringshare_add(buf);
955
956    /* not found in cache, check load queue */
957    EINA_LIST_FOREACH(_cache->load_queue, l, ci)
958      {
959         if (ci->id != id) continue;
960         ci->objs = eina_list_append(ci->objs, obj);
961         sd->ci = ci;
962         evas_object_event_callback_add(sd->obj, EVAS_CALLBACK_DEL,
963                                        _e_icon_obj_del, obj);
964         eina_stringshare_del(id);
965         return EINA_TRUE;
966      }
967
968    ci = E_NEW(Cache_Item, 1);
969    ci->id = id;
970    ci->icon = sd->obj;
971    ci->obj = obj;
972    sd->ci = ci;
973    sd->file = eina_stringshare_add(file);
974
975    evas_object_event_callback_add(sd->obj, EVAS_CALLBACK_DEL, _e_icon_obj_del, obj);
976
977    _cache->load_queue = eina_list_append(_cache->load_queue, ci);
978
979    return EINA_FALSE;
980 }
981
982 static void
983 _e_icon_cache_icon_try_next(Cache_Item *ci)
984 {
985    Evas_Object *obj;
986    E_Smart_Data *sd;
987
988    if (!ci->objs)
989      {
990         /* no more e_icon wait for this object to bet loaded */
991         _cache->load_queue = eina_list_remove(_cache->load_queue, ci);
992         _e_icon_cache_item_free(ci);
993         return;
994      }
995
996    obj = eina_list_data_get(ci->objs);
997    ci->objs = eina_list_remove_list(ci->objs, ci->objs);
998
999    if (!obj)
1000      goto __try_next;
1001
1002    if (!(sd = evas_object_smart_data_get(obj)))
1003      goto __try_next;
1004
1005    evas_object_image_file_set(sd->obj, sd->file, NULL);
1006    if (evas_object_image_load_error_get(sd->obj) != EVAS_LOAD_ERROR_NONE)
1007      goto __try_next;
1008
1009    sd->ci->icon = sd->obj;
1010    sd->ci->obj = obj;
1011    evas_object_image_preload(sd->obj, EINA_FALSE);
1012    return;
1013
1014  __try_next:
1015    evas_object_event_callback_del_full(sd->obj, EVAS_CALLBACK_DEL,
1016                                        _e_icon_obj_del, obj);
1017    _e_icon_cache_icon_try_next(ci);
1018 }
1019
1020 static void
1021 _e_icon_obj_del(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1022 {
1023    E_Smart_Data *sd;
1024
1025    if (!(sd = evas_object_smart_data_get(data))) return;
1026    if (!sd->ci) return;
1027
1028    /* check if the deleted object is the one that is used for
1029       preloading.  when other objs wait for this image data start
1030       preloading again with the next. */
1031
1032    if (sd->ci->icon == obj)
1033      {
1034         _e_icon_cache_icon_try_next(sd->ci);
1035         sd->ci = NULL;
1036      }
1037    else
1038      {
1039         sd->ci->objs = eina_list_remove(sd->ci->objs, data);
1040         sd->ci = NULL;
1041      }
1042 }
1043
1044 static void
1045 _e_icon_cache_icon_loaded(Cache_Item *ci)
1046 {
1047    int w, h, alpha;
1048    E_Smart_Data *sd;
1049    Evas_Object *obj;
1050    void *data;
1051
1052    if (!_cache) return;
1053
1054    if (!ci || !ci->id) return;
1055    _cache->load_queue = eina_list_remove(_cache->load_queue, ci);
1056
1057    data = evas_object_image_data_get(ci->icon, EINA_FALSE);
1058    evas_object_image_size_get(ci->icon, &w, &h);
1059    alpha = evas_object_image_alpha_get(ci->icon);
1060
1061    evas_object_event_callback_del_full(ci->icon, EVAS_CALLBACK_DEL,
1062                                        _e_icon_obj_del, ci->obj);
1063    evas_object_smart_callback_call(ci->obj, "preloaded", NULL);
1064
1065    DBG("icon loaded %p, %s\n", data, ci->id);
1066
1067    sd = evas_object_smart_data_get(ci->obj);
1068    sd->ci = NULL;
1069
1070    /* pass loaded data to other e_icon wating for this */
1071    EINA_LIST_FREE(ci->objs, obj)
1072      {
1073         sd = evas_object_smart_data_get(obj);
1074         sd->ci = NULL;
1075         evas_object_event_callback_del_full(sd->obj, EVAS_CALLBACK_DEL,
1076                                             _e_icon_obj_del, obj);
1077         if (!data) continue;
1078
1079         evas_object_image_size_set(sd->obj, w, h);
1080         evas_object_image_alpha_set(sd->obj, alpha);
1081         evas_object_image_data_copy_set(sd->obj, data);
1082         evas_object_show(sd->obj);
1083         evas_object_smart_callback_call(obj, "preloaded", NULL);
1084      }
1085
1086    if (data)
1087      {
1088         if (!_cache->ef)
1089           _cache->ef = eet_open(_cache->file, EET_FILE_MODE_READ_WRITE);
1090         if (_cache->ef && eet_data_image_write(_cache->ef, ci->id, data,
1091                                                w, h, alpha, 1, 100, 0))
1092           {
1093              eina_hash_add(_cache->hash, ci->id, ci);
1094              eet_data_write(_cache->ef, cache_edd, "idx", _cache, 1);
1095
1096              if (!_cache->timer)
1097                _cache->timer = ecore_timer_add(3.0, _e_icon_cache_save, NULL);
1098
1099              eina_stringshare_replace(&ci->id, NULL);
1100              return;
1101           }
1102      }
1103
1104    DBG("couldnt write cache %p !!!\n", _cache->ef);
1105    _e_icon_cache_item_free(ci);
1106 }
1107 #endif