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