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