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