1 /***************************************************
2    TODO option for maximum items to cache
3    TODO keep common list for recent file instances
4    FIXME
5  */
6 
7 #include "e.h"
8 #include "evry_api.h"
9 #include <Efreet_Trash.h>
10 
11 /* Increment for Major Changes */
12 #define MOD_CONFIG_FILE_EPOCH      1
13 /* Increment for Minor Changes (ie: user doesn't need a new config) */
14 #define MOD_CONFIG_FILE_GENERATION 0
15 #define MOD_CONFIG_FILE_VERSION    ((MOD_CONFIG_FILE_EPOCH * 1000000) + MOD_CONFIG_FILE_GENERATION)
16 
17 #define MAX_ITEMS                  10
18 #define MAX_SHOWN                  300
19 #define TERM_ACTION_DIR            "%s"
20 
21 #define CMD_NONE                   0
22 #define CMD_SHOW_ROOT              1
23 #define CMD_SHOW_HIDDEN            2
24 #define CMD_SHOW_PARENT            3
25 
26 #define ACT_TRASH                  1
27 #define ACT_DELETE                 2
28 #define ACT_COPY                   3
29 #define ACT_MOVE                   4
30 #define ACT_SORT_DATE              5
31 #define ACT_SORT_NAME              6
32 
33 #define ONE_DAY                    86400.0
34 #define SIX_DAYS_AGO               (ecore_time_unix_get() - ONE_DAY * 6)
35 #define MIN_USAGE                  0.0
36 
37 /* #undef DBG
38  * #define DBG(...) ERR(__VA_ARGS__) */
39 
40 typedef struct _Plugin        Plugin;
41 typedef struct _Data          Data;
42 typedef struct _Module_Config Module_Config;
43 
44 struct _Plugin
45 {
46    Evry_Plugin         base;
47 
48    Eina_List          *files;
49    const char         *directory;
50    const char         *input;
51    unsigned int        command;
52    unsigned int        min_query;
53    Eina_Bool           parent;
54    Eina_Bool           show_hidden;
55    Eina_Bool           dirs_only;
56    Eina_Bool           show_recent;
57    Eina_Bool           sort_by_date;
58 
59    Ecore_Thread       *thread;
60    Ecore_File_Monitor *dir_mon;
61    int                 waiting_to_finish;
62 };
63 
64 struct _Data
65 {
66    Plugin    *plugin;
67    char      *directory;
68    long       id;
69    int        level;
70    int        cnt;
71    Eina_List *files;
72    DIR       *dirp;
73    int        run_cnt;
74 };
75 
76 struct _Module_Config
77 {
78    int              version;
79 
80    unsigned char    show_homedir;
81    unsigned char    show_recent;
82    unsigned char    search_recent;
83    unsigned char    cache_dirs;
84    unsigned char    search_cache;
85 
86    // TODO
87    int              sort_by;
88    Eina_List       *search_dirs;
89 
90    E_Config_Dialog *cfd;
91    E_Module        *module;
92 };
93 
94 static const Evry_API *evry = NULL;
95 static Evry_Module *evry_module = NULL;
96 
97 static Module_Config *_conf;
98 static char _module_icon[] = "system-file-manager";
99 static Eina_List *_plugins = NULL;
100 static Eina_List *_actions = NULL;
101 static const char *_mime_dir;
102 static const char *_mime_mount;
103 static const char *_mime_unknown;
104 static Eina_Bool clear_cache = EINA_FALSE;
105 
106 /***************************************************************************/
107 
108 static void
_item_fill(Evry_Item_File * file)109 _item_fill(Evry_Item_File *file)
110 {
111    if (!file->mime)
112      {
113         const char *mime = efreet_mime_type_get(file->path);
114 
115         if (mime)
116           file->mime = eina_stringshare_add(mime);
117         else
118           file->mime = eina_stringshare_add("unknown");
119      }
120 
121    if ((file->mime == _mime_dir) ||
122        (file->mime == _mime_mount))
123      EVRY_ITEM(file)->browseable = EINA_TRUE;
124 
125    EVRY_ITEM(file)->context = eina_stringshare_ref(file->mime);
126 
127    if (!EVRY_ITEM(file)->detail)
128      evry->util_file_detail_set(file);
129 
130    evry->util_file_detail_set(file);
131 }
132 
133 static int
_cb_sort(const void * data1,const void * data2)134 _cb_sort(const void *data1, const void *data2)
135 {
136    const Evry_Item *it1 = data1;
137    const Evry_Item *it2 = data2;
138 
139    if (it1->browseable && !it2->browseable)
140      return -1;
141 
142    if (!it1->browseable && it2->browseable)
143      return 1;
144 
145    if (it1->fuzzy_match && it2->fuzzy_match)
146      if (it1->fuzzy_match - it2->fuzzy_match)
147        return it1->fuzzy_match - it2->fuzzy_match;
148 
149    return strcasecmp(it1->label, it2->label);
150 }
151 
152 static int
_cb_sort_date(const void * data1,const void * data2)153 _cb_sort_date(const void *data1, const void *data2)
154 {
155    const Evry_Item_File *it1 = data1;
156    const Evry_Item_File *it2 = data2;
157 
158    return it2->modified - it1->modified;
159 }
160 
161 static void
_scan_func(void * data,Ecore_Thread * thread)162 _scan_func(void *data, Ecore_Thread *thread)
163 {
164    Data *d = data;
165    Eina_Iterator *ls;
166    Eina_File_Direct_Info *info;
167    Evry_Item_File *file;
168 
169    if (!(ls = eina_file_stat_ls(d->directory)))
170      return;
171 
172    EINA_ITERATOR_FOREACH (ls, info)
173      {
174         if ((d->plugin->show_hidden) != (*(info->path + info->name_start) == '.'))
175           continue;
176 
177         file = EVRY_ITEM_NEW(Evry_Item_File, d->plugin, NULL, NULL, evry_item_file_free);
178         file->path = strdup(info->path);
179         EVRY_ITEM(file)->label = strdup(info->path + info->name_start);
180         EVRY_ITEM(file)->browseable = (info->type == EINA_FILE_DIR);
181 
182         d->files = eina_list_append(d->files, file);
183         /* TODO dont append files in thread, run mime scan
184          * simultaneously. ecore_thread_feedback(thread, file); */
185 
186         if (ecore_thread_check(thread))
187           break;
188      }
189 
190    eina_iterator_free(ls);
191 }
192 
193 static void
_scan_mime_func(void * data,Ecore_Thread * thread)194 _scan_mime_func(void *data, Ecore_Thread *thread)
195 {
196    Data *d = data;
197    Evry_Item_File *file;
198    Eina_List *l;
199    int cnt = 0;
200 
201    EINA_LIST_FOREACH (d->files, l, file)
202      {
203         if (ecore_thread_check(thread))
204           break;
205 
206         if ((file->mime = efreet_mime_type_get(file->path)))
207           {
208              if (!strncmp(file->mime, "inode/", 6) &&
209                  ecore_file_is_dir(file->path))
210                EVRY_ITEM(file)->browseable = EINA_TRUE;
211           }
212         else
213           file->mime = _mime_unknown;
214 
215         if (cnt++ > MAX_ITEMS * d->run_cnt) break;
216      }
217 }
218 
219 static int
_files_filter(Plugin * p)220 _files_filter(Plugin *p)
221 {
222    int match;
223    int cnt = 0;
224    Evry_Item *it;
225    Eina_List *l;
226    unsigned int len = p->input ? strlen(p->input) : 0;
227 
228    EVRY_PLUGIN_ITEMS_CLEAR(p);
229 
230    if (!p->command && p->min_query)
231      {
232         if (!p->input)
233           return 0;
234         if (len < p->min_query)
235           return 0;
236      }
237 
238    EINA_LIST_FOREACH (p->files, l, it)
239      {
240         if (cnt >= MAX_SHOWN) break;
241 
242         if (p->dirs_only && !it->browseable)
243           continue;
244 
245         if (len && (match = evry->fuzzy_match(it->label, p->input)))
246           {
247              it->fuzzy_match = match;
248              if (!it->browseable)
249                it->priority = 1;
250              EVRY_PLUGIN_ITEM_APPEND(p, it);
251              cnt++;
252           }
253         else if (len == 0)
254           {
255              if (!it->browseable)
256                it->priority = 1;
257              EVRY_PLUGIN_ITEM_APPEND(p, it);
258              cnt++;
259           }
260      }
261    return cnt;
262 }
263 
264 static void
_scan_cancel_func(void * data,Ecore_Thread * thread EINA_UNUSED)265 _scan_cancel_func(void *data, Ecore_Thread *thread EINA_UNUSED)
266 {
267    Data *d = data;
268    Plugin *p = d->plugin;
269    Evry_Item_File *file;
270 
271    /* EINA_LIST_FREE(p->files, file)
272     *   EVRY_ITEM_FREE(file); */
273 
274    EINA_LIST_FREE (d->files, file)
275      {
276         if (file->base.label) free((char *)(file->base.label));
277         if (file->path) free((char *)file->path);
278         E_FREE(file);
279      }
280 
281    p->thread = NULL;
282 
283    if (p->waiting_to_finish)
284      E_FREE(p);
285 
286    free(d->directory);
287    E_FREE(d);
288 }
289 
290 static void
_cache_mime_get(History_Types * ht,Evry_Item_File * file)291 _cache_mime_get(History_Types *ht, Evry_Item_File *file)
292 {
293    History_Entry *he;
294    History_Item *hi;
295    Eina_List *l;
296 
297    if ((he = eina_hash_find(ht->types, file->path)))
298      {
299         EINA_LIST_FOREACH (he->items, l, hi)
300           {
301              if (!hi->data)
302                continue;
303 
304              if (!file->mime)
305                file->mime = hi->data;
306 
307              hi->transient = 0;
308              EVRY_ITEM(file)->hi = hi;
309              break;
310           }
311      }
312 }
313 
314 static void
_cache_dir_add(Eina_List * files)315 _cache_dir_add(Eina_List *files)
316 {
317    Eina_List *l;
318    Evry_Item *item;
319    History_Item *hi;
320    int cnt = 0;
321 
322    EINA_LIST_REVERSE_FOREACH (files, l, item)
323      {
324         GET_FILE(file, item);
325 
326         if (!(item->hi) &&
327             (hi = evry->history_item_add(item, NULL, NULL)))
328           {
329              hi->last_used = SIX_DAYS_AGO;
330              hi->usage = MIN_USAGE * (double)cnt++;
331              hi->data = eina_stringshare_ref(file->mime);
332              item->hi = hi;
333           }
334         else if (item->hi && (item->hi->count == 1) &&
335                  (item->hi->last_used < SIX_DAYS_AGO))
336           {
337              item->hi->last_used = SIX_DAYS_AGO;
338              item->hi->usage = MIN_USAGE * (double)cnt++;
339           }
340      }
341 }
342 
343 static void
_file_add(Plugin * p,Evry_Item * item)344 _file_add(Plugin *p, Evry_Item *item)
345 {
346    GET_FILE(file, item);
347 
348    char *filename = (char *)item->label;
349    char *path = (char *)file->path;
350 
351    file->path = eina_stringshare_add(path);
352    file->mime = eina_stringshare_add(file->mime);
353 
354    item->label = eina_stringshare_add(filename);
355    item->id = eina_stringshare_ref(file->path);
356    item->context = eina_stringshare_ref(file->mime);
357 
358    evry->util_file_detail_set(file);
359 
360    p->files = eina_list_append(p->files, file);
361 
362    E_FREE(filename);
363    E_FREE(path);
364 }
365 
366 static void
_scan_end_func(void * data,Ecore_Thread * thread EINA_UNUSED)367 _scan_end_func(void *data, Ecore_Thread *thread EINA_UNUSED)
368 {
369    Data *d = data;
370    Plugin *p = d->plugin;
371    Evry_Item *item;
372    Evry_Item_File *file;
373    Eina_List *l, *ll;
374    History_Types *ht = NULL;
375 
376    if (_conf->cache_dirs)
377      ht = evry->history_types_get(EVRY_TYPE_FILE);
378 
379    if (!d->run_cnt) /* _scan_func finished */
380      {
381         EINA_LIST_FOREACH_SAFE (d->files, l, ll, item)
382           {
383              GET_FILE(browse, item);
384 
385              if (item->browseable)
386                browse->mime = _mime_dir;
387              else if (ht)
388                _cache_mime_get(ht, browse);
389 
390              if (browse->mime)
391                {
392                   d->files = eina_list_remove_list(d->files, l);
393                   _file_add(p, item);
394                }
395           }
396 
397         /* sort files by name for mimetypes scan */
398         if (d->files)
399           d->files = eina_list_sort(d->files, -1, _cb_sort);
400      }
401    else /* _scan_mime_func finished */
402      {
403         EINA_LIST_FREE (d->files, file)
404           {
405              if (!file->mime) break;
406              _file_add(p, (Evry_Item *)file);
407           }
408      }
409 
410    if (d->files) /* scan mimetypes */
411      {
412         d->run_cnt++;
413         p->thread = ecore_thread_run(_scan_mime_func,
414                                      _scan_end_func,
415                                      _scan_cancel_func, d);
416 
417         /* wait for first mime scan to finish */
418         if (d->run_cnt == 1) return;
419      }
420    else /* finished all file/mime scan */
421      {
422         free(d->directory);
423         E_FREE(d);
424         p->thread = NULL;
425 
426         if (_conf->cache_dirs && !(p->command == CMD_SHOW_HIDDEN))
427           _cache_dir_add(p->files);
428      }
429 
430    p->files = eina_list_sort(p->files, -1, _cb_sort);
431 
432    _files_filter(p);
433 
434    EVRY_PLUGIN_UPDATE(p, EVRY_UPDATE_ADD);
435 }
436 
437 static void
_dir_watcher(void * data,Ecore_File_Monitor * em EINA_UNUSED,Ecore_File_Event event,const char * path)438 _dir_watcher(void *data, Ecore_File_Monitor *em EINA_UNUSED, Ecore_File_Event event, const char *path)
439 {
440    Plugin *p = data;
441    Evry_Item_File *file;
442    const char *label;
443    Eina_List *ll, *l;
444 
445    switch (event)
446      {
447       case ECORE_FILE_EVENT_DELETED_SELF:
448         EINA_LIST_FREE (p->files, file)
449           evry->item_free(EVRY_ITEM(file));
450         break;
451 
452       case ECORE_FILE_EVENT_CREATED_DIRECTORY:
453       case ECORE_FILE_EVENT_CREATED_FILE:
454         label = ecore_file_file_get(path);
455 
456         file = EVRY_ITEM_NEW(Evry_Item_File, p, label, NULL, evry_item_file_free);
457         file->path = eina_stringshare_add(path);
458 
459         if (event == ECORE_FILE_EVENT_CREATED_DIRECTORY)
460           file->mime = eina_stringshare_ref(_mime_dir);
461 
462         _item_fill(file);
463         p->files = eina_list_append(p->files, file);
464         break;
465 
466       case ECORE_FILE_EVENT_DELETED_FILE:
467       case ECORE_FILE_EVENT_DELETED_DIRECTORY:
468         label = eina_stringshare_add(path);
469 
470         EINA_LIST_FOREACH_SAFE (p->files, l, ll, file)
471           {
472              if (file->path != label) continue;
473 
474              p->files = eina_list_remove_list(p->files, l);
475 
476              EVRY_ITEM_FREE(file);
477              break;
478           }
479         eina_stringshare_del(label);
480         break;
481 
482       default:
483         return;
484      }
485 
486    _files_filter(p);
487 
488    EVRY_PLUGIN_UPDATE(p, EVRY_UPDATE_ADD);
489 }
490 
491 static void
_read_directory(Plugin * p)492 _read_directory(Plugin *p)
493 {
494    Data *d = E_NEW(Data, 1);
495    d->plugin = p;
496    d->directory = strdup(p->directory);
497    d->run_cnt = 0;
498 
499    p->thread = ecore_thread_run(_scan_func, _scan_end_func, _scan_cancel_func, d);
500 
501    if (p->dir_mon)
502      ecore_file_monitor_del(p->dir_mon);
503 
504    p->dir_mon = ecore_file_monitor_add(p->directory, _dir_watcher, p);
505 }
506 
507 static Evry_Plugin *
_browse(Evry_Plugin * plugin,const Evry_Item * it)508 _browse(Evry_Plugin *plugin, const Evry_Item *it)
509 {
510    Plugin *p = NULL;
511 
512    if (!it || !(CHECK_TYPE(it, EVRY_TYPE_FILE)))
513      return NULL;
514 
515    GET_FILE(file, it);
516 
517    if (!evry->file_path_get(file) ||
518        !ecore_file_is_dir(file->path))
519      return NULL;
520 
521    EVRY_PLUGIN_INSTANCE(p, plugin);
522 
523    p->directory = eina_stringshare_add(file->path);
524    p->parent = EINA_TRUE;
525 
526    _read_directory(p);
527 
528    return EVRY_PLUGIN(p);
529 }
530 
531 static Evry_Plugin *
_begin(Evry_Plugin * plugin,const Evry_Item * it)532 _begin(Evry_Plugin *plugin, const Evry_Item *it)
533 {
534    Plugin *p = NULL;
535 
536    if (it)
537      {
538         const char *dir = NULL;
539 
540         if ((CHECK_TYPE(it, EVRY_TYPE_FILE)) ||
541             (CHECK_SUBTYPE(it, EVRY_TYPE_FILE)))
542           {
543              /* browse */
544              GET_FILE(file, it);
545              if (!evry->file_path_get(file))
546                return NULL;
547 
548              if (!ecore_file_is_dir(file->path))
549                {
550                   char *tmp = ecore_file_dir_get(file->path);
551                   dir = eina_stringshare_add(tmp);
552                   E_FREE(tmp);
553                }
554              else
555                {
556                   dir = eina_stringshare_add(file->path);
557                }
558           }
559         else
560           {
561              /* provide object */
562              if (!(CHECK_TYPE(it, EVRY_TYPE_ACTION)))
563                return NULL;
564           }
565 
566         if (!dir)
567           dir = eina_stringshare_add(e_user_homedir_get());
568 
569         EVRY_PLUGIN_INSTANCE(p, plugin);
570         p->directory = dir;
571         p->parent = EINA_FALSE;
572         p->min_query = 0;
573         _read_directory(p);
574 
575         return EVRY_PLUGIN(p);
576      }
577    else
578      {
579         /* provide subject */
580         EVRY_PLUGIN_INSTANCE(p, plugin);
581         p->parent = EINA_FALSE;
582         p->directory = eina_stringshare_add(e_user_homedir_get());
583         p->min_query = plugin->config->min_query;
584         _read_directory(p);
585 
586         return EVRY_PLUGIN(p);
587      }
588 
589    return NULL;
590 }
591 
592 static void
_folder_item_add(Plugin * p,const char * path,int prio)593 _folder_item_add(Plugin *p, const char *path, int prio)
594 {
595    Evry_Item_File *file;
596 
597    file = EVRY_ITEM_NEW(Evry_Item_File, p, path, NULL, evry_item_file_free);
598    file->path = eina_stringshare_add(path);
599    file->mime = eina_stringshare_ref(_mime_dir);
600    EVRY_ITEM(file)->browseable = EINA_TRUE;
601    EVRY_ITEM(file)->priority = prio;
602    EVRY_ITEM(file)->usage = -1;
603    p->files = eina_list_append(p->files, file);
604    EVRY_PLUGIN_ITEM_APPEND(p, file);
605 }
606 
607 static void
_free_files(Plugin * p)608 _free_files(Plugin *p)
609 {
610    Evry_Item_File *file;
611 
612    EVRY_PLUGIN_ITEMS_CLEAR(p);
613 
614    if (p->thread)
615      ecore_thread_cancel(p->thread);
616    p->thread = NULL;
617 
618    EINA_LIST_FREE (p->files, file)
619      EVRY_ITEM_FREE(file);
620 
621    if (p->dir_mon)
622      ecore_file_monitor_del(p->dir_mon);
623    p->dir_mon = NULL;
624 }
625 
626 static void
_finish(Evry_Plugin * plugin)627 _finish(Evry_Plugin *plugin)
628 {
629    GET_PLUGIN(p, plugin);
630 
631    IF_RELEASE(p->input);
632    IF_RELEASE(p->directory);
633 
634    if (p->thread)
635      p->waiting_to_finish = 1;
636 
637    _free_files(p);
638 
639    if (!p->waiting_to_finish)
640      E_FREE(p);
641 }
642 
643 static int
_fetch(Evry_Plugin * plugin,const char * input)644 _fetch(Evry_Plugin *plugin, const char *input)
645 {
646    GET_PLUGIN(p, plugin);
647    unsigned int len = (input ? strlen(input) : 0);
648 
649    if (!p->command)
650      EVRY_PLUGIN_ITEMS_CLEAR(p);
651 
652    IF_RELEASE(p->input);
653 
654    if (!p->parent && input && (input[0] == '/'))
655      {
656         if (p->command != CMD_SHOW_ROOT)
657           {
658              _free_files(p);
659 
660              eina_stringshare_replace(&p->directory, input);
661 
662              _read_directory(p);
663 
664              p->command = CMD_SHOW_ROOT;
665 
666              return 0;
667           }
668         int lendir = p->directory ? strlen(p->directory) : 0;
669         lendir = (lendir <= 1) ? lendir : lendir + 1;
670 
671         p->input = eina_stringshare_add(input + lendir);
672      }
673    else if (p->directory && input && !strncmp(input, "..", 2))
674      {
675         if (p->command != CMD_SHOW_PARENT)
676           {
677              char *dir;
678              char buf[PATH_MAX+1];
679              int prio = 0;
680 
681              if (strncmp(p->directory, "/", 1))
682                return 0;
683 
684              _free_files(p);
685 
686              strncpy(buf, p->directory, sizeof(buf) - 1);
687 
688              _folder_item_add(p, p->directory, prio++);
689 
690              buf[sizeof(buf) - 1] = 0;
691              while (strlen(buf) > 1)
692                {
693                   dir = dirname(buf);
694                   _folder_item_add(p, dir, prio++);
695                   strncpy(buf, dir, sizeof(buf) - 1);
696                }
697 
698              p->command = CMD_SHOW_PARENT;
699           }
700         return 1;
701      }
702    else if (p->directory && input && !strncmp(input, ".", 1))
703      {
704         if (p->command != CMD_SHOW_HIDDEN)
705           {
706              _free_files(p);
707 
708              p->show_hidden = EINA_TRUE;
709              _read_directory(p);
710 
711              p->command = CMD_SHOW_HIDDEN;
712 
713              return 0;
714           }
715         p->input = eina_stringshare_add(input);
716      }
717    else if (p->command)
718      {
719         /* clear command items */
720         _free_files(p);
721 
722         if (p->command == CMD_SHOW_ROOT)
723           {
724              IF_RELEASE(p->directory);
725              p->directory = eina_stringshare_add(e_user_homedir_get());
726           }
727 
728         p->command = CMD_NONE;
729         p->show_hidden = EINA_FALSE;
730 
731         _read_directory(p);
732      }
733 
734    if (input && !p->command)
735      p->input = eina_stringshare_add(input);
736 
737    if ((p->command) || (!p->min_query) || (len >= p->min_query))
738      _files_filter(p);
739 
740    return EVRY_PLUGIN_HAS_ITEMS(p);
741 }
742 
743 /***************************************************************************/
744 /* recent files */
745 
746 static int
_cb_sort_recent(const void * data1,const void * data2)747 _cb_sort_recent(const void *data1, const void *data2)
748 {
749    const Evry_Item *it1 = data1;
750    const Evry_Item *it2 = data2;
751 
752    if (it1->browseable && !it2->browseable)
753      return -1;
754 
755    if (!it1->browseable && it2->browseable)
756      return 1;
757 
758    if (it1->hi && it2->hi)
759      return it1->hi->last_used > it2->hi->last_used ? -1 : 1;
760 
761    if (it1->fuzzy_match && it2->fuzzy_match)
762      if (it1->fuzzy_match - it2->fuzzy_match)
763        return it1->fuzzy_match - it2->fuzzy_match;
764 
765    return strcasecmp(it1->label, it2->label);
766 }
767 
768 static int
_recentf_files_filter(Plugin * p)769 _recentf_files_filter(Plugin *p)
770 {
771    int match;
772    int cnt = 0;
773    Evry_Item *it;
774    Eina_List *l, *new = NULL;
775 
776    EVRY_PLUGIN_ITEMS_CLEAR(p);
777 
778    EINA_LIST_FOREACH (p->files, l, it)
779      {
780         if (p->dirs_only && !it->browseable)
781           continue;
782 
783         if (!p->input)
784           {
785              if (!it->browseable)
786                it->priority = 1;
787              new = eina_list_append(new, it);
788              continue;
789           }
790 
791         if (it->fuzzy_match <= 0)
792           {
793              if ((match = evry->fuzzy_match(it->label, p->input)) ||
794                  (match = evry->fuzzy_match(EVRY_FILE(it)->path, p->input)))
795                it->fuzzy_match = match;
796              else
797                it->fuzzy_match = 0;
798 
799              DBG("check match %d %s", it->fuzzy_match, it->label);
800           }
801 
802         if (it->fuzzy_match)
803           {
804              if (!it->browseable)
805                it->priority = 1;
806              new = eina_list_append(new, it);
807           }
808      }
809 
810    new = eina_list_sort(new, -1, _cb_sort_recent);
811 
812    EINA_LIST_FREE (new, it)
813      {
814         if (cnt++ < MAX_SHOWN)
815           EVRY_PLUGIN_ITEM_APPEND(p, it);
816      }
817 
818    return cnt;
819 }
820 
821 #if 0
822 /* use thread only to not block ui for ecore_file_exists ... */
823 
824 static void
825 _recentf_func(void *data)
826 {
827    Data *d = data;
828    Eina_List *l;
829    Evry_Item_File *file;
830 
831    EINA_LIST_FOREACH (d->files, l, file)
832      {
833         if ((!evry->file_path_get(file)) ||
834             (!ecore_file_exists(file->path)))
835           {
836              EVRY_ITEM(file)->hi->last_used -= ONE_DAY;
837              EVRY_ITEM(file)->hi = NULL;
838           }
839      }
840 }
841 
842 static void
843 _recentf_cancel_func(void *data)
844 {
845    Data *d = data;
846    Plugin *p = d->plugin;
847    Evry_Item_File *file;
848 
849    EINA_LIST_FREE (d->files, file)
850      EVRY_ITEM_FREE(file);
851 
852    E_FREE(d);
853 
854    if (p->waiting_to_finish)
855      E_FREE(p);
856 }
857 
858 static void
859 _recentf_end_func(void *data)
860 {
861    Data *d = data;
862    Plugin *p = d->plugin;
863    Evry_Item *it;
864 
865    EINA_LIST_FREE (d->files, it)
866      {
867         GET_FILE(file, it);
868 
869         if (!it->hi)
870           {
871              evry->item_free(it);
872              continue;
873           }
874 
875         _item_fill(file);
876 
877         if (!it->hi->data)
878           it->hi->data = eina_stringshare_ref(file->mime);
879 
880         p->files = eina_list_append(p->files, it);
881      }
882 
883    _recentf_files_filter(p);
884 
885    EVRY_PLUGIN_UPDATE(p, EVRY_UPDATE_ADD);
886 
887    p->thread = NULL;
888    E_FREE(d);
889 }
890 
891 #endif
892 
893 static Eina_Bool
_recentf_items_add_cb(const Eina_Hash * hash EINA_UNUSED,const void * key,void * data,void * fdata)894 _recentf_items_add_cb(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, void *fdata)
895 {
896    History_Entry *he = data;
897    History_Item *hi = NULL, *hi2;
898    Eina_List *l, *ll;
899    Evry_Item_File *file;
900    double last_used = 0.0;
901    Data *d = fdata;
902    Plugin *p = d->plugin;
903    const char *label;
904    const char *path;
905    int match = 0;
906 
907    EINA_LIST_FOREACH (he->items, l, hi2)
908      if (hi2->last_used > last_used)
909        {
910           last_used = hi2->last_used;
911           hi = hi2;
912        }
913 
914    if (!hi)
915      return EINA_TRUE;
916 
917    if (clear_cache)
918      {
919         DBG("clear %s", (char *)key);
920 
921         /* transient marks them for deletion */
922         if (hi->count == 1)
923           {
924              hi->usage = 0;
925              hi->count = 0;
926              hi->transient = 1;
927           }
928 
929         return EINA_TRUE;
930      }
931 
932    if (hi->transient)
933      return EINA_TRUE;
934 
935    if (!_conf->search_cache)
936      {
937         if ((hi->count == 1) && (hi->last_used < SIX_DAYS_AGO))
938           return EINA_TRUE;
939      }
940 
941    path = (const char *)key;
942 
943    if (!(label = ecore_file_file_get(path)))
944      return EINA_TRUE;
945 
946    path = eina_stringshare_add(path);
947 
948    EINA_LIST_FOREACH (p->files, ll, file)
949      {
950         if (file->path == path)
951           {
952              eina_stringshare_del(path);
953              EVRY_ITEM(file)->fuzzy_match = -1;
954              return EINA_TRUE;
955           }
956      }
957 
958    /* searching subdirs */
959    if (p->directory)
960      {
961         /* dont show recent files from same dir */
962         int len = strlen(p->directory);
963         char *end = strrchr(path, '/');
964         if (strncmp(path, p->directory, len) ||
965             (end - path) <= len)
966           {
967              /* DBG("not in dir %s", path); */
968              eina_stringshare_del(path);
969              return EINA_TRUE;
970           }
971      }
972 
973    if (!(match = evry->fuzzy_match(label, p->input)) &&
974        !(match = evry->fuzzy_match(path, p->input)))
975      {
976         eina_stringshare_del(path);
977         return EINA_TRUE;
978      }
979 
980    file = EVRY_ITEM_NEW(Evry_Item_File, p, label, NULL, evry_item_file_free);
981    file->path = path;
982 
983    if (hi->data)
984      file->mime = eina_stringshare_add(hi->data);
985 
986    EVRY_ITEM(file)->hi = hi;
987    EVRY_ITEM(file)->fuzzy_match = match;
988    EVRY_ITEM(file)->id = eina_stringshare_ref(file->path);
989 
990    _item_fill(file);
991 
992    if (!hi->data)
993      hi->data = eina_stringshare_ref(file->mime);
994 
995    d->files = eina_list_append(d->files, file);
996 
997    if (eina_list_count(d->files) > 100)
998      return EINA_FALSE;
999 
1000    return EINA_TRUE;
1001 }
1002 
1003 static Evry_Plugin *
_recentf_browse(Evry_Plugin * plugin,const Evry_Item * it)1004 _recentf_browse(Evry_Plugin *plugin, const Evry_Item *it)
1005 {
1006    Plugin *p = NULL;
1007 
1008    if (!it || !(CHECK_TYPE(it, EVRY_TYPE_FILE)))
1009      return NULL;
1010 
1011    GET_FILE(file, it);
1012 
1013    if (!evry->file_path_get(file) ||
1014        !ecore_file_is_dir(file->path))
1015      return NULL;
1016 
1017    EVRY_PLUGIN_INSTANCE(p, plugin);
1018    p->directory = eina_stringshare_add(file->path);
1019    p->parent = EINA_TRUE;
1020 
1021    return EVRY_PLUGIN(p);
1022 }
1023 
1024 static Evry_Plugin *
_recentf_begin(Evry_Plugin * plugin,const Evry_Item * it)1025 _recentf_begin(Evry_Plugin *plugin, const Evry_Item *it)
1026 {
1027    Plugin *p;
1028 
1029    if (it && !(CHECK_TYPE(it, EVRY_TYPE_ACTION)))
1030      return NULL;
1031 
1032    EVRY_PLUGIN_INSTANCE(p, plugin);
1033    p->parent = EINA_FALSE;
1034 
1035    if (it)
1036      {
1037         /* provide object */
1038      }
1039    else
1040      {
1041         /* provide subject */
1042         p->min_query = plugin->config->min_query;
1043 
1044         if (clear_cache)
1045           {
1046              History_Types *ht = evry->history_types_get(EVRY_TYPE_FILE);
1047              if (ht)
1048                eina_hash_foreach(ht->types, _recentf_items_add_cb, p);
1049 
1050              clear_cache = EINA_FALSE;
1051           }
1052      }
1053 
1054    return EVRY_PLUGIN(p);
1055 }
1056 
1057 static int
_recentf_fetch(Evry_Plugin * plugin,const char * input)1058 _recentf_fetch(Evry_Plugin *plugin, const char *input)
1059 {
1060    GET_PLUGIN(p, plugin);
1061    Evry_Item_File *file;
1062    History_Types *ht;
1063    int len = (input ? strlen(input) : 0);
1064 
1065    IF_RELEASE(p->input);
1066 
1067    /* if (p->thread)
1068     *   ecore_thread_cancel(p->thread);
1069     * p->thread = NULL; */
1070 
1071    if (input && isspace(input[len - 1]))
1072      return EVRY_PLUGIN_HAS_ITEMS(p);
1073 
1074    if (len >= plugin->config->min_query)
1075      {
1076         if (input)
1077           p->input = eina_stringshare_add(input);
1078 
1079         if ((ht = evry->history_types_get(EVRY_TYPE_FILE)))
1080           {
1081              Data *d = E_NEW(Data, 1);
1082              d->plugin = p;
1083              eina_hash_foreach(ht->types, _recentf_items_add_cb, d);
1084              EINA_LIST_FREE (d->files, file)
1085                p->files = eina_list_append(p->files, file);
1086              E_FREE(d);
1087 
1088              _recentf_files_filter(p);
1089 
1090              /* _recentf_end_func(d);
1091               * p->thread = NULL; */
1092              /* p->thread = ecore_thread_run(_recentf_func, _recentf_end_func,
1093               *           _recentf_cancel_func, d); */
1094           }
1095         return EVRY_PLUGIN_HAS_ITEMS(p);
1096      }
1097 
1098    EVRY_PLUGIN_ITEMS_CLEAR(p);
1099 
1100    return 0;
1101 }
1102 
1103 /***************************************************************************/
1104 /* actions */
1105 
1106 static int
_open_folder_check(Evry_Action * act EINA_UNUSED,const Evry_Item * it)1107 _open_folder_check(Evry_Action *act EINA_UNUSED, const Evry_Item *it)
1108 {
1109    return it->browseable && e_action_find("fileman");
1110 }
1111 
1112 static int
_open_folder_action(Evry_Action * act)1113 _open_folder_action(Evry_Action *act)
1114 {
1115    E_Action *action;
1116    char *dir;
1117 
1118    if (!(action = e_action_find("fileman")))
1119      return 0;
1120 
1121    GET_FILE(file, act->it1.item);
1122 
1123    if (!(evry->file_path_get(file)))
1124      return 0;
1125 
1126    if (!IS_BROWSEABLE(file))
1127      {
1128         dir = ecore_file_dir_get(file->path);
1129         if (!dir) return 0;
1130         action->func.go(E_OBJECT(e_comp), dir);
1131         free(dir);
1132      }
1133    else
1134      {
1135         action->func.go(E_OBJECT(e_comp), file->path);
1136      }
1137 
1138    return 1;
1139 }
1140 
1141 static int
_file_trash_action(Evry_Action * act)1142 _file_trash_action(Evry_Action *act)
1143 {
1144    Efreet_Uri *euri;
1145    int ok = 0;
1146    int force = (EVRY_ITEM_DATA_INT_GET(act) == ACT_DELETE);
1147 
1148    GET_FILE(file, act->it1.item);
1149 
1150    if (!(evry->file_url_get(file)))
1151      return 0;
1152 
1153    euri = efreet_uri_decode(file->url);
1154 
1155    if (euri)
1156      {
1157         ok = efreet_trash_delete_uri(euri, force);
1158         efreet_uri_free(euri);
1159      }
1160 
1161    return ok > 0;
1162 }
1163 
1164 static int
_file_copy_action(Evry_Action * act)1165 _file_copy_action(Evry_Action *act)
1166 {
1167    GET_FILE(src, act->it1.item);
1168    GET_FILE(dst, act->it2.item);
1169 
1170    char buf[PATH_MAX];
1171    char *ddst;
1172 
1173    if (!(evry->file_path_get(src)))
1174      return 0;
1175 
1176    if (!(evry->file_path_get(dst)))
1177      return 0;
1178 
1179    if (!ecore_file_is_dir(dst->path))
1180      ddst = ecore_file_dir_get(dst->path);
1181    else
1182      ddst = strdup(dst->path);
1183    if (!ddst)
1184      return 0;
1185 
1186    snprintf(buf, sizeof(buf), "%s/%s", ddst, ecore_file_file_get(src->path));
1187    free(ddst);
1188 
1189    DBG(" %s -> %s\n", src->path, buf);
1190 
1191    if (EVRY_ITEM_DATA_INT_GET(act) == ACT_COPY)
1192      {
1193         return ecore_file_cp(src->path, buf);
1194      }
1195    else if (EVRY_ITEM_DATA_INT_GET(act) == ACT_MOVE)
1196      {
1197         return ecore_file_mv(src->path, buf);
1198      }
1199 
1200    return 0;
1201 }
1202 
1203 static void
_sort_by_date(Plugin * p)1204 _sort_by_date(Plugin *p)
1205 {
1206    Eina_List *l;
1207    Evry_Item_File *file;
1208    struct stat s;
1209 
1210    EINA_LIST_FOREACH (p->files, l, file)
1211      {
1212         if (file->modified)
1213           continue;
1214 
1215         if (lstat(file->path, &s) == 0)
1216           file->modified = s.st_mtime;
1217 
1218         EVRY_ITEM(file)->usage = -1;
1219      }
1220 
1221    p->files = eina_list_sort(p->files, -1, _cb_sort_date);
1222    _files_filter(p);
1223 
1224    EVRY_PLUGIN_UPDATE(p, EVRY_UPDATE_ADD);
1225 }
1226 
1227 static void
_sort_by_name(Plugin * p)1228 _sort_by_name(Plugin *p)
1229 {
1230    Eina_List *l;
1231    Evry_Item *it;
1232 
1233    EINA_LIST_FOREACH (p->files, l, it)
1234      it->usage = 0;
1235 
1236    p->files = eina_list_sort(p->files, -1, _cb_sort);
1237    _files_filter(p);
1238 
1239    EVRY_PLUGIN_UPDATE(p, EVRY_UPDATE_ADD);
1240 }
1241 
1242 static int
_file_sort_action(Evry_Action * act)1243 _file_sort_action(Evry_Action *act)
1244 {
1245    GET_PLUGIN(p, act->it1.item);
1246    if (!p) return 0;
1247 
1248    if (EVRY_ITEM_DATA_INT_GET(act) == ACT_SORT_DATE)
1249      {
1250         _sort_by_date(p);
1251      }
1252    else
1253      {
1254         _sort_by_name(p);
1255      }
1256 
1257    return 0;
1258 }
1259 
1260 static int
_cb_key_down(Evry_Plugin * plugin,const Ecore_Event_Key * ev)1261 _cb_key_down(Evry_Plugin *plugin, const Ecore_Event_Key *ev)
1262 {
1263    GET_PLUGIN(p, plugin);
1264 
1265    if (!strcmp(ev->key, "F1"))
1266      {
1267         _sort_by_name(p);
1268         return 1;
1269      }
1270    if (!strcmp(ev->key, "F2"))
1271      {
1272         _sort_by_date(p);
1273         return 1;
1274      }
1275 
1276    return 0;
1277 }
1278 
1279 static int
_plugins_init(const Evry_API * api)1280 _plugins_init(const Evry_API *api)
1281 {
1282    Evry_Action *act, *act_sort_date, *act_sort_name;
1283    Evry_Plugin *p;
1284    int prio = 0;
1285    const char *config_path;
1286 
1287    evry = api;
1288 
1289    if (!evry->api_version_check(EVRY_API_VERSION))
1290      return EINA_FALSE;
1291 
1292    config_path = eina_stringshare_add("launcher/everything-files");
1293    _mime_dir = eina_stringshare_add("inode/directory");
1294    _mime_mount = eina_stringshare_add("inode/mountpoint");
1295    _mime_unknown = eina_stringshare_add("unknown");
1296 
1297 #define ACTION_NEW(_name, _type2, _icon, _act, _check, _register)            \
1298   act = EVRY_ACTION_NEW(_name, EVRY_TYPE_FILE, _type2, _icon, _act, _check); \
1299   if (_register) evry->action_register(act, prio++);                         \
1300   _actions = eina_list_append(_actions, act);                                \
1301 
1302    ACTION_NEW(N_("Copy To ..."), EVRY_TYPE_FILE, "go-next",
1303               _file_copy_action, NULL, 1);
1304    act->it2.subtype = EVRY_TYPE_DIR;
1305    EVRY_ITEM_DATA_INT_SET(act, ACT_COPY);
1306 
1307    ACTION_NEW(N_("Move To ..."), EVRY_TYPE_FILE, "go-next",
1308               _file_copy_action, NULL, 1);
1309    act->it2.subtype = EVRY_TYPE_DIR;
1310    EVRY_ITEM_DATA_INT_SET(act, ACT_MOVE);
1311 
1312    ACTION_NEW(N_("Move to Trash"), 0, "user-trash",
1313               _file_trash_action, NULL, 1);
1314    EVRY_ITEM_DATA_INT_SET(act, ACT_TRASH);
1315 
1316    ACTION_NEW(N_("Open Directory"), 0, "folder-open",
1317               _open_folder_action, _open_folder_check, 1);
1318    act->remember_context = EINA_TRUE;
1319 
1320    ACTION_NEW(N_("Sort by Date"), 0, "go-up",
1321               _file_sort_action, NULL, 0);
1322    EVRY_ITEM_DATA_INT_SET(act, ACT_SORT_DATE);
1323    act_sort_date = act;
1324 
1325    ACTION_NEW(N_("Sort by Name"), 0, "go-up",
1326               _file_sort_action, NULL, 0);
1327    EVRY_ITEM_DATA_INT_SET(act, ACT_SORT_NAME);
1328    act_sort_name = act;
1329 
1330 #undef ACTION_NEW
1331 
1332    p = EVRY_PLUGIN_BASE(N_("Files"), _module_icon, EVRY_TYPE_FILE,
1333                         _begin, _finish, _fetch);
1334    p->input_type = EVRY_TYPE_FILE;
1335    p->cb_key_down = &_cb_key_down;
1336    p->browse = &_browse;
1337    p->config_path = eina_stringshare_ref(config_path);
1338    p->actions = eina_list_append(p->actions, act_sort_date);
1339    p->actions = eina_list_append(p->actions, act_sort_name);
1340    _plugins = eina_list_append(_plugins, p);
1341 
1342    if (evry->plugin_register(p, EVRY_PLUGIN_SUBJECT, 2))
1343      p->config->min_query = 1;
1344 
1345    p = EVRY_PLUGIN_BASE(N_("Files"), _module_icon, EVRY_TYPE_FILE,
1346                         _begin, _finish, _fetch);
1347    p->cb_key_down = &_cb_key_down;
1348    p->browse = &_browse;
1349    p->config_path = eina_stringshare_ref(config_path);
1350    p->actions = eina_list_append(p->actions, act_sort_date);
1351    p->actions = eina_list_append(p->actions, act_sort_name);
1352    _plugins = eina_list_append(_plugins, p);
1353    evry->plugin_register(p, EVRY_PLUGIN_OBJECT, 2);
1354 
1355    if (!_conf->show_recent && !_conf->search_recent)
1356      return EINA_TRUE;
1357 
1358    p = EVRY_PLUGIN_BASE(N_("Recent Files"), _module_icon, EVRY_TYPE_FILE,
1359                         _recentf_begin, _finish, _recentf_fetch);
1360    p->browse = &_recentf_browse;
1361    p->config_path = eina_stringshare_ref(config_path);
1362 
1363    if (evry->plugin_register(p, EVRY_PLUGIN_SUBJECT, 3))
1364      {
1365         p->config->top_level = EINA_FALSE;
1366         p->config->min_query = 3;
1367      }
1368    _plugins = eina_list_append(_plugins, p);
1369 
1370    p = EVRY_PLUGIN_BASE(N_("Recent Files"), _module_icon, EVRY_TYPE_FILE,
1371                         _recentf_begin, _finish, _recentf_fetch);
1372    p->browse = &_recentf_browse;
1373    p->config_path = eina_stringshare_ref(config_path);
1374 
1375    if (evry->plugin_register(p, EVRY_PLUGIN_OBJECT, 3))
1376      {
1377         p->config->top_level = EINA_FALSE;
1378         p->config->min_query = 3;
1379      }
1380    _plugins = eina_list_append(_plugins, p);
1381    eina_stringshare_del(config_path);
1382 
1383    return EINA_TRUE;
1384 }
1385 
1386 static void
_plugins_shutdown(void)1387 _plugins_shutdown(void)
1388 {
1389    Evry_Action *act;
1390    Evry_Plugin *p;
1391 
1392    eina_stringshare_del(_mime_dir);
1393    eina_stringshare_del(_mime_mount);
1394    eina_stringshare_del(_mime_unknown);
1395 
1396    EINA_LIST_FREE (_plugins, p)
1397      {
1398         if (p->actions)
1399           eina_list_free(p->actions);
1400         EVRY_PLUGIN_FREE(p);
1401      }
1402 
1403    EINA_LIST_FREE (_actions, act)
1404      evry->action_free(act);
1405 }
1406 
1407 /***************************************************************************/
1408 
1409 static E_Config_DD *conf_edd = NULL;
1410 
1411 struct _E_Config_Dialog_Data
1412 {
1413    int show_homedir;
1414    int show_recent;
1415    int search_recent;
1416    int search_cache;
1417    int cache_dirs;
1418 };
1419 
1420 static void        *_create_data(E_Config_Dialog *cfd);
1421 static void         _free_data(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata);
1422 static void         _fill_data(E_Config_Dialog_Data *cfdata);
1423 static Evas_Object *_basic_create(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata);
1424 static int          _basic_apply(E_Config_Dialog *cfd, E_Config_Dialog_Data *cfdata);
1425 
1426 static E_Config_Dialog *
_conf_dialog(Evas_Object * parent EINA_UNUSED,const char * params EINA_UNUSED)1427 _conf_dialog(Evas_Object *parent EINA_UNUSED, const char *params EINA_UNUSED)
1428 {
1429    E_Config_Dialog *cfd = NULL;
1430    E_Config_Dialog_View *v = NULL;
1431 
1432    if (e_config_dialog_find("everything-files", "extensions/everything-files")) return NULL;
1433 
1434    v = E_NEW(E_Config_Dialog_View, 1);
1435    if (!v) return NULL;
1436 
1437    v->create_cfdata = _create_data;
1438    v->free_cfdata = _free_data;
1439    v->basic.create_widgets = _basic_create;
1440    v->basic.apply_cfdata = _basic_apply;
1441 
1442    cfd = e_config_dialog_new(NULL, _("Everything Files"), "everything-files",
1443                              "extensions/everything-files", _module_icon, 0, v, NULL);
1444 
1445    _conf->cfd = cfd;
1446    return cfd;
1447 }
1448 
1449 static void
_clear_cache_cb(void * data EINA_UNUSED,void * data2 EINA_UNUSED)1450 _clear_cache_cb(void *data EINA_UNUSED, void *data2 EINA_UNUSED)
1451 {
1452    clear_cache = EINA_TRUE;
1453 }
1454 
1455 static Evas_Object *
_basic_create(E_Config_Dialog * cfd EINA_UNUSED,Evas * evas,E_Config_Dialog_Data * cfdata)1456 _basic_create(E_Config_Dialog *cfd EINA_UNUSED, Evas *evas, E_Config_Dialog_Data *cfdata)
1457 {
1458    Evas_Object *o = NULL, *of = NULL, *ow = NULL;
1459 
1460    o = e_widget_list_add(evas, 0, 0);
1461 
1462    of = e_widget_framelist_add(evas, _("General"), 0);
1463    e_widget_framelist_content_align_set(of, 0.0, 0.0);
1464 
1465    /* ow = e_widget_check_add(evas, _("Show home directory"),
1466     *          &(cfdata->show_homedir));
1467     * e_widget_framelist_object_append(of, ow); */
1468 
1469    ow = e_widget_check_add(evas, _("Show recent files"),
1470                            &(cfdata->show_recent));
1471    e_widget_framelist_object_append(of, ow);
1472 
1473    ow = e_widget_check_add(evas, _("Search recent files"),
1474                            &(cfdata->search_recent));
1475    e_widget_framelist_object_append(of, ow);
1476 
1477    ow = e_widget_check_add(evas, _("Search cached files"),
1478                            &(cfdata->search_cache));
1479    e_widget_framelist_object_append(of, ow);
1480 
1481    ow = e_widget_check_add(evas, _("Cache visited directories"),
1482                            &(cfdata->cache_dirs));
1483    e_widget_framelist_object_append(of, ow);
1484 
1485    ow = e_widget_button_add(evas, _("Clear cache"), NULL,
1486                             _clear_cache_cb,
1487                             NULL, NULL);
1488    e_widget_framelist_object_append(of, ow);
1489 
1490    e_widget_list_object_append(o, of, 1, 1, 0.5);
1491    return o;
1492 }
1493 
1494 static void *
_create_data(E_Config_Dialog * cfd EINA_UNUSED)1495 _create_data(E_Config_Dialog *cfd EINA_UNUSED)
1496 {
1497    E_Config_Dialog_Data *cfdata = NULL;
1498 
1499    cfdata = E_NEW(E_Config_Dialog_Data, 1);
1500    _fill_data(cfdata);
1501    return cfdata;
1502 }
1503 
1504 static void
_free_data(E_Config_Dialog * cfd EINA_UNUSED,E_Config_Dialog_Data * cfdata)1505 _free_data(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
1506 {
1507    _conf->cfd = NULL;
1508    E_FREE(cfdata);
1509 }
1510 
1511 static void
_fill_data(E_Config_Dialog_Data * cfdata)1512 _fill_data(E_Config_Dialog_Data *cfdata)
1513 {
1514 #define C(_name) cfdata->_name = _conf->_name;
1515    C(show_homedir);
1516    C(show_recent);
1517    C(search_recent);
1518    C(search_cache);
1519    C(cache_dirs);
1520 #undef C
1521 }
1522 
1523 static int
_basic_apply(E_Config_Dialog * cfd EINA_UNUSED,E_Config_Dialog_Data * cfdata)1524 _basic_apply(E_Config_Dialog *cfd EINA_UNUSED, E_Config_Dialog_Data *cfdata)
1525 {
1526 #define C(_name) _conf->_name = cfdata->_name;
1527    C(show_homedir);
1528    C(show_recent);
1529    C(search_recent);
1530    C(search_cache);
1531    C(cache_dirs);
1532 #undef C
1533 
1534    e_config_domain_save("module.everything-files", conf_edd, _conf);
1535    e_config_save_queue();
1536    return 1;
1537 }
1538 
1539 static void
_conf_new(void)1540 _conf_new(void)
1541 {
1542    _conf = E_NEW(Module_Config, 1);
1543    _conf->show_recent = 0;
1544    _conf->show_homedir = 1;
1545    _conf->search_recent = 1;
1546    _conf->cache_dirs = 0;
1547    _conf->search_cache = 0;
1548 
1549    _conf->version = MOD_CONFIG_FILE_VERSION;
1550 }
1551 
1552 static void
_conf_free(void)1553 _conf_free(void)
1554 {
1555    E_FREE(_conf);
1556 }
1557 
1558 static void
_conf_init(E_Module * m)1559 _conf_init(E_Module *m)
1560 {
1561    char title[4096];
1562 
1563    snprintf(title, sizeof(title), "%s: %s", _("Everything Plugin"), _("Files"));
1564 
1565    e_configure_registry_item_add("launcher/everything-files", 110, title,
1566                                  NULL, _module_icon, _conf_dialog);
1567 
1568    conf_edd = E_CONFIG_DD_NEW("Module_Config", Module_Config);
1569 
1570 #undef T
1571 #undef D
1572 #define T Module_Config
1573 #define D conf_edd
1574    E_CONFIG_VAL(D, T, version, INT);
1575    E_CONFIG_VAL(D, T, show_homedir, UCHAR);
1576    E_CONFIG_VAL(D, T, show_recent, UCHAR);
1577    E_CONFIG_VAL(D, T, search_recent, UCHAR);
1578    E_CONFIG_VAL(D, T, search_cache, UCHAR);
1579    E_CONFIG_VAL(D, T, cache_dirs, UCHAR);
1580 #undef T
1581 #undef D
1582 
1583    _conf = e_config_domain_load("module.everything-files", conf_edd);
1584 
1585    if (_conf && !e_util_module_config_check(_("Everything Files"),
1586                                             _conf->version,
1587                                             MOD_CONFIG_FILE_VERSION))
1588      _conf_free();
1589 
1590    if (!_conf) _conf_new();
1591 
1592    _conf->module = m;
1593 }
1594 
1595 static void
_conf_shutdown(void)1596 _conf_shutdown(void)
1597 {
1598    e_configure_registry_item_del("launcher/everything-files");
1599 
1600    E_FREE(_conf);
1601    E_CONFIG_DD_FREE(conf_edd);
1602 }
1603 
1604 /***************************************************************************/
1605 
1606 Eina_Bool
evry_plug_files_init(E_Module * m)1607 evry_plug_files_init(E_Module *m)
1608 {
1609    _conf_init(m);
1610 
1611    EVRY_MODULE_NEW(evry_module, evry, _plugins_init, _plugins_shutdown);
1612 
1613    return EINA_TRUE;
1614 }
1615 
1616 void
evry_plug_files_shutdown(void)1617 evry_plug_files_shutdown(void)
1618 {
1619    EVRY_MODULE_FREE(evry_module);
1620 
1621    _conf_shutdown();
1622 }
1623 
1624 void
evry_plug_files_save(void)1625 evry_plug_files_save(void)
1626 {
1627    e_config_domain_save("module.everything-files", conf_edd, _conf);
1628 }
1629 
1630