diff options
author | David Walter Seikel | 2012-04-22 09:20:32 +1000 |
---|---|---|
committer | David Walter Seikel | 2012-04-22 09:20:32 +1000 |
commit | 3ad3455551be0d7859ecb02290376206d5e66498 (patch) | |
tree | 497917e12b4d7f458dff9765d9b53f64c4e03fc3 /libraries/elementary/src/lib/elm_store.c | |
parent | Update EFL to latest beta. (diff) | |
download | SledjHamr-3ad3455551be0d7859ecb02290376206d5e66498.zip SledjHamr-3ad3455551be0d7859ecb02290376206d5e66498.tar.gz SledjHamr-3ad3455551be0d7859ecb02290376206d5e66498.tar.bz2 SledjHamr-3ad3455551be0d7859ecb02290376206d5e66498.tar.xz |
And actually include new files, plus elementary libraries.
Diffstat (limited to 'libraries/elementary/src/lib/elm_store.c')
-rw-r--r-- | libraries/elementary/src/lib/elm_store.c | 751 |
1 files changed, 751 insertions, 0 deletions
diff --git a/libraries/elementary/src/lib/elm_store.c b/libraries/elementary/src/lib/elm_store.c new file mode 100644 index 0000000..a296f36 --- /dev/null +++ b/libraries/elementary/src/lib/elm_store.c | |||
@@ -0,0 +1,751 @@ | |||
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 | } | ||