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