1 #include <Elementary.h>
2 #include <Elementary_Cursor.h>
5 #ifndef EFL_HAVE_THREADS
6 # error "No thread support. Required."
9 #ifdef EFL_HAVE_POSIX_THREADS
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
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)
27 #define ELM_STORE_MAGIC 0x3f89ea56
28 #define ELM_STORE_FILESYSTEM_MAGIC 0x3f89ea57
29 #define ELM_STORE_ITEM_MAGIC 0x5afe8c1d
34 void (*free)(Elm_Store *store);
36 void (*free)(Elm_Store_Item *item);
39 Ecore_Thread *list_th;
46 Elm_Store_Item_List_Cb func;
50 Elm_Store_Item_Fetch_Cb func;
54 Elm_Store_Item_Unfetch_Cb func;
59 Eina_Bool fetch_thread : 1;
62 struct _Elm_Store_Item
67 Elm_Genlist_Item *item;
68 Ecore_Thread *fetch_th;
70 const Elm_Store_Item_Mapping *mapping;
74 Eina_Bool was_live : 1;
75 Eina_Bool realized : 1;
76 Eina_Bool fetched : 1;
79 struct _Elm_Store_Filesystem
86 struct _Elm_Store_Item_Filesystem
92 static Elm_Genlist_Item_Class _store_item_class;
95 _store_cache_trim(Elm_Store *st)
97 while ((st->realized ) &&
98 (((int)eina_list_count(st->realized) - st->realized_count)
101 Elm_Store_Item *sti = st->realized->data;
104 st->realized = eina_list_remove_list(st->realized, st->realized);
105 sti->realized = EINA_FALSE;
113 ecore_thread_cancel(sti->fetch_th);
114 sti->fetch_th = NULL;
118 sti->fetched = EINA_FALSE;
120 if (st->cb.unfetch.func)
121 st->cb.unfetch.func(st->cb.unfetch.data, sti);
129 _store_genlist_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
131 Elm_Store *st = data;
135 ecore_thread_cancel(st->list_th);
138 eina_list_free(st->realized);
141 Elm_Store_Item *sti = (Elm_Store_Item *)st->items;
142 if (sti->eval_job) ecore_job_del(sti->eval_job);
145 ecore_thread_cancel(sti->fetch_th);
146 sti->fetch_th = NULL;
148 if (sti->store->item.free) sti->store->item.free(sti);
151 if (st->cb.unfetch.func)
152 st->cb.unfetch.func(st->cb.unfetch.data, sti);
158 // FIXME: kill threads and more
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 */
166 _store_filesystem_fetch_do(void *data, Ecore_Thread *th __UNUSED__)
168 Elm_Store_Item *sti = data;
178 if (sti->store->cb.fetch.func)
179 sti->store->cb.fetch.func(sti->store->cb.fetch.data, sti);
181 sti->fetched = EINA_TRUE;
185 // ************************************************************************
186 //// * End of separate thread function. *
187 ////// ************************************************************************
188 /* TODO: refactor lock part into core? this does not depend on filesystm part */
190 _store_filesystem_fetch_end(void *data, Ecore_Thread *th)
192 Elm_Store_Item *sti = data;
194 if (sti->data) elm_genlist_item_update(sti->item);
196 if (th == sti->fetch_th) sti->fetch_th = NULL;
199 /* TODO: refactor lock part into core? this does not depend on filesystm part */
201 _store_filesystem_fetch_cancel(void *data, Ecore_Thread *th)
203 Elm_Store_Item *sti = data;
205 if (th == sti->fetch_th) sti->fetch_th = NULL;
206 if (sti->data) elm_genlist_item_update(sti->item);
211 _store_item_eval(void *data)
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;
219 _store_cache_trim(sti->store);
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,
229 else if ((!sti->store->fetch_thread))
231 _store_filesystem_fetch_do(sti, NULL);
232 _store_filesystem_fetch_end(sti, NULL);
239 ecore_thread_cancel(sti->fetch_th);
240 sti->fetch_th = NULL;
242 _store_cache_trim(sti->store);
247 _store_genlist_item_realized(void *data, Evas_Object *obj __UNUSED__, void *event_info)
249 Elm_Store *st = data;
250 Elm_Genlist_Item *gli = event_info;
251 Elm_Store_Item *sti = elm_genlist_item_data_get(gli);
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);
260 _store_genlist_item_unrealized(void *data, Evas_Object *obj __UNUSED__, void *event_info)
262 Elm_Store *st = data;
263 Elm_Genlist_Item *gli = event_info;
264 Elm_Store_Item *sti = elm_genlist_item_data_get(gli);
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);
272 static const Elm_Store_Item_Mapping *
273 _store_item_mapping_find(Elm_Store_Item *sti, const char *part)
275 const Elm_Store_Item_Mapping *m;
277 for (m = sti->mapping; m; m ++)
279 if (m->type == ELM_STORE_ITEM_MAPPING_NONE) break;
280 if (!strcmp(part, m->part)) return m;
286 _store_item_label_get(void *data, Evas_Object *obj __UNUSED__, const char *part)
288 Elm_Store_Item *sti = data;
293 const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part);
298 case ELM_STORE_ITEM_MAPPING_LABEL:
299 s = *(char **)(((unsigned char *)sti->data) + m->offset);
301 case ELM_STORE_ITEM_MAPPING_CUSTOM:
302 if (m->details.custom.func)
303 s = m->details.custom.func(sti->data, sti, part);
315 _store_item_icon_get(void *data, Evas_Object *obj, const char *part)
317 Elm_Store_Item *sti = data;
321 const Elm_Store_Item_Mapping *m = _store_item_mapping_find(sti, part);
324 Evas_Object *ic = NULL;
325 const char *s = NULL;
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,
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);
344 if (m->details.icon.standard_name)
345 elm_icon_standard_set(ic, s);
347 elm_icon_file_set(ic, s, NULL);
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);
355 elm_photo_file_set(ic, s);
357 case ELM_STORE_ITEM_MAPPING_CUSTOM:
358 if (m->details.custom.func)
359 ic = m->details.custom.func(sti->data, sti, part);
373 _store_item_del(void *data __UNUSED__, Evas_Object *obj __UNUSED__)
377 ////// **** WARNING ***********************************************************
378 //// * This function runs inside a thread outside efl mainloop. Be careful! *
379 // ************************************************************************
381 _store_filesystem_sort_cb(void *d1, void *d2)
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);
389 _store_filesystem_list_do(void *data, Ecore_Thread *th __UNUSED__)
391 Elm_Store_Filesystem *st = data;
393 const Eina_File_Direct_Info *finf;
394 Eina_List *sorted = NULL;
395 Elm_Store_Item_Info_Filesystem *info;
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);
401 EINA_ITERATOR_FOREACH(it, finf)
404 size_t pathsz = finf->path_length + 1;
406 info = calloc(1, sizeof(Elm_Store_Item_Info_Filesystem) + pathsz);
408 info->path = ((char *)info) + sizeof(Elm_Store_Item_Info_Filesystem);
409 memcpy(info->path, finf->path, pathsz);
411 if (st->base.cb.list.func)
412 ok = st->base.cb.list.func(st->base.cb.list.data, &info->base);
415 if (!st->base.sorted) ecore_thread_feedback(th, info);
416 else sorted = eina_list_append(sorted, info);
420 if (info->base.sort_id) free(info->base.sort_id);
423 if (ecore_thread_check(th)) break;
425 eina_iterator_free(it);
428 sorted = eina_list_sort(sorted, 0,
429 EINA_COMPARE_CB(_store_filesystem_sort_cb));
430 EINA_LIST_FREE(sorted, info)
432 if (!ecore_thread_check(th)) ecore_thread_feedback(th, info);
436 // ************************************************************************
437 //// * End of separate thread function. *
438 ////// ************************************************************************
441 _store_filesystem_list_end(void *data, Ecore_Thread *th)
443 Elm_Store *st = data;
444 if (th == st->list_th) st->list_th = NULL;
448 _store_filesystem_list_cancel(void *data, Ecore_Thread *th)
450 Elm_Store *st = data;
451 if (th == st->list_th) st->list_th = NULL;
455 _store_filesystem_list_update(void *data, Ecore_Thread *th __UNUSED__, void *msg)
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;
462 sti = calloc(1, sizeof(Elm_Store_Item_Filesystem));
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);
471 itc = info->base.item_class;
472 if (!itc) itc = &_store_item_class;
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;
481 // FIXME: handle being a parent (tree)
482 sti->base.item = elm_genlist_item_append(st->genlist, itc,
485 ELM_GENLIST_ITEM_NONE,
487 NULL/* func data */);
488 st->items = eina_inlist_append(st->items, (Eina_Inlist *)sti);
490 if (info->base.sort_id) free(info->base.sort_id);
496 _elm_store_new(size_t size)
498 Elm_Store *st = calloc(1, size);
499 EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
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()
513 EINA_MAGIC_SET(st, ELM_STORE_MAGIC);
515 st->fetch_thread = EINA_TRUE;
518 #define elm_store_new(type) (type*)_elm_store_new(sizeof(type))
521 _elm_store_filesystem_free(Elm_Store *store)
523 Elm_Store_Filesystem *st = (Elm_Store_Filesystem *)store;
524 eina_stringshare_del(st->dir);
528 _elm_store_filesystem_item_free(Elm_Store_Item *item)
530 Elm_Store_Item_Filesystem *sti = (Elm_Store_Item_Filesystem *)item;
531 eina_stringshare_del(sti->path);
535 elm_store_filesystem_new(void)
537 Elm_Store_Filesystem *st = elm_store_new(Elm_Store_Filesystem);
538 EINA_SAFETY_ON_NULL_RETURN_VAL(st, NULL);
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;
548 elm_store_free(Elm_Store *st)
550 void (*item_free)(Elm_Store_Item *);
551 if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
554 ecore_thread_cancel(st->list_th);
557 eina_list_free(st->realized);
558 item_free = st->item.free;
561 Elm_Store_Item *sti = (Elm_Store_Item *)st->items;
562 if (sti->eval_job) ecore_job_del(sti->eval_job);
565 ecore_thread_cancel(sti->fetch_th);
566 sti->fetch_th = NULL;
568 if (item_free) item_free(sti);
571 if (st->cb.unfetch.func)
572 st->cb.unfetch.func(st->cb.unfetch.data, sti);
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);
586 if (st->free) st->free(st);
591 elm_store_target_genlist_set(Elm_Store *st, Evas_Object *obj)
593 if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
594 if (st->genlist == obj) return;
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);
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);
611 elm_store_filesystem_directory_set(Elm_Store *store, const char *dir)
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;
618 ecore_thread_cancel(store->list_th);
619 store->list_th = NULL;
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,
630 elm_store_filesystem_directory_get(const Elm_Store *store)
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;
639 elm_store_cache_set(Elm_Store *st, int max)
641 if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
642 if (max < 0) max = 0;
644 _store_cache_trim(st);
648 elm_store_cache_get(const Elm_Store *st)
650 if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return 0;
651 return st->cache_max;
655 elm_store_list_func_set(Elm_Store *st, Elm_Store_Item_List_Cb func, const void *data)
657 if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
658 st->cb.list.func = func;
659 st->cb.list.data = (void *)data;
663 elm_store_fetch_func_set(Elm_Store *st, Elm_Store_Item_Fetch_Cb func, const void *data)
665 if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
666 st->cb.fetch.func = func;
667 st->cb.fetch.data = (void *)data;
671 elm_store_fetch_thread_set(Elm_Store *st, Eina_Bool use_thread)
673 if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
674 st->fetch_thread = !!use_thread;
678 elm_store_fetch_thread_get(const Elm_Store *st)
680 if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE;
681 return st->fetch_thread;
685 elm_store_unfetch_func_set(Elm_Store *st, Elm_Store_Item_Unfetch_Cb func, const void *data)
687 if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
688 st->cb.unfetch.func = func;
689 st->cb.unfetch.data = (void *)data;
693 elm_store_sorted_set(Elm_Store *st, Eina_Bool sorted)
695 if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return;
700 elm_store_sorted_get(const Elm_Store *st)
702 if (!EINA_MAGIC_CHECK(st, ELM_STORE_MAGIC)) return EINA_FALSE;
707 elm_store_item_data_set(Elm_Store_Item *sti, void *data)
709 if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return;
716 elm_store_item_data_get(Elm_Store_Item *sti)
718 if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
726 EAPI const Elm_Store *
727 elm_store_item_store_get(const Elm_Store_Item *sti)
729 if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
734 EAPI const Elm_Genlist_Item *
735 elm_store_item_genlist_item_get(const Elm_Store_Item *sti)
737 if (!EINA_MAGIC_CHECK(sti, ELM_STORE_ITEM_MAGIC)) return NULL;
743 elm_store_item_filesystem_path_get(const Elm_Store_Item *item)
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;