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