Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / space_file / fsmenu.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Andrea Weikert (c) 2008 Blender Foundation.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_file/fsmenu.c
29  *  \ingroup spfile
30  */
31
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <math.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "BLI_utildefines.h"
41 #include "BLI_blenlib.h"
42
43 #include "BKE_appdir.h"
44
45 #include "ED_fileselect.h"
46
47 #ifdef WIN32
48 #  include <windows.h> /* need to include windows.h so _WIN32_IE is defined  */
49 #  include <shlobj.h>  /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff
50                         * because 'near' is disabled through BLI_windstuff */
51 #  include "BLI_winstuff.h"
52 #endif
53
54 #ifdef __APPLE__
55 #include <Carbon/Carbon.h>
56 #endif /* __APPLE__ */
57
58 #ifdef __linux__
59 #include <mntent.h>
60 #endif
61
62 #include "fsmenu.h"  /* include ourselves */
63
64
65 /* FSMENU HANDLING */
66
67 typedef struct FSMenu {
68         FSMenuEntry *fsmenu_system;
69         FSMenuEntry *fsmenu_system_bookmarks;
70         FSMenuEntry *fsmenu_bookmarks;
71         FSMenuEntry *fsmenu_recent;
72 } FSMenu;
73
74 static FSMenu *g_fsmenu = NULL;
75
76 FSMenu *ED_fsmenu_get(void)
77 {
78         if (!g_fsmenu) {
79                 g_fsmenu = MEM_callocN(sizeof(struct FSMenu), "fsmenu");
80         }
81         return g_fsmenu;
82 }
83
84 struct FSMenuEntry *ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category)
85 {
86         FSMenuEntry *fsm_head = NULL;
87
88         switch (category) {
89                 case FS_CATEGORY_SYSTEM:
90                         fsm_head = fsmenu->fsmenu_system;
91                         break;
92                 case FS_CATEGORY_SYSTEM_BOOKMARKS:
93                         fsm_head = fsmenu->fsmenu_system_bookmarks;
94                         break;
95                 case FS_CATEGORY_BOOKMARKS:
96                         fsm_head = fsmenu->fsmenu_bookmarks;
97                         break;
98                 case FS_CATEGORY_RECENT:
99                         fsm_head = fsmenu->fsmenu_recent;
100                         break;
101         }
102         return fsm_head;
103 }
104
105 void ED_fsmenu_set_category(struct FSMenu *fsmenu, FSMenuCategory category, FSMenuEntry *fsm_head)
106 {
107         switch (category) {
108                 case FS_CATEGORY_SYSTEM:
109                         fsmenu->fsmenu_system = fsm_head;
110                         break;
111                 case FS_CATEGORY_SYSTEM_BOOKMARKS:
112                         fsmenu->fsmenu_system_bookmarks = fsm_head;
113                         break;
114                 case FS_CATEGORY_BOOKMARKS:
115                         fsmenu->fsmenu_bookmarks = fsm_head;
116                         break;
117                 case FS_CATEGORY_RECENT:
118                         fsmenu->fsmenu_recent = fsm_head;
119                         break;
120         }
121 }
122
123 int ED_fsmenu_get_nentries(struct FSMenu *fsmenu, FSMenuCategory category)
124 {
125         FSMenuEntry *fsm_iter;
126         int count = 0;
127
128         for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter; fsm_iter = fsm_iter->next) {
129                 count++;
130         }
131
132         return count;
133 }
134
135 FSMenuEntry *ED_fsmenu_get_entry(struct FSMenu *fsmenu, FSMenuCategory category, int index)
136 {
137         FSMenuEntry *fsm_iter;
138
139         for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter && index; fsm_iter = fsm_iter->next) {
140                 index--;
141         }
142
143         return fsm_iter;
144 }
145
146 char *ED_fsmenu_entry_get_path(struct FSMenuEntry *fsentry)
147 {
148         return fsentry->path;
149 }
150
151 void ED_fsmenu_entry_set_path(struct FSMenuEntry *fsentry, const char *path)
152 {
153         if ((!fsentry->path || !path || !STREQ(path, fsentry->path)) && (fsentry->path != path)) {
154                 char tmp_name[FILE_MAXFILE];
155
156                 MEM_SAFE_FREE(fsentry->path);
157
158                 fsentry->path = (path && path[0]) ? BLI_strdup(path) : NULL;
159
160                 BLI_make_file_string("/", tmp_name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
161                 fsmenu_write_file(ED_fsmenu_get(), tmp_name);
162         }
163 }
164
165 static void fsmenu_entry_generate_name(struct FSMenuEntry *fsentry, char *name, size_t name_size)
166 {
167         int offset = 0;
168         int len = name_size;
169
170         if (BLI_path_name_at_index(fsentry->path, -1, &offset, &len)) {
171                 /* use as size */
172                 len += 1;
173         }
174
175         BLI_strncpy(name, &fsentry->path[offset], MIN2(len, name_size));
176         if (!name[0]) {
177                 name[0] = '/';
178                 name[1] = '\0';
179         }
180 }
181
182 char *ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry)
183 {
184         if (fsentry->name[0]) {
185                 return fsentry->name;
186         }
187         else {
188                 /* Here we abuse fsm_iter->name, keeping first char NULL. */
189                 char *name = fsentry->name + 1;
190                 size_t name_size = sizeof(fsentry->name) - 1;
191
192                 fsmenu_entry_generate_name(fsentry, name, name_size);
193                 return name;
194         }
195 }
196
197 void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name)
198 {
199         if (!STREQ(name, fsentry->name)) {
200                 char tmp_name[FILE_MAXFILE];
201                 size_t tmp_name_size = sizeof(tmp_name);
202
203                 fsmenu_entry_generate_name(fsentry, tmp_name, tmp_name_size);
204                 if (!name[0] || STREQ(tmp_name, name)) {
205                         /* reset name to default behavior. */
206                         fsentry->name[0] = '\0';
207                 }
208                 else {
209                         BLI_strncpy(fsentry->name, name, sizeof(fsentry->name));
210                 }
211
212                 BLI_make_file_string("/", tmp_name, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_BOOKMARK_FILE);
213                 fsmenu_write_file(ED_fsmenu_get(), tmp_name);
214         }
215 }
216
217 void fsmenu_entry_refresh_valid(struct FSMenuEntry *fsentry)
218 {
219         if (fsentry->path && fsentry->path[0]) {
220 #ifdef WIN32
221                 /* XXX Special case, always consider those as valid.
222                  *     Thanks to Windows, which can spend five seconds to perform a mere stat() call on those paths...
223                  *     See T43684.
224                  */
225                 const char *exceptions[] = {"A:\\", "B:\\", NULL};
226                 const size_t exceptions_len[] = {strlen(exceptions[0]), strlen(exceptions[1]), 0};
227                 int i;
228
229                 for (i = 0; exceptions[i]; i++) {
230                         if (STRCASEEQLEN(fsentry->path, exceptions[i], exceptions_len[i])) {
231                                 fsentry->valid = true;
232                                 return;
233                         }
234                 }
235 #endif
236                 fsentry->valid = BLI_is_dir(fsentry->path);
237         }
238         else {
239                 fsentry->valid = false;
240         }
241 }
242
243 short fsmenu_can_save(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
244 {
245         FSMenuEntry *fsm_iter;
246
247         for (fsm_iter = ED_fsmenu_get_category(fsmenu, category); fsm_iter && idx; fsm_iter = fsm_iter->next) {
248                 idx--;
249         }
250
251         return fsm_iter ? fsm_iter->save : 0;
252 }
253
254 void fsmenu_insert_entry(struct FSMenu *fsmenu, FSMenuCategory category, const char *path, const char *name, FSMenuInsert flag)
255 {
256         FSMenuEntry *fsm_prev;
257         FSMenuEntry *fsm_iter;
258         FSMenuEntry *fsm_head;
259
260         fsm_head = ED_fsmenu_get_category(fsmenu, category);
261         fsm_prev = fsm_head;  /* this is odd and not really correct? */
262
263         for (fsm_iter = fsm_head; fsm_iter; fsm_prev = fsm_iter, fsm_iter = fsm_iter->next) {
264                 if (fsm_iter->path) {
265                         const int cmp_ret = BLI_path_cmp(path, fsm_iter->path);
266                         if (cmp_ret == 0) {
267                                 if (flag & FS_INSERT_FIRST) {
268                                         if (fsm_iter != fsm_head) {
269                                                 fsm_prev->next = fsm_iter->next;
270                                                 fsm_iter->next = fsm_head;
271                                                 ED_fsmenu_set_category(fsmenu, category, fsm_iter);
272                                         }
273                                 }
274                                 return;
275                         }
276                         else if ((flag & FS_INSERT_SORTED) && cmp_ret < 0) {
277                                 break;
278                         }
279                 }
280                 else {
281                         /* if we're bookmarking this, file should come
282                          * before the last separator, only automatically added
283                          * current dir go after the last sep. */
284                         if (flag & FS_INSERT_SAVE) {
285                                 break;
286                         }
287                 }
288         }
289
290         fsm_iter = MEM_mallocN(sizeof(*fsm_iter), "fsme");
291         fsm_iter->path = BLI_strdup(path);
292         fsm_iter->save = (flag & FS_INSERT_SAVE) != 0;
293
294         if ((category == FS_CATEGORY_RECENT) && (!name || !name[0])) {
295                 /* Special handling when adding new recent entry - check if dir exists in some other categories,
296                  * and try to use name from there if so. */
297                 FSMenuCategory cats[] = {FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS};
298                 int i = ARRAY_SIZE(cats);
299
300                 while (i--) {
301                         FSMenuEntry *tfsm = ED_fsmenu_get_category(fsmenu, cats[i]);
302
303                         for (; tfsm; tfsm = tfsm->next) {
304                                 if (STREQ(tfsm->path, fsm_iter->path)) {
305                                         if (tfsm->name[0]) {
306                                                 name = tfsm->name;
307                                         }
308                                         break;
309                                 }
310                         }
311                         if (tfsm) {
312                                 break;
313                         }
314                 }
315         }
316
317         if (name && name[0]) {
318                 BLI_strncpy(fsm_iter->name, name, sizeof(fsm_iter->name));
319         }
320         else {
321                 fsm_iter->name[0] = '\0';
322         }
323         fsmenu_entry_refresh_valid(fsm_iter);
324
325         if (fsm_prev) {
326                 if (flag & FS_INSERT_FIRST) {
327                         fsm_iter->next = fsm_head;
328                         ED_fsmenu_set_category(fsmenu, category, fsm_iter);
329                 }
330                 else {
331                         fsm_iter->next = fsm_prev->next;
332                         fsm_prev->next = fsm_iter;
333                 }
334         }
335         else {
336                 fsm_iter->next = fsm_head;
337                 ED_fsmenu_set_category(fsmenu, category, fsm_iter);
338         }
339 }
340
341 void fsmenu_remove_entry(struct FSMenu *fsmenu, FSMenuCategory category, int idx)
342 {
343         FSMenuEntry *fsm_prev = NULL;
344         FSMenuEntry *fsm_iter;
345         FSMenuEntry *fsm_head;
346
347         fsm_head = ED_fsmenu_get_category(fsmenu, category);
348
349         for (fsm_iter = fsm_head; fsm_iter && idx; fsm_prev = fsm_iter, fsm_iter = fsm_iter->next)
350                 idx--;
351
352         if (fsm_iter) {
353                 /* you should only be able to remove entries that were
354                  * not added by default, like windows drives.
355                  * also separators (where path == NULL) shouldn't be removed */
356                 if (fsm_iter->save && fsm_iter->path) {
357
358                         /* remove fsme from list */
359                         if (fsm_prev) {
360                                 fsm_prev->next = fsm_iter->next;
361                         }
362                         else {
363                                 fsm_head = fsm_iter->next;
364                                 ED_fsmenu_set_category(fsmenu, category, fsm_head);
365                         }
366                         /* free entry */
367                         MEM_freeN(fsm_iter->path);
368                         MEM_freeN(fsm_iter);
369                 }
370         }
371 }
372
373 void fsmenu_write_file(struct FSMenu *fsmenu, const char *filename)
374 {
375         FSMenuEntry *fsm_iter = NULL;
376         char fsm_name[FILE_MAX];
377         int nwritten = 0;
378
379         FILE *fp = BLI_fopen(filename, "w");
380         if (!fp) return;
381
382         fprintf(fp, "[Bookmarks]\n");
383         for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS); fsm_iter; fsm_iter = fsm_iter->next) {
384                 if (fsm_iter->path && fsm_iter->save) {
385                         fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name));
386                         if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) {
387                                 fprintf(fp, "!%s\n", fsm_iter->name);
388                         }
389                         fprintf(fp, "%s\n", fsm_iter->path);
390                 }
391         }
392         fprintf(fp, "[Recent]\n");
393         for (fsm_iter = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_RECENT); fsm_iter && (nwritten < FSMENU_RECENT_MAX); fsm_iter = fsm_iter->next, ++nwritten) {
394                 if (fsm_iter->path && fsm_iter->save) {
395                         fsmenu_entry_generate_name(fsm_iter, fsm_name, sizeof(fsm_name));
396                         if (fsm_iter->name[0] && !STREQ(fsm_iter->name, fsm_name)) {
397                                 fprintf(fp, "!%s\n", fsm_iter->name);
398                         }
399                         fprintf(fp, "%s\n", fsm_iter->path);
400                 }
401         }
402         fclose(fp);
403 }
404
405 void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename)
406 {
407         char line[FILE_MAXDIR];
408         char name[FILE_MAXFILE];
409         FSMenuCategory category = FS_CATEGORY_BOOKMARKS;
410         FILE *fp;
411
412         fp = BLI_fopen(filename, "r");
413         if (!fp) return;
414
415         name[0] = '\0';
416
417         while (fgets(line, sizeof(line), fp) != NULL) {       /* read a line */
418                 if (STREQLEN(line, "[Bookmarks]", 11)) {
419                         category = FS_CATEGORY_BOOKMARKS;
420                 }
421                 else if (STREQLEN(line, "[Recent]", 8)) {
422                         category = FS_CATEGORY_RECENT;
423                 }
424                 else if (line[0] == '!') {
425                         int len = strlen(line);
426                         if (len > 0) {
427                                 if (line[len - 1] == '\n') {
428                                         line[len - 1] = '\0';
429                                 }
430                                 BLI_strncpy(name, line + 1, sizeof(name));
431                         }
432                 }
433                 else {
434                         int len = strlen(line);
435                         if (len > 0) {
436                                 if (line[len - 1] == '\n') {
437                                         line[len - 1] = '\0';
438                                 }
439                                 /* don't do this because it can be slow on network drives,
440                                  * having a bookmark from a drive thats ejected or so isn't
441                                  * all _that_ bad */
442 #if 0
443                                 if (BLI_exists(line))
444 #endif
445                                 {
446                                         fsmenu_insert_entry(fsmenu, category, line, name, FS_INSERT_SAVE);
447                                 }
448                         }
449                         /* always reset name. */
450                         name[0] = '\0';
451                 }
452         }
453         fclose(fp);
454 }
455
456 void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
457 {
458         char line[FILE_MAXDIR];
459 #ifdef WIN32
460         /* Add the drive names to the listing */
461         {
462                 wchar_t wline[FILE_MAXDIR];
463                 __int64 tmp;
464                 char tmps[4], *name;
465                 int i;
466
467                 tmp = GetLogicalDrives();
468
469                 for (i = 0; i < 26; i++) {
470                         if ((tmp >> i) & 1) {
471                                 tmps[0] = 'A' + i;
472                                 tmps[1] = ':';
473                                 tmps[2] = '\\';
474                                 tmps[3] = '\0';
475                                 name = NULL;
476
477                                 /* Flee from horrible win querying hover floppy drives! */
478                                 if (i > 1) {
479                                         /* Try to get volume label as well... */
480                                         BLI_strncpy_wchar_from_utf8(wline, tmps, 4);
481                                         if (GetVolumeInformationW(wline, wline + 4, FILE_MAXDIR - 4, NULL, NULL, NULL, NULL, 0)) {
482                                                 size_t label_len;
483
484                                                 BLI_strncpy_wchar_as_utf8(line, wline + 4, FILE_MAXDIR - 4);
485
486                                                 label_len = MIN2(strlen(line), FILE_MAXDIR - 6);
487                                                 BLI_snprintf(line + label_len, 6, " (%.2s)", tmps);
488
489                                                 name = line;
490                                         }
491                                 }
492
493                                 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, tmps, name, FS_INSERT_SORTED);
494                         }
495                 }
496
497                 /* Adding Desktop and My Documents */
498                 if (read_bookmarks) {
499                         SHGetSpecialFolderPathW(0, wline, CSIDL_PERSONAL, 0);
500                         BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR);
501                         fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
502                         SHGetSpecialFolderPathW(0, wline, CSIDL_DESKTOPDIRECTORY, 0);
503                         BLI_strncpy_wchar_as_utf8(line, wline, FILE_MAXDIR);
504                         fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
505                 }
506         }
507 #else
508 #ifdef __APPLE__
509         {
510                 /* Get mounted volumes better method OSX 10.6 and higher, see: */
511                 /*https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html*/
512                 /* we get all volumes sorted including network and do not relay on user-defined finder visibility, less confusing */
513
514                 CFURLRef cfURL = NULL;
515                 CFURLEnumeratorResult result = kCFURLEnumeratorSuccess;
516                 CFURLEnumeratorRef volEnum = CFURLEnumeratorCreateForMountedVolumes(NULL, kCFURLEnumeratorSkipInvisibles, NULL);
517
518                 while (result != kCFURLEnumeratorEnd) {
519                         char defPath[FILE_MAX];
520
521                         result = CFURLEnumeratorGetNextURL(volEnum, &cfURL, NULL);
522                         if (result != kCFURLEnumeratorSuccess)
523                                 continue;
524
525                         CFURLGetFileSystemRepresentation(cfURL, false, (UInt8 *)defPath, FILE_MAX);
526
527                         /* Add end slash for consistency with other platforms */
528                         BLI_add_slash(defPath);
529
530                         fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, defPath, NULL, FS_INSERT_SORTED);
531                 }
532
533                 CFRelease(volEnum);
534
535                 /* Finally get user favorite places */
536                 if (read_bookmarks) {
537                         UInt32 seed;
538                         LSSharedFileListRef list = LSSharedFileListCreate(NULL, kLSSharedFileListFavoriteItems, NULL);
539                         CFArrayRef pathesArray = LSSharedFileListCopySnapshot(list, &seed);
540                         CFIndex pathesCount = CFArrayGetCount(pathesArray);
541
542                         for (CFIndex i = 0; i < pathesCount; i++) {
543                                 LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(pathesArray, i);
544
545                                 CFURLRef cfURL = NULL;
546                                 OSErr err = LSSharedFileListItemResolve(itemRef,
547                                                                         kLSSharedFileListNoUserInteraction |
548                                                                         kLSSharedFileListDoNotMountVolumes,
549                                                                         &cfURL, NULL);
550                                 if (err != noErr || !cfURL)
551                                         continue;
552
553                                 CFStringRef pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
554
555                                 if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingUTF8))
556                                         continue;
557
558                                 /* Add end slash for consistency with other platforms */
559                                 BLI_add_slash(line);
560
561                                 /* Exclude "all my files" as it makes no sense in blender fileselector */
562                                 /* Exclude "airdrop" if wlan not active as it would show "" ) */
563                                 if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) {
564                                         fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_LAST);
565                                 }
566
567                                 CFRelease(pathString);
568                                 CFRelease(cfURL);
569                         }
570
571                         CFRelease(pathesArray);
572                         CFRelease(list);
573                 }
574         }
575 #else
576         /* unix */
577         {
578                 const char *home = getenv("HOME");
579
580                 if (read_bookmarks && home) {
581                         BLI_snprintf(line, sizeof(line), "%s/", home);
582                         fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
583                         BLI_snprintf(line, sizeof(line), "%s/Desktop/", home);
584                         if (BLI_exists(line)) {
585                                 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL, FS_INSERT_SORTED);
586                         }
587                 }
588
589                 {
590                         int found = 0;
591 #ifdef __linux__
592                         /* loop over mount points */
593                         struct mntent *mnt;
594                         int len;
595                         FILE *fp;
596
597                         fp = setmntent(MOUNTED, "r");
598                         if (fp == NULL) {
599                                 fprintf(stderr, "could not get a list of mounted filesystemts\n");
600                         }
601                         else {
602                                 while ((mnt = getmntent(fp))) {
603                                         /* not sure if this is right, but seems to give the relevant mnts */
604                                         if (!STREQLEN(mnt->mnt_fsname, "/dev", 4))
605                                                 continue;
606
607                                         len = strlen(mnt->mnt_dir);
608                                         if (len && mnt->mnt_dir[len - 1] != '/') {
609                                                 BLI_snprintf(line, sizeof(line), "%s/", mnt->mnt_dir);
610                                                 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, line, NULL, FS_INSERT_SORTED);
611                                         }
612                                         else {
613                                                 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, mnt->mnt_dir, NULL, FS_INSERT_SORTED);
614                                         }
615
616                                         found = 1;
617                                 }
618                                 if (endmntent(fp) == 0) {
619                                         fprintf(stderr, "could not close the list of mounted filesystemts\n");
620                                 }
621                         }
622 #endif
623
624                         /* fallback */
625                         if (!found)
626                                 fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, "/", NULL, FS_INSERT_SORTED);
627                 }
628         }
629 #endif
630 #endif
631 }
632
633
634 static void fsmenu_free_category(struct FSMenu *fsmenu, FSMenuCategory category)
635 {
636         FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, category);
637
638         while (fsm_iter) {
639                 FSMenuEntry *fsm_next = fsm_iter->next;
640
641                 if (fsm_iter->path) {
642                         MEM_freeN(fsm_iter->path);
643                 }
644                 MEM_freeN(fsm_iter);
645
646                 fsm_iter = fsm_next;
647         }
648 }
649
650 void fsmenu_refresh_system_category(struct FSMenu *fsmenu)
651 {
652         fsmenu_free_category(fsmenu, FS_CATEGORY_SYSTEM);
653         ED_fsmenu_set_category(fsmenu, FS_CATEGORY_SYSTEM, NULL);
654
655         fsmenu_free_category(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS);
656         ED_fsmenu_set_category(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, NULL);
657
658         /* Add all entries to system category */
659         fsmenu_read_system(fsmenu, true);
660 }
661
662 void fsmenu_refresh_bookmarks_status(struct FSMenu *fsmenu)
663 {
664         int categories[] = {FS_CATEGORY_SYSTEM, FS_CATEGORY_SYSTEM_BOOKMARKS, FS_CATEGORY_BOOKMARKS, FS_CATEGORY_RECENT};
665         int i;
666
667         for (i = sizeof(categories) / sizeof(*categories); i--; ) {
668                 FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, categories[i]);
669                 for ( ; fsm_iter; fsm_iter = fsm_iter->next) {
670                         fsmenu_entry_refresh_valid(fsm_iter);
671                 }
672         }
673 }
674
675 void fsmenu_free(void)
676 {
677         if (g_fsmenu) {
678                 fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM);
679                 fsmenu_free_category(g_fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS);
680                 fsmenu_free_category(g_fsmenu, FS_CATEGORY_BOOKMARKS);
681                 fsmenu_free_category(g_fsmenu, FS_CATEGORY_RECENT);
682                 MEM_freeN(g_fsmenu);
683         }
684
685         g_fsmenu = NULL;
686 }
687
688 int fsmenu_get_active_indices(struct FSMenu *fsmenu, enum FSMenuCategory category, const char *dir)
689 {
690         FSMenuEntry *fsm_iter = ED_fsmenu_get_category(fsmenu, category);
691         int i;
692
693         for (i = 0; fsm_iter; fsm_iter = fsm_iter->next, i++) {
694                 if (BLI_path_cmp(dir, fsm_iter->path) == 0) {
695                         return i;
696                 }
697         }
698
699         return -1;
700 }