From: Hyoyoung Chang <hyoyoung@gmail.com>
[framework/uifw/elementary.git] / src / lib / elm_store.c
1 #include <Elementary.h>
2 #include <Elementary_Cursor.h>
3 #include "elm_priv.h"
4
5 typedef struct _Elm_Store_Filesystem           Elm_Store_Filesystem;
6 typedef struct _Elm_Store_Item_Filesystem      Elm_Store_Item_Filesystem;
7
8 #define ELM_STORE_MAGIC            0x3f89ea56
9 #define ELM_STORE_FILESYSTEM_MAGIC 0x3f89ea57
10 #define ELM_STORE_ITEM_MAGIC       0x5afe8c1d
11
12 struct _Elm_Store
13 {
14    EINA_MAGIC;
15    void           (*free)(Elm_Store *store);
16    struct {
17       void        (*free)(Elm_Store_Item *item);
18    } item;
19    Evas_Object   *genlist;
20    Ecore_Thread  *list_th;
21    Eina_Inlist   *items;
22    Eina_List     *realized;
23    int            realized_count;
24    int            cache_max;
25    struct {
26       struct {
27          Elm_Store_Item_List_Cb     func;
28          void                      *data;
29       } list;
30       struct {
31          Elm_Store_Item_Fetch_Cb    func;
32          void                      *data;
33       } fetch;
34       struct {
35          Elm_Store_Item_Unfetch_Cb  func;
36          void                      *data;
37       } unfetch;
38    } cb;
39    Eina_Bool sorted : 1;
40    Eina_Bool fetch_thread : 1;
41 };
42
43 struct _Elm_Store_Item
44 {
45    EINA_INLIST;
46    EINA_MAGIC;
47    Elm_Store                    *store;
48    Elm_Object_Item              *item;
49    Ecore_Thread                 *fetch_th;
50    Ecore_Job                    *eval_job;
51    const Elm_Store_Item_Mapping *mapping;
52    void                         *data;
53    Eina_Lock                     lock;
54    Eina_Bool                     live : 1;
55    Eina_Bool                     was_live : 1;
56    Eina_Bool                     realized : 1;
57    Eina_Bool                     fetched : 1;
58 };
59
60 struct _Elm_Store_Filesystem
61 {
62    Elm_Store base;
63    EINA_MAGIC;
64    const char *dir;
65 };
66
67 struct _Elm_Store_Item_Filesystem
68 {
69    Elm_Store_Item base;
70    const char *path;
71 };
72
73 static Elm_Genlist_Item_Class _store_item_class;
74
75 static void
76 _store_cache_trim(Elm_Store *st)
77 {
78    while ((st->realized ) &&
79           (((int)eina_list_count(st->realized) - st->realized_count)
80            > st->cache_max))
81      {
82         Elm_Store_Item *sti = st->realized->data;
83         if (sti->realized)
84           {
85              st->realized = eina_list_remove_list(st->realized, st->realized);
86              sti->realized = EINA_FALSE;
87           }
88         eina_lock_take(&sti->lock);
89         if (!sti->fetched)
90           {
91              eina_lock_release(&sti->lock);
92              if (sti->fetch_th)
93                {
94                   ecore_thread_cancel(sti->fetch_th);
95                   sti->fetch_th = NULL;
96                }
97              eina_lock_take(&sti->lock);
98           }
99         sti->fetched = EINA_FALSE;
100 //// let fetch/unfetch do the locking   
101 //        eina_lock_release(&sti->lock);
102         if (st->cb.unfetch.func)
103           st->cb.unfetch.func(st->cb.unfetch.data, sti);
104 //        eina_lock_take(&sti->lock);
105         sti->data = NULL;
106         eina_lock_release(&sti->lock);
107      }
108 }
109
110 static void
111 _store_genlist_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
112 {
113    Elm_Store *st = data;
114    st->genlist = NULL;
115    if (st->list_th)
116      {
117         ecore_thread_cancel(st->list_th);
118         st->list_th = NULL;
119      }
120    eina_list_free(st->realized);
121    while (st->items)
122      {
123         Elm_Store_Item *sti = (Elm_Store_Item *)st->items;
124         if (sti->eval_job) ecore_job_del(sti->eval_job);
125         if (sti->fetch_th)
126           {
127              ecore_thread_cancel(sti->fetch_th);
128              sti->fetch_th = NULL;
129           }
130         if (sti->store->item.free) sti->store->item.free(sti);
131         eina_lock_take(&sti->lock);
132         if (sti->data)
133           {
134              if (st->cb.unfetch.func)
135                st->cb.unfetch.func(st->cb.unfetch.data, sti);
136              sti->data = NULL;
137           }
138         eina_lock_release(&sti->lock);
139         eina_lock_free(&sti->lock);
140         st->items = NULL;
141         free(sti);
142      }
143    // FIXME: kill threads and more
144 }
145
146 ////// **** WARNING ***********************************************************
147 ////   * This function runs inside a thread outside efl mainloop. Be careful! *
148 //     ************************************************************************
149 /* TODO: refactor lock part into core? this does not depend on filesystm part */
150 static void
151 _store_filesystem_fetch_do(void *data, Ecore_Thread *th __UNUSED__)
152 {
153    Elm_Store_Item *sti = data;
154    eina_lock_take(&sti->lock);
155    if (sti->data)
156      {
157         eina_lock_release(&sti->lock);
158         return;
159      }
160    if (!sti->fetched)
161      {
162 //// let fetch/unfetch do the locking   
163 //        eina_lock_release(&sti->lock);
164         if (sti->store->cb.fetch.func)
165           sti->store->cb.fetch.func(sti->store->cb.fetch.data, sti);
166 //        eina_lock_take(&sti->lock);
167         sti->fetched = EINA_TRUE;
168      }
169    eina_lock_release(&sti->lock);
170 }
171 //     ************************************************************************
172 ////   * End of separate thread function.                                     *
173 ////// ************************************************************************
174 /* TODO: refactor lock part into core? this does not depend on filesystm part */
175 static void
176 _store_filesystem_fetch_end(void *data, Ecore_Thread *th)
177 {
178    Elm_Store_Item *sti = data;
179    eina_lock_take(&sti->lock);
180    if (sti->data) elm_genlist_item_update(sti->item);
181    eina_lock_release(&sti->lock);
182    if (th == sti->fetch_th) sti->fetch_th = NULL;
183 }
184
185 /* TODO: refactor lock part into core? this does not depend on filesystm part */
186 static void
187 _store_filesystem_fetch_cancel(void *data, Ecore_Thread *th)
188 {
189    Elm_Store_Item *sti = data;
190    eina_lock_take(&sti->lock);
191    if (th == sti->fetch_th) sti->fetch_th = NULL;
192    if (sti->data) elm_genlist_item_update(sti->item);
193    eina_lock_release(&sti->lock);
194 }
195
196 static void
197 _store_item_eval(void *data)
198 {
199    Elm_Store_Item *sti = data;
200    sti->eval_job = NULL;
201    if (sti->live == sti->was_live) return;
202    sti->was_live = sti->live;
203    if (sti->live)
204      {
205         _store_cache_trim(sti->store);
206         if (sti->realized)
207           sti->store->realized = eina_list_remove(sti->store->realized, sti);
208         sti->store->realized = eina_list_append(sti->store->realized, sti);
209         sti->realized = EINA_TRUE;
210         if ((sti->store->fetch_thread) && (!sti->fetch_th))
211           sti->fetch_th = ecore_thread_run(_store_filesystem_fetch_do,
212                                            _store_filesystem_fetch_end,
213                                            _store_filesystem_fetch_cancel,
214                                            sti);
215         else if ((!sti->store->fetch_thread))
216           {
217              _store_filesystem_fetch_do(sti, NULL);
218              _store_filesystem_fetch_end(sti, NULL);
219           }
220      }
221    else
222      {
223         if (sti->fetch_th)
224           {
225              ecore_thread_cancel(sti->fetch_th);
226              sti->fetch_th = NULL;
227           }
228         _store_cache_trim(sti->store);
229      }
230 }
231
232 static void
233 _store_genlist_item_realized(void *data, Evas_Object *obj __UNUSED__, void *event_info)
234 {
235    Elm_Store *st = data;
236    Elm_Object_Item *gli = event_info;
237    Elm_Store_Item *sti = elm_object_item_data_get(gli);
238    if (!sti) return;
239    st->realized_count++;
240    sti->live = EINA_TRUE;
241    if (sti->eval_job) ecore_job_del(sti->eval_job);
242    sti->eval_job = ecore_job_add(_store_item_eval, sti);
243 }
244
245 static void
246 _store_genlist_item_unrealized(void *data, Evas_Object *obj __UNUSED__, void *event_info)
247 {
248    Elm_Store *st = data;
249    Elm_Object_Item *gli = event_info;
250    Elm_Store_Item *sti = elm_object_item_data_get(gli);
251    if (!sti) return;
252    st->realized_count--;
253    sti->live = EINA_FALSE;
254    if (sti->eval_job) ecore_job_del(sti->eval_job);
255    sti->eval_job = ecore_job_add(_store_item_eval, sti);
256 }
257
258 static const Elm_Store_Item_Mapping *
259 _store_item_mapping_find(Elm_Store_Item *sti, const char *part)
260 {
261    const Elm_Store_Item_Mapping *m;
262
263    for (m = sti->mapping; m; m ++)
264      {
265         if (m->type == ELM_STORE_ITEM_MAPPING_NONE) break;
266         if (!strcmp(part, m->part)) return m;
267      }
268    return NULL;
269 }
270
271 static char *
272 _store_item_text_get(void *data, Evas_Object *obj __UNUSED__, const char *part)
273 {
274    Elm_Store_Item *sti = data;
275    const char *s = "";
276    eina_lock_take(&sti->lock);
277    if (sti->data)
278      {
279         const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part);
280         if (m)
281           {
282              switch (m->type)
283                {
284                 case ELM_STORE_ITEM_MAPPING_LABEL:
285                    s = *(char **)(((unsigned char *)sti->data) + m->offset);
286                    break;
287                 case ELM_STORE_ITEM_MAPPING_CUSTOM:
288                    if (m->details.custom.func)
289                      s = m->details.custom.func(sti->data, sti, part);
290                    break;
291                 default:
292                    break;
293                }
294           }
295      }
296    eina_lock_release(&sti->lock);
297    return s ? strdup(s) : NULL;
298 }
299
300 static Evas_Object *
301 _store_item_content_get(void *data, Evas_Object *obj, const char *part)
302 {
303    Elm_Store_Item *sti = data;
304    eina_lock_take(&sti->lock);
305    if (sti->data)
306      {
307         const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part);
308         if (m)
309           {
310              Evas_Object *ic = NULL;
311              const char *s = NULL;
312
313              switch (m->type)
314                {
315                 case ELM_STORE_ITEM_MAPPING_ICON:
316                    ic = elm_icon_add(obj);
317                    s = *(char **)(((unsigned char *)sti->data) + m->offset);
318                    elm_icon_order_lookup_set(ic, m->details.icon.lookup_order);
319                    evas_object_size_hint_aspect_set(ic,
320                                                     EVAS_ASPECT_CONTROL_VERTICAL,
321                                                     m->details.icon.w,
322                                                     m->details.icon.h);
323                    elm_icon_smooth_set(ic, m->details.icon.smooth);
324                    elm_icon_no_scale_set(ic, m->details.icon.no_scale);
325                    elm_icon_resizable_set(ic,
326                                       m->details.icon.scale_up,
327                                       m->details.icon.scale_down);
328                    if (s)
329                      {
330                         if (m->details.icon.standard_name)
331                           elm_icon_standard_set(ic, s);
332                         else
333                           elm_icon_file_set(ic, s, NULL);
334                      }
335                    break;
336                 case ELM_STORE_ITEM_MAPPING_PHOTO:
337                    ic = elm_icon_add(obj);
338                    s = *(char **)(((unsigned char *)sti->data) + m->offset);
339                    elm_photo_size_set(ic, m->details.photo.size);
340                    if (s)
341                      elm_photo_file_set(ic, s);
342                    break;
343                 case ELM_STORE_ITEM_MAPPING_CUSTOM:
344                    if (m->details.custom.func)
345                      ic = m->details.custom.func(sti->data, sti, part);
346                    break;
347                 default:
348                    break;
349                }
350              eina_lock_release(&sti->lock);
351              return ic;
352           }
353      }
354    eina_lock_release(&sti->lock);
355    return NULL;
356 }
357
358 static void
359 _store_item_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__)
360 {
361 }
362
363 ////// **** WARNING ***********************************************************
364 ////   * This function runs inside a thread outside efl mainloop. Be careful! *
365 //     ************************************************************************
366 static int
367 _store_filesystem_sort_cb(void *d1, void *d2)
368 {
369    Elm_Store_Item_Info *info1 = d1, *info2 = d2;
370    if ((!info1->sort_id) || (!info2->sort_id)) return 0;
371    return strcoll(info1->sort_id, info2->sort_id);
372 }
373
374 static void
375 _store_filesystem_list_do(void *data, Ecore_Thread *th __UNUSED__)
376 {
377    Elm_Store_Filesystem *st = data;
378    Eina_Iterator *it;
379    const Eina_File_Direct_Info *finf;
380    Eina_List *sorted = NULL;
381    Elm_Store_Item_Info_Filesystem *info;
382
383    // FIXME: need a way to abstract the open, list, feed items from list
384    // and maybe get initial sortable key vals etc.
385    it = eina_file_stat_ls(st->dir);
386    if (!it) return;
387    EINA_ITERATOR_FOREACH(it, finf)
388      {
389         Eina_Bool ok;
390         size_t pathsz = finf->path_length + 1;
391
392         if (finf->path[finf->name_start] == '.') continue ;
393
394         info = calloc(1, sizeof(Elm_Store_Item_Info_Filesystem) + pathsz);
395         if (!info) continue;
396         info->path = ((char *)info) + sizeof(Elm_Store_Item_Info_Filesystem);
397         memcpy(info->path, finf->path, pathsz);
398         ok = EINA_TRUE;
399         if (st->base.cb.list.func)
400           ok = st->base.cb.list.func(st->base.cb.list.data, &info->base);
401         if (ok)
402           {
403              if (!st->base.sorted) ecore_thread_feedback(th, info);
404              else sorted = eina_list_append(sorted, info);
405           }
406         else
407           {
408              if (info->base.sort_id) free(info->base.sort_id);
409              free(info);
410           }
411         if (ecore_thread_check(th)) break;
412      }
413    eina_iterator_free(it);
414    if (sorted)
415      {
416         sorted = eina_list_sort(sorted, 0,
417                                 EINA_COMPARE_CB(_store_filesystem_sort_cb));
418         EINA_LIST_FREE(sorted, info)
419           {
420              if (!ecore_thread_check(th)) ecore_thread_feedback(th, info);
421           }
422      }
423 }
424 //     ************************************************************************
425 ////   * End of separate thread function.                                     *
426 ////// ************************************************************************
427
428 static void
429 _store_filesystem_list_end(void *data, Ecore_Thread *th)
430 {
431    Elm_Store *st = data;
432    if (th == st->list_th) st->list_th = NULL;
433 }
434
435 static void
436 _store_filesystem_list_cancel(void *data, Ecore_Thread *th)
437 {
438    Elm_Store *st = data;
439    if (th == st->list_th) st->list_th = NULL;
440 }
441
442 static void
443 _store_filesystem_list_update(void *data, Ecore_Thread *th __UNUSED__, void *msg)
444 {
445    Elm_Store *st = data;
446    Elm_Store_Item_Filesystem *sti;
447    Elm_Genlist_Item_Class *itc;
448    Elm_Store_Item_Info_Filesystem *info = msg;
449
450    sti = calloc(1, sizeof(Elm_Store_Item_Filesystem));
451    if (!sti) goto done;
452    eina_lock_new(&sti->base.lock);
453    EINA_MAGIC_SET(&(sti->base), ELM_STORE_ITEM_MAGIC);
454    sti->base.store = st;
455    sti->base.data = info->base.data;
456    sti->base.mapping = info->base.mapping;
457    sti->path = eina_stringshare_add(info->path);
458
459    itc = info->base.item_class;
460    if (!itc) itc = &_store_item_class;
461    else
462      {
463         itc->func.text_get = _store_item_text_get;
464         itc->func.content_get  = _store_item_content_get;
465         itc->func.state_get = NULL; // FIXME: support state gets later
466         itc->func.del       = _store_item_del;
467      }
468
469    // FIXME: handle being a parent (tree)
470    sti->base.item = elm_genlist_item_append(st->genlist, itc,
471                                             sti/* item data */,
472                                             NULL/* parent */,
473                                             ELM_GENLIST_ITEM_NONE,
474                                             NULL/* func */,
475                                             NULL/* func data */);
476    st->items = eina_inlist_append(st->items, (Eina_Inlist *)sti);
477 done:
478    if (info->base.sort_id) free(info->base.sort_id);
479    free(info);
480 }
481
482 // public api calls
483 static Elm_Store *
484 _elm_store_new(size_t size)
485 {
486    Elm_Store *st = calloc(1, size);
487    EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
488
489    // TODO: BEGIN - move to elm_store_init()
490    eina_magic_string_set(ELM_STORE_MAGIC, "Elm_Store");
491    eina_magic_string_set(ELM_STORE_FILESYSTEM_MAGIC, "Elm_Store_Filesystem");
492    eina_magic_string_set(ELM_STORE_ITEM_MAGIC, "Elm_Store_Item");
493    // setup default item class (always the same) if list cb doesnt provide one
494    _store_item_class.item_style = "default";
495    _store_item_class.func.text_get = _store_item_text_get;
496    _store_item_class.func.content_get  = _store_item_content_get;
497    _store_item_class.func.state_get = NULL; // FIXME: support state gets later
498    _store_item_class.func.del       = _store_item_del;
499    // TODO: END - move to elm_store_init()
500
501    EINA_MAGIC_SET(st, ELM_STORE_MAGIC);
502    st->cache_max = 128;
503    st->fetch_thread = EINA_TRUE;
504    return st;
505 }
506 #define elm_store_new(type) (type*)_elm_store_new(sizeof(type))
507
508 static void
509 _elm_store_filesystem_free(Elm_Store *store)
510 {
511    Elm_Store_Filesystem *st = (Elm_Store_Filesystem *)store;
512    eina_stringshare_del(st->dir);
513 }
514
515 static void
516 _elm_store_filesystem_item_free(Elm_Store_Item *item)
517 {
518    Elm_Store_Item_Filesystem *sti = (Elm_Store_Item_Filesystem *)item;
519    eina_stringshare_del(sti->path);
520 }
521
522 EAPI Elm_Store *
523 elm_store_filesystem_new(void)
524 {
525    Elm_Store_Filesystem *st = elm_store_new(Elm_Store_Filesystem);
526    EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
527
528    EINA_MAGIC_SET(st, ELM_STORE_FILESYSTEM_MAGIC);
529    st->base.free = _elm_store_filesystem_free;
530    st->base.item.free = _elm_store_filesystem_item_free;
531
532    return &st->base;
533 }
534
535 EAPI void
536 elm_store_free(Elm_Store *st)
537 {
538    void (*item_free)(Elm_Store_Item *);
539    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
540    if (st->list_th)
541      {
542         ecore_thread_cancel(st->list_th);
543         st->list_th = NULL;
544      }
545    eina_list_free(st->realized);
546    item_free = st->item.free;
547    while (st->items)
548      {
549         Elm_Store_Item *sti = (Elm_Store_Item *)st->items;
550         if (sti->eval_job) ecore_job_del(sti->eval_job);
551         if (sti->fetch_th)
552           {
553              ecore_thread_cancel(sti->fetch_th);
554              sti->fetch_th = NULL;
555           }
556         if (item_free) item_free(sti);
557         eina_lock_take(&sti->lock);
558         if (sti->data)
559           {
560              if (st->cb.unfetch.func)
561                st->cb.unfetch.func(st->cb.unfetch.data, sti);
562              sti->data = NULL;
563           }
564         eina_lock_release(&sti->lock);
565         eina_lock_free(&sti->lock);
566         free(sti);
567      }
568    if (st->genlist)
569      {
570         evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st);
571         evas_object_smart_callback_del(st->genlist, "realized", _store_genlist_item_realized);
572         evas_object_smart_callback_del(st->genlist, "unrealized", _store_genlist_item_unrealized);
573         elm_genlist_clear(st->genlist);
574         st->genlist = NULL;
575      }
576    if (st->free) st->free(st);
577    free(st);
578 }
579
580 EAPI void
581 elm_store_target_genlist_set(Elm_Store *st, Evas_Object *obj)
582 {
583    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
584    if (st->genlist == obj) return;
585    if (st->genlist)
586      {
587         evas_object_event_callback_del_full(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st);
588         evas_object_smart_callback_del(st->genlist, "realized", _store_genlist_item_realized);
589         evas_object_smart_callback_del(st->genlist, "unrealized", _store_genlist_item_unrealized);
590         elm_genlist_clear(st->genlist);
591      }
592    st->genlist = obj;
593    if (!st->genlist) return;
594    evas_object_smart_callback_add(st->genlist, "realized", _store_genlist_item_realized, st);
595    evas_object_smart_callback_add(st->genlist, "unrealized", _store_genlist_item_unrealized, st);
596    evas_object_event_callback_add(st->genlist, EVAS_CALLBACK_DEL, _store_genlist_del, st);
597    elm_genlist_clear(st->genlist);
598 }
599
600 EAPI void
601 elm_store_filesystem_directory_set(Elm_Store *store, const char *dir)
602 {
603    Elm_Store_Filesystem *st = (Elm_Store_Filesystem *)store;
604    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return;
605    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return;
606    if (store->list_th)
607      {
608         ecore_thread_cancel(store->list_th);
609         store->list_th = NULL;
610      }
611    if (!eina_stringshare_replace(&st->dir, dir)) return;
612    store->list_th = ecore_thread_feedback_run(_store_filesystem_list_do,
613                                               _store_filesystem_list_update,
614                                               _store_filesystem_list_end,
615                                               _store_filesystem_list_cancel,
616                                               st, EINA_TRUE);
617 }
618
619 EAPI const char *
620 elm_store_filesystem_directory_get(const Elm_Store *store)
621 {
622    const Elm_Store_Filesystem *st = (const Elm_Store_Filesystem *)store;
623    if (!EINA_MAGIC_CHECK(store, ELM_STORE_MAGIC)) return NULL;
624    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL;
625    return st->dir;
626 }
627
628 EAPI void
629 elm_store_cache_set(Elm_Store *st, int max)
630 {
631    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
632    if (max < 0) max = 0;
633    st->cache_max = max;
634    _store_cache_trim(st);
635 }
636
637 EAPI int
638 elm_store_cache_get(const Elm_Store *st)
639 {
640    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return 0;
641    return st->cache_max;
642 }
643
644 EAPI void
645 elm_store_list_func_set(Elm_Store *st, Elm_Store_Item_List_Cb func, const void *data)
646 {
647    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
648    st->cb.list.func = func;
649    st->cb.list.data = (void *)data;
650 }
651
652 EAPI void
653 elm_store_fetch_func_set(Elm_Store *st, Elm_Store_Item_Fetch_Cb func, const void *data)
654 {
655    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
656    st->cb.fetch.func = func;
657    st->cb.fetch.data = (void *)data;
658 }
659
660 EAPI void
661 elm_store_fetch_thread_set(Elm_Store *st, Eina_Bool use_thread)
662 {
663    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
664    st->fetch_thread = !!use_thread;
665 }
666
667 EAPI Eina_Bool
668 elm_store_fetch_thread_get(const Elm_Store *st)
669 {
670    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE;
671    return st->fetch_thread;
672 }
673
674 EAPI void
675 elm_store_unfetch_func_set(Elm_Store *st, Elm_Store_Item_Unfetch_Cb func, const void *data)
676 {
677    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
678    st->cb.unfetch.func = func;
679    st->cb.unfetch.data = (void *)data;
680 }
681
682 EAPI void
683 elm_store_sorted_set(Elm_Store *st, Eina_Bool sorted)
684 {
685    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
686    st->sorted = sorted;
687 }
688
689 EAPI Eina_Bool
690 elm_store_sorted_get(const Elm_Store *st)
691 {
692    if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE;
693    return st->sorted;
694 }
695
696 EAPI void
697 elm_store_item_data_set(Elm_Store_Item *sti, void *data)
698 {
699    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
700 //// let fetch/unfetch do the locking   
701 //   eina_lock_take(&sti->lock);
702    sti->data = data;
703 //   eina_lock_release(&sti->lock);
704 }
705
706 EAPI void *
707 elm_store_item_data_get(Elm_Store_Item *sti)
708 {
709    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
710    void *d;
711 //// let fetch/unfetch do the locking   
712 //   eina_lock_take(&sti->lock);
713    d = sti->data;
714 //   eina_lock_release(&sti->lock);
715    return d;
716 }
717
718 EAPI const Elm_Store *
719 elm_store_item_store_get(const Elm_Store_Item *sti)
720 {
721    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
722    // dont need lock
723    return sti->store;
724 }
725
726 EAPI const Elm_Object_Item *
727 elm_store_item_genlist_item_get(const Elm_Store_Item *sti)
728 {
729    if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
730    // dont need lock
731    return sti->item;
732 }
733
734 EAPI const char *
735 elm_store_item_filesystem_path_get(const Elm_Store_Item *item)
736 {
737    Elm_Store_Item_Filesystem *sti = (Elm_Store_Item_Filesystem *)item;
738    Elm_Store_Filesystem *st;
739    if (!EINA_MAGIC_CHECK(item, ELM_STORE_ITEM_MAGIC)) return NULL;
740    if (!EINA_MAGIC_CHECK(item->store, ELM_STORE_MAGIC)) return NULL;
741    /* ensure we're dealing with filesystem item */
742    st = (Elm_Store_Filesystem *)item->store;
743    if (!EINA_MAGIC_CHECK(st, ELM_STORE_FILESYSTEM_MAGIC)) return NULL;
744    // dont need lock
745    return sti->path;
746 }